diff --git a/app/components/FeedBack/Snackers.vue b/app/components/FeedBack/Snackers.vue index 0b309728..ac1ba183 100644 --- a/app/components/FeedBack/Snackers.vue +++ b/app/components/FeedBack/Snackers.vue @@ -23,7 +23,7 @@ function calc_margin(index) { transition="slide-x-reverse-transition" max-width="200px" height="20px" - timeout="10000" + timeout="-1" z-index="4" > diff --git a/app/composables/project_manager.js b/app/composables/project_manager.js index 0630a112..3696bae3 100644 --- a/app/composables/project_manager.js +++ b/app/composables/project_manager.js @@ -8,6 +8,7 @@ import { useAppStore } from "@ogw_front/stores/app"; import { useBackStore } from "@ogw_front/stores/back"; import { useDataStore } from "@ogw_front/stores/data"; import { useDataStyleStore } from "@ogw_front/stores/data_style"; +import { useFeedbackStore } from "@ogw_front/stores/feedback"; import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer"; import { useTreeviewStore } from "@ogw_front/stores/treeview"; import { useViewerStore } from "@ogw_front/stores/viewer"; @@ -16,6 +17,7 @@ async function exportProject() { console.log("[export triggered]"); const appStore = useAppStore(); const backStore = useBackStore(); + const feedbackStore = useFeedbackStore(); const snapshot = await appStore.exportStores(); const schema = back_schemas.opengeodeweb_back.export_project; const defaultName = "project.vease"; @@ -26,6 +28,7 @@ async function exportProject() { body: { snapshot, filename: defaultName }, }); fileDownload(result, defaultName); + feedbackStore.add_success("Project exported successfully"); return { result }; } @@ -74,22 +77,19 @@ async function importProject(file) { } await treeviewStore.importStores(snapshot.treeview || {}); + await dataStore.importStores(snapshot.data); await hybridViewerStore.initHybridViewer(); - await hybridViewerStore.importStores(snapshot.hybridViewer || {}); const items = snapshot?.data?.items || []; - await importWorkflowFromSnapshot(items); await hybridViewerStore.importStores(snapshot.hybridViewer || {}); - { - await dataStyleStore.importStores(snapshot.dataStyle || {}); - } - { - await dataStyleStore.applyAllStylesFromState(); - } + await dataStyleStore.importStores(snapshot.dataStyle || {}); + await dataStyleStore.applyAllStylesFromState(); treeviewStore.finalizeImportSelection(); treeviewStore.isImporting = false; + const feedbackStore = useFeedbackStore(); + feedbackStore.add_success("Project imported successfully"); } export { exportProject, importProject }; diff --git a/app/stores/data.js b/app/stores/data.js index 526b6720..597acbfd 100644 --- a/app/stores/data.js +++ b/app/stores/data.js @@ -191,15 +191,21 @@ export const useDataStore = defineStore("data", () => { async function exportStores() { const items = await data_db.toArray(); - return { items }; + const modelComponents = await model_components_db.toArray(); + const modelComponentsRelations = await model_components_relation_db.toArray(); + return { items, modelComponents, modelComponentsRelations }; } - async function importStores(_snapshot) { + async function importStores(snapshot) { await clear(); + await model_components_db.bulkPut(snapshot.modelComponents); + await model_components_relation_db.bulkPut(snapshot.modelComponentsRelations); } async function clear() { await data_db.clear(); + await model_components_db.clear(); + await model_components_relation_db.clear(); } return { diff --git a/app/stores/data_style.js b/app/stores/data_style.js index ce8430ed..5008f565 100644 --- a/app/stores/data_style.js +++ b/app/stores/data_style.js @@ -13,7 +13,7 @@ export const useDataStyleStore = defineStore("dataStyle", () => { const dataStore = useDataStore(); const data_style_db = database.data_style; const model_component_type_datastyle_db = database.model_component_type_datastyle; - const component_datastyle_db = database.component_datastyle; + const component_datastyle_db = database.model_component_datastyle; async function addDataStyle(id, geode_object) { await data_style_db.put(structuredClone({ id, ...getDefaultStyle(geode_object) })); @@ -47,9 +47,9 @@ export const useDataStyleStore = defineStore("dataStyle", () => { function exportStores() { return { - styles: dataStyleState.styles, - componentStyles: dataStyleState.componentStyles, - modelComponentTypeStyles: dataStyleState.modelComponentTypeStyles, + styles: dataStyleState.styles.value, + componentStyles: dataStyleState.componentStyles.value, + modelComponentTypeStyles: dataStyleState.modelComponentTypeStyles.value, }; } diff --git a/internal/stores/data_style/mesh/cells/index.js b/internal/stores/data_style/mesh/cells/index.js index 6630cf96..e6eae3d1 100644 --- a/internal/stores/data_style/mesh/cells/index.js +++ b/internal/stores/data_style/mesh/cells/index.js @@ -40,11 +40,22 @@ export function useMeshCellsStyle() { } if (type === "vertex") { const name = meshCellsVertexAttributeStyle.meshCellsVertexAttributeName(id); - return meshCellsVertexAttributeStyle.setMeshCellsVertexAttributeName(id, name); + const { colorMap } = meshCellsVertexAttributeStyle.meshCellsVertexAttributeStoredConfig( + id, + name, + ); + return Promise.all([ + meshCellsVertexAttributeStyle.setMeshCellsVertexAttributeName(id, name), + meshCellsVertexAttributeStyle.setMeshCellsVertexAttributeColorMap(id, colorMap), + ]); } if (type === "cell") { const name = meshCellsCellAttributeStyle.meshCellsCellAttributeName(id); - return meshCellsCellAttributeStyle.setMeshCellsCellAttributeName(id, name); + const { colorMap } = meshCellsCellAttributeStyle.meshCellsCellAttributeStoredConfig(id, name); + return Promise.all([ + meshCellsCellAttributeStyle.setMeshCellsCellAttributeName(id, name), + meshCellsCellAttributeStyle.setMeshCellsCellAttributeColorMap(id, colorMap), + ]); } throw new Error(`Unknown mesh cells coloring type: ${type}`); } diff --git a/internal/stores/data_style/mesh/edges/index.js b/internal/stores/data_style/mesh/edges/index.js index 969dc769..25b8bba8 100644 --- a/internal/stores/data_style/mesh/edges/index.js +++ b/internal/stores/data_style/mesh/edges/index.js @@ -35,11 +35,22 @@ export function useMeshEdgesStyle() { } if (type === "vertex") { const name = meshEdgesVertexAttributeStyle.meshEdgesVertexAttributeName(id); - return meshEdgesVertexAttributeStyle.setMeshEdgesVertexAttributeName(id, name); + const { colorMap } = meshEdgesVertexAttributeStyle.meshEdgesVertexAttributeStoredConfig( + id, + name, + ); + return Promise.all([ + meshEdgesVertexAttributeStyle.setMeshEdgesVertexAttributeName(id, name), + meshEdgesVertexAttributeStyle.setMeshEdgesVertexAttributeColorMap(id, colorMap), + ]); } if (type === "edge") { const name = meshEdgesEdgeAttributeStyle.meshEdgesEdgeAttributeName(id); - return meshEdgesEdgeAttributeStyle.setMeshEdgesEdgeAttributeName(id, name); + const { colorMap } = meshEdgesEdgeAttributeStyle.meshEdgesEdgeAttributeStoredConfig(id, name); + return Promise.all([ + meshEdgesEdgeAttributeStyle.setMeshEdgesEdgeAttributeName(id, name), + meshEdgesEdgeAttributeStyle.setMeshEdgesEdgeAttributeColorMap(id, colorMap), + ]); } throw new Error(`Unknown mesh edges coloring type: ${type}`); } diff --git a/internal/stores/data_style/mesh/points/index.js b/internal/stores/data_style/mesh/points/index.js index 11e0bdc8..31e0976e 100644 --- a/internal/stores/data_style/mesh/points/index.js +++ b/internal/stores/data_style/mesh/points/index.js @@ -28,9 +28,17 @@ function useMeshPointsColoringStyle() { }); if (type === "constant") { return meshPointsColorStyle.setMeshPointsColor(id, meshPointsColorStyle.meshPointsColor(id)); - } else if (type === "vertex") { + } + if (type === "vertex") { const name = meshPointsVertexAttributeStyle.meshPointsVertexAttributeName(id); - return meshPointsVertexAttributeStyle.setMeshPointsVertexAttributeName(id, name); + const { colorMap } = meshPointsVertexAttributeStyle.meshPointsVertexAttributeStoredConfig( + id, + name, + ); + return Promise.all([ + meshPointsVertexAttributeStyle.setMeshPointsVertexAttributeName(id, name), + meshPointsVertexAttributeStyle.setMeshPointsVertexAttributeColorMap(id, colorMap), + ]); } throw new Error(`Unknown mesh points coloring type: ${type}`); } diff --git a/internal/stores/data_style/mesh/polygons/index.js b/internal/stores/data_style/mesh/polygons/index.js index 1a81c52b..ad5b677a 100644 --- a/internal/stores/data_style/mesh/polygons/index.js +++ b/internal/stores/data_style/mesh/polygons/index.js @@ -34,15 +34,30 @@ function useMeshPolygonsColoringStyle() { id, meshPolygonsColorStyle.meshPolygonsColor(id), ); - } else if (type === "textures") { + } + if (type === "textures") { const textures = meshPolygonsTexturesStyle.meshPolygonsTextures(id); return meshPolygonsTexturesStyle.setMeshPolygonsTextures(id, textures); - } else if (type === "vertex") { + } + if (type === "vertex") { const name = meshPolygonsVertexAttributeStyle.meshPolygonsVertexAttributeName(id); - return meshPolygonsVertexAttributeStyle.setMeshPolygonsVertexAttributeName(id, name); - } else if (type === "polygon") { + const { colorMap } = meshPolygonsVertexAttributeStyle.meshPolygonsVertexAttributeStoredConfig( + id, + name, + ); + return Promise.all([ + meshPolygonsVertexAttributeStyle.setMeshPolygonsVertexAttributeName(id, name), + meshPolygonsVertexAttributeStyle.setMeshPolygonsVertexAttributeColorMap(id, colorMap), + ]); + } + if (type === "polygon") { const name = meshPolygonsPolygonAttributeStyle.meshPolygonsPolygonAttributeName(id); - return meshPolygonsPolygonAttributeStyle.setMeshPolygonsPolygonAttributeName(id, name); + const { colorMap } = + meshPolygonsPolygonAttributeStyle.meshPolygonsPolygonAttributeStoredConfig(id, name); + return Promise.all([ + meshPolygonsPolygonAttributeStyle.setMeshPolygonsPolygonAttributeName(id, name), + meshPolygonsPolygonAttributeStyle.setMeshPolygonsPolygonAttributeColorMap(id, colorMap), + ]); } throw new Error(`Unknown mesh polygons coloring type: ${type}`); } diff --git a/internal/stores/data_style/mesh/polyhedra/index.js b/internal/stores/data_style/mesh/polyhedra/index.js index e3c0d258..fe0938b3 100644 --- a/internal/stores/data_style/mesh/polyhedra/index.js +++ b/internal/stores/data_style/mesh/polyhedra/index.js @@ -38,14 +38,27 @@ export function useMeshPolyhedraStyle() { } if (type === "vertex") { const name = meshPolyhedraVertexAttributeStyle.meshPolyhedraVertexAttributeName(id); - return meshPolyhedraVertexAttributeStyle.setMeshPolyhedraVertexAttributeName(id, name); + const { colorMap } = + meshPolyhedraVertexAttributeStyle.meshPolyhedraVertexAttributeStoredConfig(id, name); + return Promise.all([ + meshPolyhedraVertexAttributeStyle.setMeshPolyhedraVertexAttributeName(id, name), + meshPolyhedraVertexAttributeStyle.setMeshPolyhedraVertexAttributeColorMap(id, colorMap), + ]); } if (type === "polyhedron") { const name = meshPolyhedraPolyhedronAttributeStyle.meshPolyhedraPolyhedronAttributeName(id); - return meshPolyhedraPolyhedronAttributeStyle.setMeshPolyhedraPolyhedronAttributeName( - id, - name, - ); + const { colorMap } = + meshPolyhedraPolyhedronAttributeStyle.meshPolyhedraPolyhedronAttributeStoredConfig( + id, + name, + ); + return Promise.all([ + meshPolyhedraPolyhedronAttributeStyle.setMeshPolyhedraPolyhedronAttributeName(id, name), + meshPolyhedraPolyhedronAttributeStyle.setMeshPolyhedraPolyhedronAttributeColorMap( + id, + colorMap, + ), + ]); } throw new Error(`Unknown mesh polyhedra coloring type: ${type}`); } diff --git a/tests/unit/composables/project_manager.nuxt.test.js b/tests/unit/composables/project_manager.nuxt.test.js index 3ab6171d..c35b5a7c 100644 --- a/tests/unit/composables/project_manager.nuxt.test.js +++ b/tests/unit/composables/project_manager.nuxt.test.js @@ -28,7 +28,7 @@ const CLIPPING_RANGE1 = 0.1; const CLIPPING_RANGE2 = 1000; const CLIPPING_RANGE = [CLIPPING_RANGE1, CLIPPING_RANGE2]; const POINT_SIZE = 2; -const VIEWER_CALL_COUNT = 2; +const VIEWER_CALL_COUNT = 1; // Snapshot const snapshotMock = { @@ -104,6 +104,7 @@ const dataStoreMock = { clear: vi.fn(), registerObject: vi.fn().mockResolvedValue(), addItem: vi.fn().mockResolvedValue(), + importStores: vi.fn().mockResolvedValue(), }; const dataStyleStoreMock = { importStores: vi.fn().mockResolvedValue(), @@ -111,6 +112,10 @@ const dataStyleStoreMock = { addDataStyle: vi.fn().mockResolvedValue(), applyDefaultStyle: vi.fn().mockResolvedValue(), }; +const feedbackStoreMock = { + add_success: vi.fn(), + add_error: vi.fn(), +}; const viewer_call_mock_fn = vi.fn().mockResolvedValue(); @@ -176,6 +181,9 @@ vi.mock(import("@ogw_front/stores/hybrid_viewer"), () => ({ vi.mock(import("@ogw_front/stores/back"), () => ({ useBackStore: () => backStoreMock, })); +vi.mock(import("@ogw_front/stores/feedback"), () => ({ + useFeedbackStore: () => feedbackStoreMock, +})); vi.mock(import("@ogw_front/stores/app"), () => ({ useAppStore: () => ({ exportStores: vi.fn(() => ({ projectName: "mockedProject" })), @@ -202,6 +210,7 @@ function verifyViewerCalls() { function verifyStoreImports() { expect(treeviewStoreMock.importStores).toHaveBeenCalledWith(snapshotMock.treeview); + expect(dataStoreMock.importStores).toHaveBeenCalledWith(snapshotMock.data); expect(hybridViewerStoreMock.initHybridViewer).toHaveBeenCalledWith(); expect(hybridViewerStoreMock.importStores).toHaveBeenCalledWith(snapshotMock.hybridViewer); expect(hybridViewerStoreMock.setZScaling).toHaveBeenCalledWith(Z_SCALE); @@ -220,6 +229,7 @@ function verifyRemaining() { expect(dataStyleStoreMock.addDataStyle).toHaveBeenCalledWith("abc123", "PointSet2D"); expect(dataStyleStoreMock.applyDefaultStyle).toHaveBeenCalledWith("abc123"); expect(hybridViewerStoreMock.remoteRender).toHaveBeenCalledWith(); + expect(feedbackStoreMock.add_success).toHaveBeenCalledWith("Project imported successfully"); } describe("projectManager composable (compact)", () => { @@ -231,6 +241,7 @@ describe("projectManager composable (compact)", () => { dataStoreMock, dataStyleStoreMock, hybridViewerStoreMock, + feedbackStoreMock, ]; for (const store of storesList) { const values = Object.values(store); @@ -249,6 +260,7 @@ describe("projectManager composable (compact)", () => { await exportProject(); expect(fileDownload).toHaveBeenCalledWith({ snapshot: snapshotMock }, "project.vease"); + expect(feedbackStoreMock.add_success).toHaveBeenCalledWith("Project exported successfully"); }); test("importProjectFile with snapshot - Viewer and Stores", async () => {