From 5d3cad0def87c017a211a56ab0d6d56e7d88997b Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Wed, 28 Aug 2024 20:13:34 -0500 Subject: [PATCH] Reintegrated VR compnent. --- src/diagram/diagramManager.ts | 9 +- src/integration/database/database.ts | 3 + src/integration/database/pouchData.ts | 105 ++++++++++++++++++++++++ src/react/pages/createDiagramModal.tsx | 5 +- src/react/pages/editDataModal.tsx | 19 +++++ src/react/pages/manageDiagramsModal.tsx | 8 +- src/react/pages/vrExperience.tsx | 34 ++++++-- src/react/vrTemplate.tsx | 10 +-- src/util/constants.ts | 1 + src/util/functions/buildQuestLink.ts | 19 ----- src/vrApp.ts | 22 ++--- 11 files changed, 186 insertions(+), 49 deletions(-) create mode 100644 src/integration/database/database.ts create mode 100644 src/integration/database/pouchData.ts create mode 100644 src/react/pages/editDataModal.tsx create mode 100644 src/util/constants.ts delete mode 100644 src/util/functions/buildQuestLink.ts diff --git a/src/diagram/diagramManager.ts b/src/diagram/diagramManager.ts index 55669a6..2f943bb 100644 --- a/src/diagram/diagramManager.ts +++ b/src/diagram/diagramManager.ts @@ -33,12 +33,9 @@ export class DiagramManager { this._me = getMe(); this._scene = DefaultScene.Scene; this._config = new AppConfig(); - this._diagramMenuManager = new DiagramMenuManager(this.onDiagramEventObservable, controllerObservable, this._config, readyObservable); this._diagramEntityActionManager = buildEntityActionManager(controllerObservable); this.onDiagramEventObservable.add(this.onDiagramEvent, DiagramEventObserverMask.FROM_DB, true, this); - - this.onUserEventObservable.add((user) => { if (user.id != this._me) { this._logger.debug('user event', user); @@ -140,6 +137,12 @@ export class DiagramManager { private onDiagramEvent(event: DiagramEvent) { let diagramObject = this._diagramObjects.get(event?.entity?.id); switch (event.type) { + case DiagramEventType.CLEAR: + this._diagramObjects.forEach((value, key) => { + value.dispose(); + }); + this._diagramObjects.clear(); + break; case DiagramEventType.ADD: if (diagramObject) { diagramObject.fromDiagramEntity(event.entity); diff --git a/src/integration/database/database.ts b/src/integration/database/database.ts new file mode 100644 index 0000000..e9f368b --- /dev/null +++ b/src/integration/database/database.ts @@ -0,0 +1,3 @@ +import {DEFAULT_DB_NAME} from "../../util/constants"; + +export const db = new PouchDB(DEFAULT_DB_NAME); \ No newline at end of file diff --git a/src/integration/database/pouchData.ts b/src/integration/database/pouchData.ts new file mode 100644 index 0000000..2819b60 --- /dev/null +++ b/src/integration/database/pouchData.ts @@ -0,0 +1,105 @@ +import {Observable} from "@babylonjs/core"; +import {DiagramEntity, DiagramEventType} from "../../diagram/types/diagramEntity"; +import {DiagramManager} from "../../diagram/diagramManager"; +import {DiagramEventObserverMask} from "../../diagram/types/diagramEventObserverMask"; +import log, {Logger} from "loglevel"; +import PouchDB from 'pouchdb'; + +export class PouchData { + public readonly onDBEntityUpdateObservable: Observable = new Observable(); + public readonly onDBEntityRemoveObservable: Observable = new Observable(); + private _db: PouchDB; + private _diagramManager: DiagramManager; + private _logger: Logger = log.getLogger('PouchData'); + + constructor() { + + } + + public async setDb(dbname: string) { + if (this._db) { + await this._db.close(); + } + this._db = new PouchDB(dbname); + const all = await this._db.allDocs({include_docs: true}); + for (const dbEntity of all.rows) { + this.onDBEntityUpdateObservable.notifyObservers(dbEntity.doc, DiagramEventObserverMask.FROM_DB); + } + } + + public setDiagramManager(diagramManager: DiagramManager) { + this._diagramManager = diagramManager; + diagramManager.onDiagramEventObservable.add((evt) => { + this._logger.debug(evt); + if (!evt?.entity) { + this._logger.warn('no entity'); + return; + } + if (!evt?.entity?.id) { + this._logger.warn('no entity id'); + return; + } + switch (evt.type) { + case DiagramEventType.REMOVE: + this.remove(evt.entity.id); + break; + case DiagramEventType.ADD: + case DiagramEventType.MODIFY: + case DiagramEventType.DROP: + this.upsert(evt.entity); + break; + default: + this._logger.warn('unknown diagram event type', evt); + } + }, DiagramEventObserverMask.TO_DB); + + this.onDBEntityUpdateObservable.add((evt) => { + this._logger.debug(evt); + if (evt.id != 'metadata' && evt.type != 'user') { + diagramManager.onDiagramEventObservable.notifyObservers({ + type: DiagramEventType.ADD, + entity: evt + }, DiagramEventObserverMask.FROM_DB); + } else { + + } + }); + this.onDBEntityRemoveObservable.add((entity) => { + this._logger.debug(entity); + diagramManager.onDiagramEventObservable.notifyObservers( + {type: DiagramEventType.REMOVE, entity: entity}, DiagramEventObserverMask.FROM_DB); + }); + } + + public async remove(id: string) { + if (!id) { + return; + } + try { + const doc = await this._db.get(id); + await this._db.remove(doc); + } catch (err) { + this._logger.error(err); + } + } + + public async upsert(entity: DiagramEntity) { + if (!entity) { + return; + } + if (entity.template == '#image-template' && !entity.image) { + this._logger.error('no image data', entity); + return; + } + let doc = null; + try { + doc = await this._db.get(entity.id, {conflicts: true, include_docs: true}); + await this._db.put({_id: doc._id, _rev: doc._rev, ...entity}); + } catch (err) { + await this._db.put({_id: entity.id, ...entity}); + } + if (doc && doc._conflicts) { + this._logger.warn('CONFLICTS!', doc._conflicts); + } + } +} \ No newline at end of file diff --git a/src/react/pages/createDiagramModal.tsx b/src/react/pages/createDiagramModal.tsx index decebf0..4c33413 100644 --- a/src/react/pages/createDiagramModal.tsx +++ b/src/react/pages/createDiagramModal.tsx @@ -20,9 +20,9 @@ export default function CreateDiagramModal({createOpened, closeCreate}) { console.error(err); } const id = 'diagram-' + v4(); - const newDiagram = {...diagram, _id: id} + const newDiagram = {...diagram, _id: id, type: 'diagram'}; if (!doc) { - await db.put({_id: 'directory', diagrams: [newDiagram]}); + await db.put({_id: 'directory', diagrams: [newDiagram], type: 'directory'}); } else { if (doc.diagrams) { doc.diagrams.push(newDiagram); @@ -96,6 +96,5 @@ export default function CreateDiagramModal({createOpened, closeCreate}) { - ) } \ No newline at end of file diff --git a/src/react/pages/editDataModal.tsx b/src/react/pages/editDataModal.tsx new file mode 100644 index 0000000..3b2c0e1 --- /dev/null +++ b/src/react/pages/editDataModal.tsx @@ -0,0 +1,19 @@ +export default function EditDataModal({currentDb}) { + if (currentDb) { + + return ( +
+

Edit Data

+
+ + + + + +
+
+ ) + } else { + return

Nothing Selected

+ } +} \ No newline at end of file diff --git a/src/react/pages/manageDiagramsModal.tsx b/src/react/pages/manageDiagramsModal.tsx index 9f1de85..95ee7e2 100644 --- a/src/react/pages/manageDiagramsModal.tsx +++ b/src/react/pages/manageDiagramsModal.tsx @@ -3,7 +3,7 @@ import React from "react"; import {useDoc, usePouch} from "use-pouchdb"; import {IconPencilBolt, IconTrash} from "@tabler/icons-react"; -export default function ManageDiagramsModal({openCreate, manageOpened, closeManage}) { +export default function ManageDiagramsModal({setDbName, openCreate, manageOpened, closeManage}) { const {doc: diagram, error} = useDoc('directory', {}, {_id: 'directory', diagrams: []}); const [selected, setSelected] = React.useState(null); const db = usePouch(); @@ -30,7 +30,11 @@ export default function ManageDiagramsModal({openCreate, manageOpened, closeMana - + diff --git a/src/react/pages/vrExperience.tsx b/src/react/pages/vrExperience.tsx index 6a76c47..ead7c0a 100644 --- a/src/react/pages/vrExperience.tsx +++ b/src/react/pages/vrExperience.tsx @@ -1,4 +1,4 @@ -//import VrApp from '../../vrApp'; +import VrApp from '../../vrApp'; import React, {useEffect, useState} from "react"; import {Affix, Burger, Group, Menu} from "@mantine/core"; import VrTemplate from "../vrTemplate"; @@ -9,9 +9,28 @@ import ManageDiagramsModal from "./manageDiagramsModal"; import {useNavigate} from "react-router-dom"; import {useDisclosure} from "@mantine/hooks"; +let vrApp: VrApp = null; + export default function VrExperience() { const [createOpened, {open: openCreate, close: closeCreate}] = useDisclosure(false); const [manageOpened, {open: openManage, close: closeManage}] = useDisclosure(false); + const [currentDb, setCurrentDb] = useState(null); + const [dbName, setDbName] = useState('vr'); + useEffect(() => { + if (vrApp && dbName) { + console.log('here'); + console.log(dbName); + try { + vrApp.setDb(dbName).then((db) => { + setCurrentDb(db); + console.log(db); + }); + } catch (err) { + console.log(err); + } + closeManage(); + } + }, [dbName]); useEffect(() => { const data = window.localStorage.getItem('createOpened'); if (data === 'true') { @@ -20,6 +39,7 @@ export default function VrExperience() { navigator.xr.isSessionSupported('immersive-vr').then((supported) => { setImmersiveDisabled(!supported); }); + vrApp = new VrApp(document.getElementById('vrCanvas') as HTMLCanvasElement); }, []); useEffect(() => { console.log('Create Opened: ', createOpened); @@ -30,7 +50,7 @@ export default function VrExperience() { const navigate = useNavigate(); const availableInFree = () => { - return null + return null; } const availableInBasic = () => { return Basic @@ -55,12 +75,14 @@ export default function VrExperience() { const manageModal = () => { if (manageOpened) { return + manageOpened={manageOpened} + closeManage={closeManage} + setDbName={setDbName}/> } else { return <> } } - console.log('VrExperience'); + return ( @@ -122,9 +144,7 @@ export default function VrExperience() { - - - + ) diff --git a/src/react/vrTemplate.tsx b/src/react/vrTemplate.tsx index a44cdf3..a1d58b4 100644 --- a/src/react/vrTemplate.tsx +++ b/src/react/vrTemplate.tsx @@ -4,16 +4,16 @@ import React from "react"; import {theme} from "./theme"; import {Provider} from "use-pouchdb"; import PouchDB from 'pouchdb'; +import {DEFAULT_DB_NAME} from "../util/constants"; -const db = new PouchDB('mydb'); +const db = new PouchDB(DEFAULT_DB_NAME); export default function VrTemplate(props: { children: React.ReactNode }) { return ( - - - {props.children} - + + {props.children} + ) diff --git a/src/util/constants.ts b/src/util/constants.ts new file mode 100644 index 0000000..366d605 --- /dev/null +++ b/src/util/constants.ts @@ -0,0 +1 @@ +export const DEFAULT_DB_NAME = "mydb"; \ No newline at end of file diff --git a/src/util/functions/buildQuestLink.ts b/src/util/functions/buildQuestLink.ts deleted file mode 100644 index d46da5b..0000000 --- a/src/util/functions/buildQuestLink.ts +++ /dev/null @@ -1,19 +0,0 @@ -export function buildQuestLink() { - /* - - */ - const div = document.createElement("div"); - div.id = "questLaunch"; - const a = document.createElement("a"); - a.href = "https://www.oculus.com/open_url/?url=" + window.location.href; - a.target = "_blank"; - a.innerText = "Launch On Quest"; - div.appendChild(a); - const main = document.querySelector('#main'); - if (main) { - //main.appendChild(div); - } - -} \ No newline at end of file diff --git a/src/vrApp.ts b/src/vrApp.ts index a35504a..3750124 100644 --- a/src/vrApp.ts +++ b/src/vrApp.ts @@ -4,13 +4,12 @@ import {DiagramManager} from "./diagram/diagramManager"; import log, {Logger} from "loglevel"; import {CustomEnvironment} from "./util/customEnvironment"; import {Spinner} from "./objects/spinner"; -import {PouchdbPersistenceManager} from "./integration/database/pouchdbPersistenceManager"; import {addSceneInspector} from "./util/functions/sceneInspector"; import {groundMeshObserver} from "./util/functions/groundMeshObserver"; -import {buildQuestLink} from "./util/functions/buildQuestLink"; import {exportGltf} from "./util/functions/exportGltf"; import {DefaultScene} from "./defaultScene"; import {Introduction} from "./tutorial/introduction"; +import {PouchData} from "./integration/database/pouchData"; const webGpu = false; @@ -18,7 +17,9 @@ log.setLevel('error', false); export default class VrApp { //preTasks = [havokModule]; private logger: Logger = log.getLogger('App'); - private _canvas: HTMLCanvasElement + private _canvas: HTMLCanvasElement; + private _db: PouchData; + constructor(canvas: HTMLCanvasElement) { this._canvas = canvas; @@ -27,6 +28,10 @@ export default class VrApp { }); } + public async setDb(dbname: string) { + this._db.setDb(dbname); + return this._db; + } public async initialize(scene: Scene) { setMainCamera(scene); const spinner = new Spinner(); @@ -35,7 +40,9 @@ export default class VrApp { const diagramManager = new DiagramManager(diagramReadyObservable); diagramReadyObservable.add((ready) => { if (ready) { - initDb(diagramManager); + const db = new PouchData(); + db.setDiagramManager(diagramManager); + this._db = db; } else { this.logger.error('DiagramManager not ready'); } @@ -79,7 +86,7 @@ export default class VrApp { }); } } -buildQuestLink(); + function setMainCamera(scene: Scene) { const CAMERA_NAME = 'Main Camera'; const camera: FreeCamera = new FreeCamera(CAMERA_NAME, @@ -87,11 +94,6 @@ function setMainCamera(scene: Scene) { scene.setActiveCameraByName(CAMERA_NAME); } -async function initDb(diagramManager: DiagramManager) { - const db = new PouchdbPersistenceManager(); - db.setDiagramManager(diagramManager); - await db.initialize(); -} function initEnvironment(diagramManager: DiagramManager, spinner: Spinner) { const environment = new CustomEnvironment("default", diagramManager.config);