+
+
+
+
+
+
+
+
+
+
0 ? onAdditionalResizeStart($event) : onResizeStart($event)
+ "
+ />
+
+
+
+
diff --git a/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue b/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue
new file mode 100644
index 00000000..b60eb311
--- /dev/null
+++ b/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/Viewer/ObjectTree/Views/ModelComponents.vue b/app/components/Viewer/ObjectTree/Views/ModelComponents.vue
new file mode 100644
index 00000000..31630a53
--- /dev/null
+++ b/app/components/Viewer/ObjectTree/Views/ModelComponents.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/Viewer/Tree/ObjectTree.vue b/app/components/Viewer/Tree/ObjectTree.vue
deleted file mode 100644
index ce2fff80..00000000
--- a/app/components/Viewer/Tree/ObjectTree.vue
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/Viewer/TreeComponent.vue b/app/components/Viewer/TreeComponent.vue
deleted file mode 100644
index f3e06847..00000000
--- a/app/components/Viewer/TreeComponent.vue
+++ /dev/null
@@ -1,170 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ item.title }}
-
-
- ID: {{ item.id }}
- Name: {{ item.title }}
-
- Status: {{ item.is_active ? "Active" : "Inactive" }}
-
-
-
-
-
-
-
-
-
diff --git a/app/components/Viewer/TreeObject.vue b/app/components/Viewer/TreeObject.vue
deleted file mode 100644
index 870f07cf..00000000
--- a/app/components/Viewer/TreeObject.vue
+++ /dev/null
@@ -1,184 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ item.title }}
-
-
-
-
-
-
-
-
-
-
diff --git a/app/components/Viewer/Ui.vue b/app/components/Viewer/Ui.vue
index bb4869e2..407ce084 100644
--- a/app/components/Viewer/Ui.vue
+++ b/app/components/Viewer/Ui.vue
@@ -1,6 +1,6 @@
- emit('show-menu', args)" />
+ emit('show-menu', args)" />
{
+ const children = (category.children || []).toSorted((itemA, itemB) => {
+ const valueA = itemA[field] || "";
+ const valueB = itemB[field] || "";
+ return valueA.localeCompare(valueB, undefined, {
+ numeric: true,
+ sensitivity: "base",
+ });
+ });
+ return {
+ ...category,
+ id: category.id,
+ title: category.title || category.id,
+ children,
+ };
+ });
+}
+
+function useTreeFilter(rawItems, options = {}) {
+ const search = ref("");
+ const sortType = ref(options.defaultSort || "name");
+ const filterOptions = ref(options.defaultFilters || {});
+
+ const availableFilterOptions = computed(() =>
+ rawItems.value.map((category) => category.title || category.id),
+ );
+
+ watch(
+ availableFilterOptions,
+ (newOptions) => {
+ for (const option of newOptions) {
+ if (filterOptions.value[option] === undefined) {
+ filterOptions.value[option] = true;
+ }
+ }
+ },
+ { immediate: true },
+ );
+
+ const processedItems = computed(() =>
+ sortAndFormatItems(
+ rawItems.value.filter((category) => {
+ const key = category.title || category.id;
+ return filterOptions.value[key] !== false;
+ }),
+ sortType.value,
+ ),
+ );
+
+ function toggleSort() {
+ sortType.value = sortType.value === "name" ? "id" : "name";
+ }
+
+ return {
+ search,
+ sortType,
+ filterOptions,
+ processedItems,
+ availableFilterOptions,
+ toggleSort,
+ customFilter,
+ };
+}
+
+export { customFilter, useTreeFilter };
diff --git a/app/stores/treeview.js b/app/stores/treeview.js
index 5fb9c661..3f681ab2 100644
--- a/app/stores/treeview.js
+++ b/app/stores/treeview.js
@@ -1,100 +1,153 @@
-export const useTreeviewStore = defineStore("treeview", () => {
- const PANEL_WIDTH = 300;
+import { defineStore } from "pinia";
+
+import { ref, toRaw, watch } from "vue";
+import { database } from "@ogw_internal/database/database";
+const PANEL_WIDTH = 300;
+export const useTreeviewStore = defineStore("treeview", () => {
const items = ref([]);
const selection = ref([]);
- const components_selection = ref([]);
- const isAdditionnalTreeDisplayed = ref(false);
+ const opened_views = ref([
+ { type: "object", id: "main", title: "Objects", scrollTop: 0, opened: [] },
+ ]);
const panelWidth = ref(PANEL_WIDTH);
- const model_id = ref("");
- const isTreeCollection = ref(false);
- const selectedTree = ref(undefined);
+ const additionalPanelWidth = ref(PANEL_WIDTH);
const isImporting = ref(false);
const pendingSelectionIds = ref([]);
+ const rowHeights = ref([]);
- // /** Functions **/
- function addItem(geode_object_type, name, id, viewer_type) {
- const child = { title: name, id, viewer_type };
-
- for (let i = 0; i < items.value.length; i += 1) {
- if (items.value[i].title === geode_object_type) {
- items.value[i].children.push(child);
- items.value[i].children.sort((element1, element2) =>
- element1.title.localeCompare(element2.title, undefined, {
- numeric: true,
- sensitivity: "base",
- }),
- );
- selection.value.push(id);
- return;
+ async function loadConfig() {
+ try {
+ const config = await database.treeview_config.get("main");
+ if (config?.opened_views) {
+ opened_views.value = config.opened_views;
}
+ if (config?.panelWidth) {
+ panelWidth.value = config.panelWidth;
+ }
+ if (config?.additionalPanelWidth) {
+ additionalPanelWidth.value = config.additionalPanelWidth;
+ }
+ if (config?.selectionIds) {
+ selection.value = config.selectionIds;
+ }
+ if (config?.rowHeights) {
+ rowHeights.value = config.rowHeights;
+ }
+ } catch (error) {
+ console.error("Failed to load treeview config:", error);
}
- items.value.push({ title: geode_object_type, children: [child] });
- items.value.sort((element1, element2) =>
- element1.title.localeCompare(element2.title, undefined, {
- numeric: true,
- sensitivity: "base",
- }),
- );
- selection.value.push(id);
}
-
- function displayAdditionalTree(id) {
- isAdditionnalTreeDisplayed.value = true;
- model_id.value = id;
+ loadConfig();
+
+ watch(
+ [opened_views, panelWidth, additionalPanelWidth, selection, rowHeights],
+ () => {
+ database.treeview_config.put({
+ id: "main",
+ opened_views: toRaw(opened_views.value),
+ panelWidth: panelWidth.value,
+ additionalPanelWidth: additionalPanelWidth.value,
+ selectionIds: toRaw(selection.value),
+ rowHeights: toRaw(rowHeights.value),
+ });
+ },
+ { deep: true },
+ );
+
+ function closeView(index) {
+ if (index > 0) {
+ opened_views.value.splice(index, 1);
+ }
}
- function displayFileTree() {
- isAdditionnalTreeDisplayed.value = false;
+ function addItem(geodeObjectType, name, id, viewer_type) {
+ const child = { title: name, id, viewer_type, geode_object_type: geodeObjectType };
+ let found = false;
+ for (const item of items.value) {
+ if (item.title === geodeObjectType) {
+ item.children.push(child);
+ const opt = { numeric: true, sensitivity: "base" };
+ item.children.sort((childA, childB) =>
+ childA.title.localeCompare(childB.title, undefined, opt),
+ );
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ items.value.push({ id: geodeObjectType, title: geodeObjectType, children: [child] });
+ const sortOpt = { numeric: true, sensitivity: "base" };
+ items.value.sort((groupA, groupB) =>
+ groupA.title.localeCompare(groupB.title, undefined, sortOpt),
+ );
+ }
+ selection.value.push(id);
}
- function toggleTreeView() {
- isTreeCollection.value = !isTreeCollection.value;
- console.log("Switched to", isTreeCollection.value ? "TreeCollection" : "TreeComponent");
+ function removeItem(id) {
+ for (let index = 0; index < items.value.length; index += 1) {
+ const group = items.value[index];
+ const childIndex = group.children.findIndex((child) => child.id === id);
+ if (childIndex !== -1) {
+ group.children.splice(childIndex, 1);
+ if (group.children.length === 0) {
+ items.value.splice(index, 1);
+ }
+ const selectionIndex = selection.value.indexOf(id);
+ if (selectionIndex !== -1) {
+ selection.value.splice(selectionIndex, 1);
+ }
+ return;
+ }
+ }
}
- function setPanelWidth(width) {
- panelWidth.value = width;
+ function displayAdditionalTree(id, title, geodeObjectType) {
+ const index = opened_views.value.findIndex((view) => view.id === id);
+ if (index !== -1) {
+ return closeView(index);
+ }
+ additionalPanelWidth.value = panelWidth.value;
+ opened_views.value.push({
+ type: "component",
+ id,
+ title: title || id,
+ geode_object_type: geodeObjectType,
+ scrollTop: 0,
+ opened: [],
+ });
}
- function exportStores() {
- const selectionIds = selection.value.map((store) => store.id);
- return {
- isAdditionnalTreeDisplayed: isAdditionnalTreeDisplayed.value,
- panelWidth: panelWidth.value,
- model_id: model_id.value,
- isTreeCollection: isTreeCollection.value,
- selectedTree: selectedTree.value,
- selectionIds,
- };
+ function moveView(fromIdx, toIdx) {
+ if (fromIdx !== 0 && toIdx !== 0) {
+ const [element] = opened_views.value.splice(fromIdx, 1);
+ opened_views.value.splice(toIdx, 0, element);
+ }
}
function importStores(snapshot) {
- isAdditionnalTreeDisplayed.value = snapshot?.isAdditionnalTreeDisplayed || false;
+ opened_views.value = snapshot?.opened_views || [
+ { type: "object", id: "main", title: "Objects", scrollTop: 0, opened: [] },
+ ];
panelWidth.value = snapshot?.panelWidth || PANEL_WIDTH;
- model_id.value = snapshot?.model_id || "";
- isTreeCollection.value = snapshot?.isTreeCollection || false;
- selectedTree.value = snapshot?.selectedTree || undefined;
-
+ additionalPanelWidth.value = snapshot?.additionalPanelWidth || PANEL_WIDTH;
+ rowHeights.value = snapshot?.rowHeights || [];
pendingSelectionIds.value =
- snapshot?.selectionIds || (snapshot?.selection || []).map((store) => store.id) || [];
+ snapshot?.selectionIds ||
+ (snapshot?.selection || []).map((selectionItem) => selectionItem.id || selectionItem) ||
+ [];
}
function finalizeImportSelection() {
- const ids = pendingSelectionIds.value || [];
const rebuilt = [];
- if (ids.length === 0) {
- for (const group of items.value) {
- for (const child of group.children) {
- rebuilt.push(child);
- }
- }
- } else {
- for (const group of items.value) {
- for (const child of group.children) {
- if (ids.includes(child.id)) {
- rebuilt.push(child);
- }
+ for (const group of items.value) {
+ for (const child of group.children) {
+ if (
+ pendingSelectionIds.value.length === 0 ||
+ pendingSelectionIds.value.includes(child.id)
+ ) {
+ rebuilt.push(child.id || child);
}
}
}
@@ -102,54 +155,78 @@ export const useTreeviewStore = defineStore("treeview", () => {
pendingSelectionIds.value = [];
}
- function removeItem(id) {
- for (let i = 0; i < items.value.length; i += 1) {
- const group = items.value[i];
- const childIndex = group.children.findIndex((child) => child.id === id);
+ function clear() {
+ items.value = [];
+ selection.value = [];
+ pendingSelectionIds.value = [];
+ opened_views.value = [
+ { type: "object", id: "main", title: "Objects", scrollTop: 0, opened: [] },
+ ];
+ }
- if (childIndex !== -1) {
- group.children.splice(childIndex, 1);
+ function displayFileTree() {
+ opened_views.value = [
+ { type: "object", id: "main", title: "Objects", scrollTop: 0, opened: [] },
+ ];
+ }
- if (group.children.length === 0) {
- items.value.splice(i, 1);
- }
+ function setPanelWidth(width) {
+ panelWidth.value = width;
+ }
- const selectionIndex = selection.value.findIndex((item) => item.id === id);
- if (selectionIndex !== -1) {
- selection.value.splice(selectionIndex, 1);
- }
+ function setAdditionalPanelWidth(width) {
+ additionalPanelWidth.value = width;
+ }
- return;
- }
+ function setScrollTop(viewId, scrollTop) {
+ const view = opened_views.value.find((openedView) => openedView.id === viewId);
+ if (view) {
+ view.scrollTop = scrollTop;
}
}
- function clear() {
- items.value = [];
- selection.value = [];
- components_selection.value = [];
- pendingSelectionIds.value = [];
- model_id.value = "";
- selectedTree.value = undefined;
+ function setOpened(viewId, opened) {
+ const view = opened_views.value.find((openedView) => openedView.id === viewId);
+ if (view) {
+ view.opened = opened;
+ }
+ }
+
+ function setRowHeights(heights) {
+ rowHeights.value = heights;
+ }
+
+ function exportStores() {
+ return {
+ opened_views: opened_views.value,
+ panelWidth: panelWidth.value,
+ additionalPanelWidth: additionalPanelWidth.value,
+ selectionIds: selection.value,
+ rowHeights: rowHeights.value,
+ };
}
return {
items,
selection,
- components_selection,
- isAdditionnalTreeDisplayed,
+ opened_views,
panelWidth,
- model_id,
- selectedTree,
+ additionalPanelWidth,
isImporting,
+ rowHeights,
addItem,
removeItem,
displayAdditionalTree,
+ closeView,
+ moveView,
+ importStores,
displayFileTree,
- toggleTreeView,
setPanelWidth,
+ setAdditionalPanelWidth,
+ setScrollTop,
+ setOpened,
+ setRowHeights,
exportStores,
- importStores,
finalizeImportSelection,
clear,
};
diff --git a/internal/database/base_database.js b/internal/database/base_database.js
index c541657c..4f5c1793 100644
--- a/internal/database/base_database.js
+++ b/internal/database/base_database.js
@@ -13,6 +13,7 @@ export class BaseDatabase extends Dexie {
[dataStyleTable.name]: dataStyleTable.schema,
[modelComponentDataStyleTable.name]: modelComponentDataStyleTable.schema,
[modelComponentsRelationTable.name]: modelComponentsRelationTable.schema,
+ treeview_config: "id",
};
}