@geode/opengeodeweb-front 10.29.0-rc.1 → 10.29.0-rc.10
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/ContextMenu/InfoCard.vue +56 -21
- package/app/components/Viewer/Generic/Model/BlocksOptions.vue +3 -3
- package/app/components/Viewer/Generic/Model/CornersOptions.vue +3 -4
- package/app/components/Viewer/Generic/Model/LinesOptions.vue +3 -3
- package/app/components/Viewer/Generic/Model/ModelStyleCard.vue +5 -1
- package/app/components/Viewer/Generic/Model/SurfacesOptions.vue +3 -3
- package/app/components/Viewer/ObjectTree/Views/ModelComponents.vue +6 -2
- package/app/components/Viewer/Options/ColorMapList.vue +3 -2
- package/app/stores/app.js +2 -2
- package/app/stores/back.js +1 -1
- package/app/stores/cloud.js +1 -1
- package/app/stores/menu.js +1 -1
- package/app/stores/viewer.js +1 -1
- package/app/utils/extension.js +2 -2
- package/app/utils/local/microservices.js +61 -32
- package/nuxt.config.js +2 -0
- package/package.json +1 -1
- package/server/api/{app → serverless}/run_cloud.js +3 -3
- package/server/utils/cloud.js +22 -52
- package/tests/unit/stores/cloud.nuxt.test.js +2 -2
- 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
|
@@ -23,28 +23,24 @@ const menuStore = useMenuStore();
|
|
|
23
23
|
const dataStore = useDataStore();
|
|
24
24
|
|
|
25
25
|
const componentName = ref("");
|
|
26
|
+
const componentItem = ref(undefined);
|
|
26
27
|
|
|
27
28
|
watch(
|
|
28
29
|
() => menuStore.current_meta_data,
|
|
29
30
|
async (newMeta) => {
|
|
30
31
|
componentName.value = "";
|
|
32
|
+
componentItem.value = undefined;
|
|
31
33
|
if (!newMeta) {
|
|
32
34
|
return;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
componentName.value = comp.name;
|
|
43
|
-
} else {
|
|
44
|
-
componentName.value = newMeta.pickedComponentId;
|
|
45
|
-
}
|
|
46
|
-
} catch {
|
|
47
|
-
componentName.value = newMeta.pickedComponentId;
|
|
37
|
+
const modelId = newMeta.modelId || newMeta.id;
|
|
38
|
+
if (newMeta.pickedComponentId && modelId) {
|
|
39
|
+
const components = await dataStore.getAllMeshComponents(modelId);
|
|
40
|
+
const comp = components.find((component) => component.id === newMeta.pickedComponentId);
|
|
41
|
+
if (comp) {
|
|
42
|
+
componentName.value = comp.title;
|
|
43
|
+
componentItem.value = comp;
|
|
48
44
|
}
|
|
49
45
|
}
|
|
50
46
|
},
|
|
@@ -56,7 +52,7 @@ const cleanName = computed(() => {
|
|
|
56
52
|
if (!meta) {
|
|
57
53
|
return "Unnamed Object";
|
|
58
54
|
}
|
|
59
|
-
if (componentName.value) {
|
|
55
|
+
if (componentName.value && meta.viewer_type === "model_component") {
|
|
60
56
|
return componentName.value;
|
|
61
57
|
}
|
|
62
58
|
return meta.name || "Unnamed Object";
|
|
@@ -70,6 +66,18 @@ const displayTitle = computed(() => {
|
|
|
70
66
|
return middleTruncate(name, TRUNCATE_MAX_LENGTH, TRUNCATE_START_CHARS, TRUNCATE_END_CHARS);
|
|
71
67
|
});
|
|
72
68
|
|
|
69
|
+
const displayComponentTitle = computed(() => {
|
|
70
|
+
if (!componentItem.value) {
|
|
71
|
+
return "";
|
|
72
|
+
}
|
|
73
|
+
return middleTruncate(
|
|
74
|
+
componentItem.value.title,
|
|
75
|
+
TRUNCATE_MAX_LENGTH,
|
|
76
|
+
TRUNCATE_START_CHARS,
|
|
77
|
+
TRUNCATE_END_CHARS,
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
73
81
|
const copied = ref(false);
|
|
74
82
|
async function copyId(targetId) {
|
|
75
83
|
if (!targetId) {
|
|
@@ -86,16 +94,17 @@ async function copyId(targetId) {
|
|
|
86
94
|
}
|
|
87
95
|
}
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (!metaId) {
|
|
97
|
+
function formatId(id) {
|
|
98
|
+
if (!id) {
|
|
92
99
|
return "";
|
|
93
100
|
}
|
|
94
|
-
if (
|
|
95
|
-
return
|
|
101
|
+
if (id.length <= MAX_SHORT_ID_LENGTH) {
|
|
102
|
+
return id;
|
|
96
103
|
}
|
|
97
|
-
return `${
|
|
98
|
-
}
|
|
104
|
+
return `${id.slice(0, ID_SLICE_START)}...${id.slice(id.length - ID_SLICE_END_OFFSET)}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const formattedId = computed(() => formatId(metaData?.id));
|
|
99
108
|
</script>
|
|
100
109
|
|
|
101
110
|
<template>
|
|
@@ -138,6 +147,32 @@ const formattedId = computed(() => {
|
|
|
138
147
|
class="ml-1"
|
|
139
148
|
/>
|
|
140
149
|
</v-col>
|
|
150
|
+
|
|
151
|
+
<template v-if="componentItem">
|
|
152
|
+
<v-divider class="w-100 my-2" opacity="0.2" />
|
|
153
|
+
<v-col
|
|
154
|
+
class="text-subtitle-2 font-weight-bold text-truncate text-white w-100 pa-0"
|
|
155
|
+
cols="auto"
|
|
156
|
+
style="line-height: 1.3"
|
|
157
|
+
>
|
|
158
|
+
{{ displayComponentTitle }}
|
|
159
|
+
</v-col>
|
|
160
|
+
<v-col
|
|
161
|
+
class="text-caption font-weight-black text-uppercase text-secondary pa-0"
|
|
162
|
+
style="font-size: 0.68rem; line-height: 1.2"
|
|
163
|
+
>
|
|
164
|
+
{{ componentItem.category }}
|
|
165
|
+
</v-col>
|
|
166
|
+
<v-col
|
|
167
|
+
class="id-badge-container mt-1 d-inline-flex align-center px-2 py-0.5"
|
|
168
|
+
@click.stop="copyId(componentItem.id)"
|
|
169
|
+
>
|
|
170
|
+
<span class="id-text">
|
|
171
|
+
{{ formatId(componentItem.id) }}
|
|
172
|
+
</span>
|
|
173
|
+
<v-icon icon="mdi-content-copy" size="10" color="white" class="ml-1" />
|
|
174
|
+
</v-col>
|
|
175
|
+
</template>
|
|
141
176
|
</v-row>
|
|
142
177
|
</GlassCard>
|
|
143
178
|
</v-sheet>
|
|
@@ -19,7 +19,7 @@ const hybridViewerStore = useHybridViewerStore();
|
|
|
19
19
|
const blocksVisibility = computed({
|
|
20
20
|
get: () => dataStyleStore.modelComponentTypeVisibility(modelId, "Block"),
|
|
21
21
|
set: async (newValue) => {
|
|
22
|
-
await dataStyleStore.
|
|
22
|
+
await dataStyleStore.setModelBlocksVisibility(modelId, targetBlockIds, newValue);
|
|
23
23
|
hybridViewerStore.remoteRender();
|
|
24
24
|
},
|
|
25
25
|
});
|
|
@@ -36,7 +36,7 @@ const blockVisibility = computed({
|
|
|
36
36
|
const blocksColor = computed({
|
|
37
37
|
get: () => dataStyleStore.modelComponentTypeColor(modelId, "Block"),
|
|
38
38
|
set: async (color) => {
|
|
39
|
-
await dataStyleStore.
|
|
39
|
+
await dataStyleStore.setModelBlocksColor(modelId, targetBlockIds, color);
|
|
40
40
|
hybridViewerStore.remoteRender();
|
|
41
41
|
},
|
|
42
42
|
});
|
|
@@ -52,7 +52,7 @@ const blockColor = computed({
|
|
|
52
52
|
const blocksActiveColoring = computed({
|
|
53
53
|
get: () => dataStyleStore.getModelComponentTypeActiveColoring(modelId, "Block"),
|
|
54
54
|
set: async (coloringType) => {
|
|
55
|
-
await dataStyleStore.
|
|
55
|
+
await dataStyleStore.setModelBlocksActiveColoring(modelId, targetBlockIds, coloringType);
|
|
56
56
|
hybridViewerStore.remoteRender();
|
|
57
57
|
},
|
|
58
58
|
});
|
|
@@ -13,14 +13,13 @@ const { modelId, cornerId, targetCornerIds } = defineProps({
|
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
const dataStyleStore = useDataStyleStore();
|
|
16
|
-
console.log("CornersOptions setup!");
|
|
17
16
|
const hybridViewerStore = useHybridViewerStore();
|
|
18
17
|
|
|
19
18
|
// Visibility
|
|
20
19
|
const cornersVisibility = computed({
|
|
21
20
|
get: () => dataStyleStore.modelComponentTypeVisibility(modelId, "Corner"),
|
|
22
21
|
set: async (newValue) => {
|
|
23
|
-
await dataStyleStore.
|
|
22
|
+
await dataStyleStore.setModelCornersVisibility(modelId, targetCornerIds, newValue);
|
|
24
23
|
hybridViewerStore.remoteRender();
|
|
25
24
|
},
|
|
26
25
|
});
|
|
@@ -37,7 +36,7 @@ const cornerVisibility = computed({
|
|
|
37
36
|
const cornersColor = computed({
|
|
38
37
|
get: () => dataStyleStore.modelComponentTypeColor(modelId, "Corner"),
|
|
39
38
|
set: async (color) => {
|
|
40
|
-
await dataStyleStore.
|
|
39
|
+
await dataStyleStore.setModelCornersColor(modelId, targetCornerIds, color);
|
|
41
40
|
hybridViewerStore.remoteRender();
|
|
42
41
|
},
|
|
43
42
|
});
|
|
@@ -53,7 +52,7 @@ const cornerColor = computed({
|
|
|
53
52
|
const cornersActiveColoring = computed({
|
|
54
53
|
get: () => dataStyleStore.getModelComponentTypeActiveColoring(modelId, "Corner"),
|
|
55
54
|
set: async (coloringType) => {
|
|
56
|
-
await dataStyleStore.
|
|
55
|
+
await dataStyleStore.setModelCornersActiveColoring(modelId, targetCornerIds, coloringType);
|
|
57
56
|
hybridViewerStore.remoteRender();
|
|
58
57
|
},
|
|
59
58
|
});
|
|
@@ -19,7 +19,7 @@ const hybridViewerStore = useHybridViewerStore();
|
|
|
19
19
|
const linesVisibility = computed({
|
|
20
20
|
get: () => dataStyleStore.modelComponentTypeVisibility(modelId, "Line"),
|
|
21
21
|
set: async (newValue) => {
|
|
22
|
-
await dataStyleStore.
|
|
22
|
+
await dataStyleStore.setModelLinesVisibility(modelId, targetLineIds, newValue);
|
|
23
23
|
hybridViewerStore.remoteRender();
|
|
24
24
|
},
|
|
25
25
|
});
|
|
@@ -36,7 +36,7 @@ const lineVisibility = computed({
|
|
|
36
36
|
const linesColor = computed({
|
|
37
37
|
get: () => dataStyleStore.modelComponentTypeColor(modelId, "Line"),
|
|
38
38
|
set: async (color) => {
|
|
39
|
-
await dataStyleStore.
|
|
39
|
+
await dataStyleStore.setModelLinesColor(modelId, targetLineIds, color);
|
|
40
40
|
hybridViewerStore.remoteRender();
|
|
41
41
|
},
|
|
42
42
|
});
|
|
@@ -52,7 +52,7 @@ const lineColor = computed({
|
|
|
52
52
|
const linesActiveColoring = computed({
|
|
53
53
|
get: () => dataStyleStore.getModelComponentTypeActiveColoring(modelId, "Line"),
|
|
54
54
|
set: async (coloringType) => {
|
|
55
|
-
await dataStyleStore.
|
|
55
|
+
await dataStyleStore.setModelLinesActiveColoring(modelId, targetLineIds, coloringType);
|
|
56
56
|
hybridViewerStore.remoteRender();
|
|
57
57
|
},
|
|
58
58
|
});
|
|
@@ -63,9 +63,13 @@ watch(
|
|
|
63
63
|
|
|
64
64
|
const targetComponentIds = ref([]);
|
|
65
65
|
watch(
|
|
66
|
-
() => [modelId.value, componentType.value],
|
|
66
|
+
() => [modelId.value, componentType.value, itemProps.meta_data.targetComponentIds],
|
|
67
67
|
async () => {
|
|
68
68
|
targetComponentIds.value = [];
|
|
69
|
+
if (itemProps.meta_data.targetComponentIds) {
|
|
70
|
+
targetComponentIds.value = itemProps.meta_data.targetComponentIds;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
69
73
|
if (componentType.value && modelId.value) {
|
|
70
74
|
const currentModelId = modelId.value;
|
|
71
75
|
const currentType = componentType.value;
|
|
@@ -19,7 +19,7 @@ const hybridViewerStore = useHybridViewerStore();
|
|
|
19
19
|
const surfacesVisibility = computed({
|
|
20
20
|
get: () => dataStyleStore.modelComponentTypeVisibility(modelId, "Surface"),
|
|
21
21
|
set: async (newValue) => {
|
|
22
|
-
await dataStyleStore.
|
|
22
|
+
await dataStyleStore.setModelSurfacesVisibility(modelId, targetSurfaceIds, newValue);
|
|
23
23
|
hybridViewerStore.remoteRender();
|
|
24
24
|
},
|
|
25
25
|
});
|
|
@@ -36,7 +36,7 @@ const surfaceVisibility = computed({
|
|
|
36
36
|
const surfacesColor = computed({
|
|
37
37
|
get: () => dataStyleStore.modelComponentTypeColor(modelId, "Surface"),
|
|
38
38
|
set: async (color) => {
|
|
39
|
-
await dataStyleStore.
|
|
39
|
+
await dataStyleStore.setModelSurfacesColor(modelId, targetSurfaceIds, color);
|
|
40
40
|
hybridViewerStore.remoteRender();
|
|
41
41
|
},
|
|
42
42
|
});
|
|
@@ -52,7 +52,7 @@ const surfaceColor = computed({
|
|
|
52
52
|
const surfacesActiveColoring = computed({
|
|
53
53
|
get: () => dataStyleStore.getModelComponentTypeActiveColoring(modelId, "Surface"),
|
|
54
54
|
set: async (coloringType) => {
|
|
55
|
-
await dataStyleStore.
|
|
55
|
+
await dataStyleStore.setModelSurfacesActiveColoring(modelId, targetSurfaceIds, coloringType);
|
|
56
56
|
hybridViewerStore.remoteRender();
|
|
57
57
|
},
|
|
58
58
|
});
|
|
@@ -79,7 +79,7 @@ const itemsForTreeView = computed(() => {
|
|
|
79
79
|
for (const category of filteredCategories.value) {
|
|
80
80
|
result.push({
|
|
81
81
|
...category,
|
|
82
|
-
children: sortAndFormatItems(componentsCache.value
|
|
82
|
+
children: sortAndFormatItems(componentsCache.value[category.id], sortType.value),
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
return result;
|
|
@@ -87,12 +87,16 @@ const itemsForTreeView = computed(() => {
|
|
|
87
87
|
|
|
88
88
|
function showContextMenu(event, item) {
|
|
89
89
|
const actualItem = item.raw || item;
|
|
90
|
+
const typeId = actualItem.category || actualItem.id;
|
|
91
|
+
const typeItem = itemsForTreeView.value.find((type) => type.id === typeId);
|
|
92
|
+
const targetComponentIds = typeItem ? typeItem.children.map((child) => child.id) : undefined;
|
|
90
93
|
emit("show-menu", {
|
|
91
94
|
event,
|
|
92
95
|
itemId: actualItem.category ? actualItem.id : id,
|
|
93
96
|
context_type: actualItem.category ? "model_component" : "model_component_type",
|
|
94
97
|
modelId: id,
|
|
95
98
|
modelComponentType: actualItem.category ? undefined : actualItem.id,
|
|
99
|
+
targetComponentIds,
|
|
96
100
|
});
|
|
97
101
|
}
|
|
98
102
|
|
|
@@ -108,7 +112,7 @@ function handleHoverEnter({ item, immediate = false }) {
|
|
|
108
112
|
() =>
|
|
109
113
|
actualItem.category
|
|
110
114
|
? [actualItem.viewer_id]
|
|
111
|
-
: actualItem.children
|
|
115
|
+
: actualItem.children.map((child) => child.viewer_id),
|
|
112
116
|
"model",
|
|
113
117
|
immediate,
|
|
114
118
|
);
|
|
@@ -78,7 +78,8 @@ 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
|
+
data-testid="colorMapListLoading"
|
|
82
83
|
contained
|
|
83
84
|
persistent
|
|
84
85
|
class="align-center justify-center"
|
|
@@ -87,9 +88,9 @@ watch(filteredPresets, drawAllCanvases);
|
|
|
87
88
|
>
|
|
88
89
|
<v-progress-circular indeterminate color="primary" />
|
|
89
90
|
</v-overlay>
|
|
90
|
-
|
|
91
91
|
<v-text-field
|
|
92
92
|
v-model="filterText"
|
|
93
|
+
data-testid="colorMapListFilter"
|
|
93
94
|
placeholder="Search presets..."
|
|
94
95
|
density="compact"
|
|
95
96
|
hide-details
|
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: {
|
package/app/stores/menu.js
CHANGED
|
@@ -83,7 +83,7 @@ const Section_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
|
83
83
|
|
|
84
84
|
const StructuralModel_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
85
85
|
|
|
86
|
-
const ModelComponent_menu = [ModelStyleOptions];
|
|
86
|
+
const ModelComponent_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
87
87
|
|
|
88
88
|
const menusData = {
|
|
89
89
|
mesh: {
|
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: {
|
|
@@ -13,6 +13,7 @@ import { executablePath } from "./path.js";
|
|
|
13
13
|
|
|
14
14
|
const MILLISECONDS_PER_SECOND = 1000;
|
|
15
15
|
const DEFAULT_TIMEOUT_SECONDS = 45;
|
|
16
|
+
const MAX_PORT_RETRIES = 1;
|
|
16
17
|
|
|
17
18
|
async function runScript(
|
|
18
19
|
execPath,
|
|
@@ -51,7 +52,11 @@ async function runScript(
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
function isPortInUseError(errorMessage) {
|
|
56
|
+
return /EADDRINUSE|address already in use|port already in use/iu.test(errorMessage);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function runBack(execName, execPath, args = {}, attempts = 0) {
|
|
55
60
|
const { projectFolderPath } = args;
|
|
56
61
|
if (!projectFolderPath) {
|
|
57
62
|
throw new Error("projectFolderPath is required");
|
|
@@ -60,44 +65,68 @@ async function runBack(execName, execPath, args = {}) {
|
|
|
60
65
|
if (!uploadFolderPath) {
|
|
61
66
|
uploadFolderPath = path.join(projectFolderPath, "uploads");
|
|
62
67
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
68
|
+
try {
|
|
69
|
+
const port = await getAvailablePort();
|
|
70
|
+
const backArgs = [
|
|
71
|
+
"--port",
|
|
72
|
+
String(port),
|
|
73
|
+
"--project_folder_path",
|
|
74
|
+
projectFolderPath,
|
|
75
|
+
"--upload_folder_path",
|
|
76
|
+
uploadFolderPath,
|
|
77
|
+
"--allowed_origins",
|
|
78
|
+
"http://localhost:*",
|
|
79
|
+
"--timeout",
|
|
80
|
+
"0",
|
|
81
|
+
];
|
|
82
|
+
if (process.env.NODE_ENV === "development" || !process.env.NODE_ENV) {
|
|
83
|
+
backArgs.push("--debug");
|
|
84
|
+
}
|
|
85
|
+
console.log("runBack", execPath, execName, backArgs);
|
|
86
|
+
await runScript(execPath, execName, backArgs, "Serving Flask app");
|
|
87
|
+
return port;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (!isPortInUseError(error)) {
|
|
90
|
+
console.log("runBack error", error);
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
if (attempts <= MAX_PORT_RETRIES) {
|
|
94
|
+
console.log("Retrying runBack on conflicting port", port);
|
|
95
|
+
const port = await runBack(execName, execPath, args, attempts + 1);
|
|
96
|
+
return port;
|
|
97
|
+
}
|
|
78
98
|
}
|
|
79
|
-
console.log("runBack", execPath, execName, backArgs);
|
|
80
|
-
await runScript(execPath, execName, backArgs, "Serving Flask app");
|
|
81
|
-
return port;
|
|
82
99
|
}
|
|
83
100
|
|
|
84
|
-
async function runViewer(execName, execPath, args = {}) {
|
|
101
|
+
async function runViewer(execName, execPath, args = {}, attempts = 0) {
|
|
85
102
|
const { projectFolderPath } = args;
|
|
86
103
|
if (!projectFolderPath) {
|
|
87
104
|
throw new Error("projectFolderPath is required");
|
|
88
105
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
try {
|
|
107
|
+
const port = await getAvailablePort();
|
|
108
|
+
const viewerArgs = [
|
|
109
|
+
"--port",
|
|
110
|
+
String(port),
|
|
111
|
+
"--project_folder_path",
|
|
112
|
+
projectFolderPath,
|
|
113
|
+
"--timeout",
|
|
114
|
+
"0",
|
|
115
|
+
];
|
|
116
|
+
console.log("runViewer", execPath, execName, viewerArgs);
|
|
117
|
+
await runScript(execPath, execName, viewerArgs, "Starting factory");
|
|
118
|
+
return port;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (!isPortInUseError(error)) {
|
|
121
|
+
console.log("runBack error", error);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
if (attempts <= MAX_PORT_RETRIES) {
|
|
125
|
+
console.log("Retrying runViewer on conflicting port", port);
|
|
126
|
+
const port = await runViewer(execName, execPath, args, attempts + 1);
|
|
127
|
+
return port;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
101
130
|
}
|
|
102
131
|
|
|
103
132
|
function addMicroserviceMetadatas(projectFolderPath, serviceObj) {
|
package/nuxt.config.js
CHANGED
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@ import { GoogleAuth } from "google-auth-library";
|
|
|
6
6
|
import { ServicesClient } from "@google-cloud/run";
|
|
7
7
|
|
|
8
8
|
// Local imports
|
|
9
|
-
import {
|
|
9
|
+
import { artifactImage, requestConfig } from "@ogw_server/utils/cloud";
|
|
10
10
|
|
|
11
11
|
export default defineEventHandler(async (event) => {
|
|
12
12
|
try {
|
|
@@ -23,8 +23,8 @@ export default defineEventHandler(async (event) => {
|
|
|
23
23
|
scopes: ["https://www.googleapis.com/auth/cloud-platform"],
|
|
24
24
|
});
|
|
25
25
|
const authClient = await auth.getClient();
|
|
26
|
-
const
|
|
27
|
-
const request = requestConfig(parent,
|
|
26
|
+
const image = await artifactImage(parent, authClient);
|
|
27
|
+
const request = requestConfig(parent, image, email, projectName);
|
|
28
28
|
console.log({ request });
|
|
29
29
|
const runClient = new ServicesClient({ authClient });
|
|
30
30
|
const [operation] = await runClient.createService(request);
|
package/server/utils/cloud.js
CHANGED
|
@@ -5,11 +5,16 @@ import { google } from "googleapis";
|
|
|
5
5
|
|
|
6
6
|
// Local imports
|
|
7
7
|
|
|
8
|
-
async function artifactImage(
|
|
8
|
+
async function artifactImage(parent, authClient) {
|
|
9
|
+
const projectName = process.env.PROJECT;
|
|
10
|
+
const registry = google.artifactregistry({
|
|
11
|
+
version: "v1",
|
|
12
|
+
auth: authClient,
|
|
13
|
+
});
|
|
9
14
|
const branch = process.env.NETLIFY_BRANCH;
|
|
10
15
|
const [_, projectId] = parent.split("/");
|
|
11
16
|
const repository = `${parent}/repositories/github/packages/`;
|
|
12
|
-
const name = `${repository}${
|
|
17
|
+
const name = `${repository}${projectName}/tags/${branch}`;
|
|
13
18
|
console.log({ name });
|
|
14
19
|
const response = await registry.projects.locations.repositories.packages.tags.get({
|
|
15
20
|
name,
|
|
@@ -17,24 +22,11 @@ async function artifactImage(registry, parent, repo) {
|
|
|
17
22
|
console.log({ response });
|
|
18
23
|
const digest = response.data.version.split("/").pop();
|
|
19
24
|
const artifactRegistry = `europe-west9-docker.pkg.dev/${projectId}/github`;
|
|
20
|
-
const image = `${artifactRegistry}/${
|
|
21
|
-
console.log("Found image for",
|
|
25
|
+
const image = `${artifactRegistry}/${projectName}@${digest}`;
|
|
26
|
+
console.log("Found image for", projectName, image);
|
|
22
27
|
return image;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
|
-
function artifactImages(parent, authClient) {
|
|
26
|
-
const projectName = process.env.PROJECT;
|
|
27
|
-
const registry = google.artifactregistry({
|
|
28
|
-
version: "v1",
|
|
29
|
-
auth: authClient,
|
|
30
|
-
});
|
|
31
|
-
return Promise.all([
|
|
32
|
-
artifactImage(registry, parent, "opengeodeweb-router"),
|
|
33
|
-
artifactImage(registry, parent, `${projectName}-back`),
|
|
34
|
-
artifactImage(registry, parent, `${projectName}-viewer`),
|
|
35
|
-
]);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
30
|
function sanitizeLabelValue(label) {
|
|
39
31
|
console.log("label", label);
|
|
40
32
|
const maxLabelLength = 63;
|
|
@@ -44,47 +36,35 @@ function sanitizeLabelValue(label) {
|
|
|
44
36
|
.slice(0, maxLabelLength);
|
|
45
37
|
}
|
|
46
38
|
|
|
47
|
-
|
|
48
|
-
function requestConfig(parent, routerImage, backImage, viewerImage, email, projectName) {
|
|
39
|
+
function requestConfig(parent, image, email, projectName) {
|
|
49
40
|
const resources = {
|
|
50
41
|
limits: {
|
|
51
|
-
cpu: "
|
|
52
|
-
memory: "
|
|
42
|
+
cpu: "2000m",
|
|
43
|
+
memory: "3Gi",
|
|
53
44
|
},
|
|
45
|
+
cpuIdle: false,
|
|
46
|
+
startup_cpu_boost: true,
|
|
54
47
|
};
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
const labels = {
|
|
49
|
+
user: sanitizeLabelValue(email),
|
|
50
|
+
project: sanitizeLabelValue(projectName),
|
|
58
51
|
};
|
|
59
52
|
return {
|
|
60
53
|
parent,
|
|
61
54
|
service: {
|
|
62
55
|
ingress: "INGRESS_TRAFFIC_ALL",
|
|
63
56
|
invokerIamDisabled: true,
|
|
64
|
-
labels
|
|
65
|
-
user: sanitizeLabelValue(email),
|
|
66
|
-
project: sanitizeLabelValue(projectName),
|
|
67
|
-
},
|
|
57
|
+
labels,
|
|
68
58
|
scaling: {
|
|
69
59
|
scalingMode: "MANUAL",
|
|
70
60
|
manualInstanceCount: 1,
|
|
71
61
|
},
|
|
72
62
|
template: {
|
|
73
|
-
labels
|
|
74
|
-
|
|
75
|
-
project: sanitizeLabelValue(projectId),
|
|
76
|
-
},
|
|
77
|
-
volumes: [
|
|
78
|
-
{
|
|
79
|
-
name: "project",
|
|
80
|
-
emptyDir: {
|
|
81
|
-
medium: "MEMORY",
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
],
|
|
63
|
+
labels,
|
|
64
|
+
timeout: { seconds: 3600 },
|
|
85
65
|
containers: [
|
|
86
66
|
{
|
|
87
|
-
image
|
|
67
|
+
image,
|
|
88
68
|
ports: [
|
|
89
69
|
{
|
|
90
70
|
containerPort: 80,
|
|
@@ -106,20 +86,10 @@ function requestConfig(parent, routerImage, backImage, viewerImage, email, proje
|
|
|
106
86
|
failureThreshold: 30,
|
|
107
87
|
},
|
|
108
88
|
},
|
|
109
|
-
{
|
|
110
|
-
image: backImage,
|
|
111
|
-
resources,
|
|
112
|
-
volumeMounts: [volumeMounts],
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
image: viewerImage,
|
|
116
|
-
resources,
|
|
117
|
-
volumeMounts: [volumeMounts],
|
|
118
|
-
},
|
|
119
89
|
],
|
|
120
90
|
},
|
|
121
91
|
},
|
|
122
92
|
};
|
|
123
93
|
}
|
|
124
94
|
|
|
125
|
-
export {
|
|
95
|
+
export { artifactImage, requestConfig };
|
|
@@ -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
|
});
|
|
@@ -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
|