@geode/opengeodeweb-front 10.29.0-rc.9 → 10.29.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/Viewer/ObjectTree/Views/ModelCollections.vue +3 -3
- package/app/components/Viewer/Options/ColorMapList.vue +1 -1
- package/app/composables/virtual_tree.js +1 -1
- package/app/stores/app.js +2 -2
- package/app/stores/back.js +1 -1
- package/app/stores/cloud.js +1 -1
- package/app/stores/data_helpers/collections.js +13 -19
- package/app/stores/viewer.js +1 -1
- package/app/utils/extension.js +2 -2
- package/internal/database/tables/model_components.js +1 -1
- package/internal/database/tables/model_components_relation.js +1 -1
- package/nuxt.config.js +2 -0
- package/package.json +1 -1
- package/server/utils/cloud.js +3 -0
- package/tests/unit/composables/virtual_tree.nuxt.test.js +63 -0
- package/tests/unit/stores/cloud.nuxt.test.js +2 -2
- package/tests/unit/stores/data.nuxt.test.js +127 -0
- package/tests/unit/stores/infra.nuxt.test.js +1 -1
- /package/server/api/{app → local}/kill.post.js +0 -0
- /package/server/api/{app → local}/project_folder_path.post.js +0 -0
- /package/server/api/{app → local}/run_back.post.js +0 -0
- /package/server/api/{app → local}/run_viewer.post.js +0 -0
- /package/server/api/{extensions → microservice/extensions}/kill.post.js +0 -0
- /package/server/api/{extensions → microservice/extensions}/run.post.js +0 -0
- /package/server/api/{extensions → microservice/extensions}/upload.put.js +0 -0
- /package/server/api/{app → serverless}/run_cloud.js +0 -0
|
@@ -127,10 +127,10 @@ function expandAll() {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function extractIds(node) {
|
|
130
|
-
if (node.children
|
|
130
|
+
if (node.children) {
|
|
131
131
|
return node.children.flatMap((child) => extractIds(child));
|
|
132
132
|
}
|
|
133
|
-
if (
|
|
133
|
+
if (Number.isInteger(node.viewer_id)) {
|
|
134
134
|
return [node.viewer_id];
|
|
135
135
|
}
|
|
136
136
|
return [];
|
|
@@ -187,7 +187,7 @@ function getLeafViewerIds(item) {
|
|
|
187
187
|
|
|
188
188
|
<template #append="{ item }">
|
|
189
189
|
<v-btn
|
|
190
|
-
v-if="
|
|
190
|
+
v-if="getLeafViewerIds(item).length > 0"
|
|
191
191
|
icon="mdi-target"
|
|
192
192
|
size="medium"
|
|
193
193
|
variant="text"
|
|
@@ -78,7 +78,7 @@ watch(filteredPresets, drawAllCanvases);
|
|
|
78
78
|
<template>
|
|
79
79
|
<GlassCard width="320" variant="panel" padding="pa-3" rounded="lg" class="overflow-hidden">
|
|
80
80
|
<v-overlay
|
|
81
|
-
v-
|
|
81
|
+
v-if="loading"
|
|
82
82
|
data-testid="colorMapListLoading"
|
|
83
83
|
contained
|
|
84
84
|
persistent
|
|
@@ -33,7 +33,7 @@ export function useVirtualTree(propsIn, emit) {
|
|
|
33
33
|
|
|
34
34
|
function getLeafChildrenIds(item, ids = []) {
|
|
35
35
|
const children = item[actualItemProps.value.children];
|
|
36
|
-
if (children
|
|
36
|
+
if (children) {
|
|
37
37
|
for (const child of children) {
|
|
38
38
|
getLeafChildrenIds(child, ids);
|
|
39
39
|
}
|
package/app/stores/app.js
CHANGED
|
@@ -196,7 +196,7 @@ export const useAppStore = defineStore("app", () => {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
function upload(file, callbacks = {}) {
|
|
199
|
-
const route = "/api/extensions/upload";
|
|
199
|
+
const route = "/api/microservice/extensions/upload";
|
|
200
200
|
const store = useAppStore();
|
|
201
201
|
return upload_file(
|
|
202
202
|
store,
|
|
@@ -244,7 +244,7 @@ export const useAppStore = defineStore("app", () => {
|
|
|
244
244
|
function createProjectFolder() {
|
|
245
245
|
const { PROJECT } = useRuntimeConfig().public;
|
|
246
246
|
const schema = {
|
|
247
|
-
$id: "/api/
|
|
247
|
+
$id: "/api/local/project_folder_path",
|
|
248
248
|
methods: ["POST"],
|
|
249
249
|
type: "object",
|
|
250
250
|
properties: { PROJECT: { type: "string" } },
|
package/app/stores/back.js
CHANGED
|
@@ -81,7 +81,7 @@ export const useBackStore = defineStore("back", {
|
|
|
81
81
|
const appStore = useAppStore();
|
|
82
82
|
const { COMMAND_BACK, NUXT_ROOT_PATH } = useRuntimeConfig().public;
|
|
83
83
|
const schema = {
|
|
84
|
-
$id: "/api/
|
|
84
|
+
$id: "/api/local/run_back",
|
|
85
85
|
methods: ["POST"],
|
|
86
86
|
type: "object",
|
|
87
87
|
properties: {
|
package/app/stores/cloud.js
CHANGED
|
@@ -12,7 +12,7 @@ export const useCloudStore = defineStore("cloud", {
|
|
|
12
12
|
this.status = Status.CONNECTING;
|
|
13
13
|
console.log("[CLOUD] Launching cloud backend...");
|
|
14
14
|
const schema = {
|
|
15
|
-
$id: "/api/
|
|
15
|
+
$id: "/api/serverless/run_cloud",
|
|
16
16
|
methods: ["POST"],
|
|
17
17
|
type: "object",
|
|
18
18
|
properties: {
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
+
import { MESH_COMPONENT_TYPES } from "@ogw_front/utils/default_styles";
|
|
1
2
|
import { database } from "@ogw_internal/database/database.js";
|
|
2
3
|
import { liveQuery } from "dexie";
|
|
3
4
|
import { useDataMesh } from "./mesh.js";
|
|
4
5
|
import { useObservable } from "@vueuse/rxjs";
|
|
5
6
|
|
|
7
|
+
function pluralize(type) {
|
|
8
|
+
if (type.endsWith("y")) {
|
|
9
|
+
return `${type.slice(0, -1)}ies`;
|
|
10
|
+
}
|
|
11
|
+
return `${type}s`;
|
|
12
|
+
}
|
|
13
|
+
|
|
6
14
|
export function useDataCollections() {
|
|
7
15
|
const model_components_db = database.model_components;
|
|
8
16
|
const model_components_relation_db = database.model_components_relation;
|
|
@@ -12,11 +20,7 @@ export function useDataCollections() {
|
|
|
12
20
|
const count = await model_components_db
|
|
13
21
|
.where("id")
|
|
14
22
|
.equals(modelId)
|
|
15
|
-
.and((component) =>
|
|
16
|
-
["Horizon", "Fault", "FaultBlock", "StratigraphicUnit", "ModelBoundary"].includes(
|
|
17
|
-
component.type,
|
|
18
|
-
),
|
|
19
|
-
)
|
|
23
|
+
.and((component) => !MESH_COMPONENT_TYPES.includes(component.type))
|
|
20
24
|
.count();
|
|
21
25
|
return count > 0;
|
|
22
26
|
}
|
|
@@ -24,11 +28,7 @@ export function useDataCollections() {
|
|
|
24
28
|
async function getAllCollectionComponents(modelId) {
|
|
25
29
|
const items = await model_components_db.where("id").equals(modelId).toArray();
|
|
26
30
|
return items
|
|
27
|
-
.filter((component) =>
|
|
28
|
-
["Horizon", "Fault", "FaultBlock", "StratigraphicUnit", "ModelBoundary"].includes(
|
|
29
|
-
component.type,
|
|
30
|
-
),
|
|
31
|
-
)
|
|
31
|
+
.filter((component) => !MESH_COMPONENT_TYPES.includes(component.type))
|
|
32
32
|
.map((component) => ({
|
|
33
33
|
id: component.geode_id,
|
|
34
34
|
title: component.name,
|
|
@@ -68,19 +68,13 @@ export function useDataCollections() {
|
|
|
68
68
|
|
|
69
69
|
async function formatedCollectionComponents(modelId) {
|
|
70
70
|
const byType = await fetchAllCollectionComponents(modelId);
|
|
71
|
-
const
|
|
72
|
-
Horizon: "Horizons",
|
|
73
|
-
Fault: "Faults",
|
|
74
|
-
FaultBlock: "FaultBlocks",
|
|
75
|
-
StratigraphicUnit: "StratigraphicUnits",
|
|
76
|
-
ModelBoundary: "ModelBoundaries",
|
|
77
|
-
};
|
|
71
|
+
const collectionTypes = Object.keys(byType);
|
|
78
72
|
|
|
79
|
-
return
|
|
73
|
+
return collectionTypes
|
|
80
74
|
.filter((type) => byType[type] && byType[type].length > 0)
|
|
81
75
|
.map((type) => ({
|
|
82
76
|
id: type,
|
|
83
|
-
title:
|
|
77
|
+
title: pluralize(type),
|
|
84
78
|
children: byType[type],
|
|
85
79
|
}));
|
|
86
80
|
}
|
package/app/stores/viewer.js
CHANGED
|
@@ -133,7 +133,7 @@ export const useViewerStore = defineStore(
|
|
|
133
133
|
|
|
134
134
|
const { COMMAND_VIEWER, NUXT_ROOT_PATH } = useRuntimeConfig().public;
|
|
135
135
|
const schema = {
|
|
136
|
-
$id: "/api/
|
|
136
|
+
$id: "/api/local/run_viewer",
|
|
137
137
|
methods: ["POST"],
|
|
138
138
|
type: "object",
|
|
139
139
|
properties: { COMMAND_VIEWER: { type: "string" }, NUXT_ROOT_PATH: { type: "string" } },
|
package/app/utils/extension.js
CHANGED
|
@@ -81,7 +81,7 @@ function runExtensions() {
|
|
|
81
81
|
const params = { projectFolderPath, projectName };
|
|
82
82
|
|
|
83
83
|
const schema = {
|
|
84
|
-
$id: "/api/extensions/run",
|
|
84
|
+
$id: "/api/microservice/extensions/run",
|
|
85
85
|
methods: ["POST"],
|
|
86
86
|
type: "object",
|
|
87
87
|
properties: {
|
|
@@ -104,7 +104,7 @@ function killExtension(extensionId) {
|
|
|
104
104
|
console.log(`[AppStore] Killing extension: ${extensionId}`, { params });
|
|
105
105
|
|
|
106
106
|
const schema = {
|
|
107
|
-
$id: "/api/extensions/kill",
|
|
107
|
+
$id: "/api/microservice/extensions/kill",
|
|
108
108
|
methods: ["POST"],
|
|
109
109
|
type: "object",
|
|
110
110
|
properties: {
|
package/nuxt.config.js
CHANGED
package/package.json
CHANGED
package/server/utils/cloud.js
CHANGED
|
@@ -42,6 +42,8 @@ function requestConfig(parent, image, email, projectName) {
|
|
|
42
42
|
cpu: "2000m",
|
|
43
43
|
memory: "3Gi",
|
|
44
44
|
},
|
|
45
|
+
cpuIdle: false,
|
|
46
|
+
startup_cpu_boost: true,
|
|
45
47
|
};
|
|
46
48
|
const labels = {
|
|
47
49
|
user: sanitizeLabelValue(email),
|
|
@@ -59,6 +61,7 @@ function requestConfig(parent, image, email, projectName) {
|
|
|
59
61
|
},
|
|
60
62
|
template: {
|
|
61
63
|
labels,
|
|
64
|
+
timeout: { seconds: 3600 },
|
|
62
65
|
containers: [
|
|
63
66
|
{
|
|
64
67
|
image,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Third party imports
|
|
2
|
+
import { describe, expect, test, vi } from "vitest";
|
|
3
|
+
import { ref } from "vue";
|
|
4
|
+
|
|
5
|
+
// Local imports
|
|
6
|
+
import { useVirtualTree } from "@ogw_front/composables/virtual_tree";
|
|
7
|
+
|
|
8
|
+
describe("virtual tree composable", () => {
|
|
9
|
+
test("correctly handles empty collections without treating them as leaf nodes", () => {
|
|
10
|
+
// Structure:
|
|
11
|
+
// ModelBoundaries (category)
|
|
12
|
+
// ├── empty_collection (empty collection component)
|
|
13
|
+
// └── non_empty_collection (non-empty collection component)
|
|
14
|
+
// └── mesh1 (leaf mesh component)
|
|
15
|
+
const items = [
|
|
16
|
+
{
|
|
17
|
+
id: "ModelBoundaries",
|
|
18
|
+
title: "Model Boundaries",
|
|
19
|
+
children: [
|
|
20
|
+
{
|
|
21
|
+
id: "empty_collection",
|
|
22
|
+
title: "Empty Collection",
|
|
23
|
+
children: [],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: "non_empty_collection",
|
|
27
|
+
title: "Non-empty Collection",
|
|
28
|
+
children: [
|
|
29
|
+
{
|
|
30
|
+
id: "mesh1",
|
|
31
|
+
title: "Mesh 1",
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const props = ref({
|
|
40
|
+
items,
|
|
41
|
+
opened: [],
|
|
42
|
+
selected: ["mesh1"],
|
|
43
|
+
selection: { selectable: true, strategy: "classic" },
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const emit = vi.fn();
|
|
47
|
+
const { isSelected, getIndeterminate } = useVirtualTree(props, emit);
|
|
48
|
+
|
|
49
|
+
// 1. The empty collection has no leaf children, so it should not be considered selected
|
|
50
|
+
expect(isSelected(items[0].children[0])).toBe(false);
|
|
51
|
+
|
|
52
|
+
// 2. The non-empty collection has "mesh1" as a child (which is in the selected set), so it is selected
|
|
53
|
+
expect(isSelected(items[0].children[1])).toBe(true);
|
|
54
|
+
|
|
55
|
+
// 3. The category root (ModelBoundaries) only has "mesh1" as an active leaf descendant.
|
|
56
|
+
// Since "mesh1" is selected, the category root must evaluate to selected (true).
|
|
57
|
+
// (If the bug were present, it would look for both "empty_collection" and "mesh1" in selected, resulting in false)
|
|
58
|
+
expect(isSelected(items[0])).toBe(true);
|
|
59
|
+
|
|
60
|
+
// 4. ModelBoundaries should not be indeterminate since all its leaf descendants are selected
|
|
61
|
+
expect(getIndeterminate(items[0])).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -38,7 +38,7 @@ describe("cloud store", () => {
|
|
|
38
38
|
const cloudStore = useCloudStore();
|
|
39
39
|
const feedbackStore = useFeedbackStore();
|
|
40
40
|
|
|
41
|
-
registerEndpoint("/api/
|
|
41
|
+
registerEndpoint("/api/serverless/run_cloud", {
|
|
42
42
|
method: "POST",
|
|
43
43
|
handler: postFakeCall,
|
|
44
44
|
});
|
|
@@ -58,7 +58,7 @@ describe("cloud store", () => {
|
|
|
58
58
|
const cloudStore = useCloudStore();
|
|
59
59
|
const feedbackStore = useFeedbackStore();
|
|
60
60
|
|
|
61
|
-
registerEndpoint("/api/
|
|
61
|
+
registerEndpoint("/api/serverless/run_cloud", {
|
|
62
62
|
method: "POST",
|
|
63
63
|
handler: postFakeCall,
|
|
64
64
|
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Third party imports
|
|
2
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
3
|
+
|
|
4
|
+
// Local imports
|
|
5
|
+
import { setupActivePinia } from "@ogw_tests/utils";
|
|
6
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
7
|
+
|
|
8
|
+
describe("useDataStore - collections", () => {
|
|
9
|
+
setupActivePinia();
|
|
10
|
+
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
const dataStore = useDataStore();
|
|
13
|
+
await dataStore.clear();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("correctly recognizes, formats, and pluralizes any collection component type not in MESH_COMPONENT_TYPES", async () => {
|
|
17
|
+
const dataStore = useDataStore();
|
|
18
|
+
const modelId = "test_model_id";
|
|
19
|
+
|
|
20
|
+
// 1. Add model item
|
|
21
|
+
await dataStore.addItem({
|
|
22
|
+
id: modelId,
|
|
23
|
+
name: "Test Model",
|
|
24
|
+
viewer_type: "model",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// 2. Add mesh components and collection components (including a custom type like "MyCustomCollection")
|
|
28
|
+
await dataStore.addComponents({
|
|
29
|
+
id: modelId,
|
|
30
|
+
mesh_components: [
|
|
31
|
+
{
|
|
32
|
+
geode_id: "mesh_corner",
|
|
33
|
+
name: "Corner 1",
|
|
34
|
+
type: "Corner",
|
|
35
|
+
viewer_id: 1,
|
|
36
|
+
is_active: true,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
geode_id: "mesh_surface",
|
|
40
|
+
name: "Surface 1",
|
|
41
|
+
type: "Surface",
|
|
42
|
+
viewer_id: 2,
|
|
43
|
+
is_active: true,
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
collection_components: [
|
|
47
|
+
// Standard collection type
|
|
48
|
+
{ geode_id: "fault1", name: "Fault 1", type: "Fault", viewer_id: 3, is_active: true },
|
|
49
|
+
// Custom collection type (not previously hardcoded)
|
|
50
|
+
{
|
|
51
|
+
geode_id: "custom1",
|
|
52
|
+
name: "Custom 1",
|
|
53
|
+
type: "MyCustomCollection",
|
|
54
|
+
viewer_id: 4,
|
|
55
|
+
is_active: true,
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Add component relations
|
|
61
|
+
await dataStore.addComponentRelations({
|
|
62
|
+
id: modelId,
|
|
63
|
+
collection_components: [
|
|
64
|
+
{ geode_id: "fault1", items: ["mesh_surface"] },
|
|
65
|
+
{ geode_id: "custom1", items: [] },
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// 3. Verify hasCollectionComponents is true
|
|
70
|
+
const hasCollections = await dataStore.hasCollectionComponents(modelId);
|
|
71
|
+
expect(hasCollections).toBe(true);
|
|
72
|
+
|
|
73
|
+
// 4. Verify getAllCollectionComponents returns both Fault and MyCustomCollection
|
|
74
|
+
const allCollections = await dataStore.getAllCollectionComponents(modelId);
|
|
75
|
+
expect(allCollections).toStrictEqual([
|
|
76
|
+
{
|
|
77
|
+
id: "custom1",
|
|
78
|
+
title: "Custom 1",
|
|
79
|
+
category: "MyCustomCollection",
|
|
80
|
+
viewer_id: 4,
|
|
81
|
+
is_active: true,
|
|
82
|
+
},
|
|
83
|
+
{ id: "fault1", title: "Fault 1", category: "Fault", viewer_id: 3, is_active: true },
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
// 5. Verify formatedCollectionComponents groups them and pluralizes the titles
|
|
87
|
+
const formatted = await dataStore.formatedCollectionComponents(modelId);
|
|
88
|
+
expect(formatted).toStrictEqual([
|
|
89
|
+
{
|
|
90
|
+
id: "MyCustomCollection",
|
|
91
|
+
title: "MyCustomCollections",
|
|
92
|
+
children: [
|
|
93
|
+
{
|
|
94
|
+
id: "custom1",
|
|
95
|
+
title: "Custom 1",
|
|
96
|
+
category: "MyCustomCollection",
|
|
97
|
+
viewer_id: 4,
|
|
98
|
+
is_active: true,
|
|
99
|
+
children: [],
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: "Fault",
|
|
105
|
+
title: "Faults",
|
|
106
|
+
children: [
|
|
107
|
+
{
|
|
108
|
+
id: "fault1",
|
|
109
|
+
title: "Fault 1",
|
|
110
|
+
category: "Fault",
|
|
111
|
+
viewer_id: 3,
|
|
112
|
+
is_active: true,
|
|
113
|
+
children: [
|
|
114
|
+
{
|
|
115
|
+
id: "mesh_surface",
|
|
116
|
+
title: "Surface 1",
|
|
117
|
+
category: "Surface",
|
|
118
|
+
viewer_id: 2,
|
|
119
|
+
is_active: true,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
]);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -291,7 +291,7 @@ describe("infra store", () => {
|
|
|
291
291
|
|
|
292
292
|
infraStore.app_mode = appMode.CLOUD;
|
|
293
293
|
const url = "test.com";
|
|
294
|
-
registerEndpoint("/api/
|
|
294
|
+
registerEndpoint("/api/serverless/run_cloud", {
|
|
295
295
|
method: "POST",
|
|
296
296
|
handler: () => ({ url }),
|
|
297
297
|
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|