@geode/opengeodeweb-front 10.24.2 → 10.25.0-rc.2
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/Generic/Mesh/PolyhedraOptions.vue +1 -1
- package/app/stores/app.js +20 -27
- package/app/stores/infra.js +7 -0
- package/app/utils/config.js +23 -1
- package/app/utils/extension.js +25 -0
- package/app/utils/local/cleanup.js +28 -15
- package/app/utils/local/path.js +5 -0
- package/package.json +3 -3
- package/server/api/extensions/kill.post.js +43 -0
- package/server/api/extensions/run.post.js +3 -4
|
@@ -128,7 +128,7 @@ const polyhedron_attribute_color_map = computed({
|
|
|
128
128
|
v-model:polyhedron_attribute_range="polyhedron_attribute_range"
|
|
129
129
|
v-model:polyhedron_attribute_color_map="polyhedron_attribute_color_map"
|
|
130
130
|
:capabilities="{
|
|
131
|
-
vertex: { available: true, hasColorMap:
|
|
131
|
+
vertex: { available: true, hasColorMap: true },
|
|
132
132
|
polyhedron: { available: true, hasColorMap: true },
|
|
133
133
|
}"
|
|
134
134
|
/>
|
package/app/stores/app.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import { api_fetch } from "@ogw_internal/utils/api_fetch.js";
|
|
3
3
|
import { upload_file } from "@ogw_internal/utils/upload_file.js";
|
|
4
4
|
|
|
5
|
+
import { killExtension } from "@ogw_front/utils/extension.js";
|
|
6
|
+
import { useInfraStore } from "@ogw_front/stores/infra";
|
|
7
|
+
|
|
5
8
|
// oxlint-disable-next-line max-lines-per-function, max-statements
|
|
6
9
|
export const useAppStore = defineStore("app", () => {
|
|
7
10
|
const stores = [];
|
|
@@ -155,51 +158,41 @@ export const useAppStore = defineStore("app", () => {
|
|
|
155
158
|
return [...loadedExtensions.value.values()];
|
|
156
159
|
}
|
|
157
160
|
|
|
158
|
-
function unloadExtension(
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (extensionData.module && typeof extensionData.module.uninstall === "function") {
|
|
164
|
-
try {
|
|
165
|
-
extensionData.module.uninstall(extensionAPI.value);
|
|
166
|
-
console.log(`[AppStore] Extension uninstall called: ${id}`);
|
|
167
|
-
} catch (error) {
|
|
168
|
-
console.error(`[AppStore] Error calling uninstall for ${id}:`, error);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (extensionAPI.value && typeof extensionAPI.value.unregisterToolsByExtension === "function") {
|
|
173
|
-
extensionAPI.value.unregisterToolsByExtension(id);
|
|
174
|
-
}
|
|
161
|
+
async function unloadExtension(extensionId) {
|
|
162
|
+
console.log(`[AppStore] Unloading extension: ${extensionId}`);
|
|
163
|
+
const infraStore = useInfraStore();
|
|
164
|
+
await infraStore.unregister_microservice(extensionId);
|
|
165
|
+
await killExtension(extensionId);
|
|
175
166
|
|
|
176
|
-
loadedExtensions.value.delete(
|
|
177
|
-
console.log(`[AppStore] Extension unloaded: ${
|
|
167
|
+
loadedExtensions.value.delete(extensionId);
|
|
168
|
+
console.log(`[AppStore] Extension unloaded: ${extensionId}`);
|
|
178
169
|
return true;
|
|
179
170
|
}
|
|
180
171
|
|
|
181
|
-
function toggleExtension(
|
|
182
|
-
const extensionData = getExtension(
|
|
172
|
+
function toggleExtension(extensionId) {
|
|
173
|
+
const extensionData = getExtension(extensionId);
|
|
183
174
|
if (!extensionData) {
|
|
184
175
|
return false;
|
|
185
176
|
}
|
|
186
177
|
extensionData.enabled = !extensionData.enabled;
|
|
187
|
-
console.log(
|
|
178
|
+
console.log(
|
|
179
|
+
`[AppStore] Extension ${extensionData.enabled ? "enabled" : "disabled"}: ${extensionId}`,
|
|
180
|
+
);
|
|
188
181
|
return extensionData.enabled;
|
|
189
182
|
}
|
|
190
183
|
|
|
191
|
-
function setExtensionEnabled(
|
|
192
|
-
const extensionData = getExtension(
|
|
184
|
+
function setExtensionEnabled(extensionId, enabled) {
|
|
185
|
+
const extensionData = getExtension(extensionId);
|
|
193
186
|
if (!extensionData) {
|
|
194
187
|
return false;
|
|
195
188
|
}
|
|
196
189
|
extensionData.enabled = enabled;
|
|
197
|
-
console.log(`[AppStore] Extension ${enabled ? "enabled" : "disabled"}: ${
|
|
190
|
+
console.log(`[AppStore] Extension ${enabled ? "enabled" : "disabled"}: ${extensionId}`);
|
|
198
191
|
return true;
|
|
199
192
|
}
|
|
200
193
|
|
|
201
|
-
function getExtensionEnabled(
|
|
202
|
-
return getExtension(
|
|
194
|
+
function getExtensionEnabled(extensionId) {
|
|
195
|
+
return getExtension(extensionId)?.enabled ?? false;
|
|
203
196
|
}
|
|
204
197
|
|
|
205
198
|
function upload(file, callbacks = {}) {
|
package/app/stores/infra.js
CHANGED
|
@@ -30,6 +30,13 @@ export const useInfraStore = defineStore("infra", {
|
|
|
30
30
|
console.log("[INFRA] Microservice registered:", store_name);
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
+
unregister_microservice(microserviceId) {
|
|
34
|
+
console.log("[INFRA] Unregistering microservice:", microserviceId);
|
|
35
|
+
this.microservices = this.microservices.filter(
|
|
36
|
+
(microservice) => microservice.$id !== microserviceId,
|
|
37
|
+
);
|
|
38
|
+
console.log("[INFRA] Microservice unregistered:", microserviceId);
|
|
39
|
+
},
|
|
33
40
|
create_backend(name, email, launch) {
|
|
34
41
|
console.log("[INFRA] Starting create_backend - Mode:", this.app_mode);
|
|
35
42
|
console.log(
|
package/app/utils/config.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Node.js imports
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { unlink } from "node:fs";
|
|
3
4
|
|
|
4
5
|
// Third party imports
|
|
5
6
|
import Conf from "conf";
|
|
@@ -31,9 +32,30 @@ function addExtensionToConf(projectName, { extensionID, extensionPath }) {
|
|
|
31
32
|
projectConfig.set(`extensions.${extensionID}.path`, extensionPath);
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
async function removeExtensionFromConf(projectName, extensionID) {
|
|
36
|
+
const projectConfig = projectConf(projectName);
|
|
37
|
+
const extensionArchivePath = extensionPathFromConf(projectName, extensionID);
|
|
38
|
+
|
|
39
|
+
await unlink(extensionArchivePath, (error) => {
|
|
40
|
+
if (error) {
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
console.log(`${extensionArchivePath} was deleted`);
|
|
44
|
+
});
|
|
45
|
+
projectConfig.delete(`extensions.${extensionID}`);
|
|
46
|
+
console.log(`${extensionID} was deleted from ${projectName} config`);
|
|
47
|
+
}
|
|
48
|
+
|
|
34
49
|
function extensionPathFromConf(projectName, extensionID) {
|
|
35
50
|
const projectConfig = projectConf(projectName);
|
|
36
51
|
return projectConfig.get(`extensions.${extensionID}.path`);
|
|
37
52
|
}
|
|
38
53
|
|
|
39
|
-
export {
|
|
54
|
+
export {
|
|
55
|
+
confFolderPath,
|
|
56
|
+
projectConf,
|
|
57
|
+
extensionsConf,
|
|
58
|
+
addExtensionToConf,
|
|
59
|
+
removeExtensionFromConf,
|
|
60
|
+
extensionPathFromConf,
|
|
61
|
+
};
|
package/app/utils/extension.js
CHANGED
|
@@ -95,10 +95,35 @@ function runExtensions() {
|
|
|
95
95
|
return appStore.request({ schema, params });
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
function killExtension(extensionId) {
|
|
99
|
+
const appStore = useAppStore();
|
|
100
|
+
const { projectFolderPath } = appStore;
|
|
101
|
+
const { PROJECT: projectName } = useRuntimeConfig().public;
|
|
102
|
+
const params = { extensionId, projectFolderPath, projectName };
|
|
103
|
+
|
|
104
|
+
console.log(`[AppStore] Killing extension: ${extensionId}`, { params });
|
|
105
|
+
|
|
106
|
+
const schema = {
|
|
107
|
+
$id: "/api/extensions/kill",
|
|
108
|
+
methods: ["POST"],
|
|
109
|
+
type: "object",
|
|
110
|
+
properties: {
|
|
111
|
+
extensionId: { type: "string" },
|
|
112
|
+
projectFolderPath: { type: "string" },
|
|
113
|
+
projectName: { type: "string" },
|
|
114
|
+
},
|
|
115
|
+
required: ["extensionId", "projectFolderPath", "projectName"],
|
|
116
|
+
additionalProperties: false,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return appStore.request({ schema, params });
|
|
120
|
+
}
|
|
121
|
+
|
|
98
122
|
export {
|
|
99
123
|
importExtensionFile,
|
|
100
124
|
unloadExtension,
|
|
101
125
|
uploadExtension,
|
|
102
126
|
registerRunningExtensions,
|
|
103
127
|
runExtensions,
|
|
128
|
+
killExtension,
|
|
104
129
|
};
|
|
@@ -38,14 +38,9 @@ function killHttpMicroservice(microservice) {
|
|
|
38
38
|
console.log("killHttpMicroservice", { ...microservice });
|
|
39
39
|
const failMessage = `Failed to kill ${microservice.name}`;
|
|
40
40
|
async function do_kill() {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
throw new Error(failMessage);
|
|
46
|
-
} catch (error) {
|
|
47
|
-
console.log(`${microservice.name} closed`, error);
|
|
48
|
-
}
|
|
41
|
+
await $fetch(microservice.url, {
|
|
42
|
+
method: microservice.method,
|
|
43
|
+
});
|
|
49
44
|
}
|
|
50
45
|
return pTimeout(do_kill(), {
|
|
51
46
|
milliseconds: 5000,
|
|
@@ -103,20 +98,27 @@ function killWebsocketMicroservice(microservice) {
|
|
|
103
98
|
});
|
|
104
99
|
}
|
|
105
100
|
|
|
106
|
-
function killMicroservice(microservice) {
|
|
101
|
+
async function killMicroservice(microservice, microservices) {
|
|
107
102
|
if (microservice.type === "back") {
|
|
108
|
-
|
|
103
|
+
await killHttpMicroservice(microservice);
|
|
104
|
+
} else if (microservice.type === "viewer") {
|
|
105
|
+
await killWebsocketMicroservice(microservice);
|
|
106
|
+
} else {
|
|
107
|
+
throw new Error(`Unknown microservice type: ${microservice.type}`);
|
|
109
108
|
}
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
|
|
110
|
+
if (microservices) {
|
|
111
|
+
const index = microservices.indexOf(microservice);
|
|
112
|
+
if (index !== -1) {
|
|
113
|
+
microservices.splice(index, 1);
|
|
114
|
+
}
|
|
112
115
|
}
|
|
113
|
-
throw new Error(`Unknown microservice type: ${microservice.type}`);
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
function killMicroservices(microservices) {
|
|
117
119
|
console.log("killMicroservices", { microservices });
|
|
118
120
|
return Promise.all(
|
|
119
|
-
microservices.map(
|
|
121
|
+
microservices.map((microservice) => killMicroservice(microservice, microservices)),
|
|
120
122
|
);
|
|
121
123
|
}
|
|
122
124
|
|
|
@@ -142,8 +144,19 @@ async function cleanupBackend(projectFolderPath) {
|
|
|
142
144
|
await deleteFolderRecursive(projectFolderPath);
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
function getMicroserviceByName(microservices, name) {
|
|
148
|
+
return microservices.find((microservice) => microservice.name === name);
|
|
149
|
+
}
|
|
150
|
+
|
|
145
151
|
function microservicesMetadatasPath(projectFolderPath) {
|
|
146
152
|
return path.join(projectFolderPath, "microservices.json");
|
|
147
153
|
}
|
|
148
154
|
|
|
149
|
-
export {
|
|
155
|
+
export {
|
|
156
|
+
cleanupBackend,
|
|
157
|
+
deleteFolderRecursive,
|
|
158
|
+
killMicroservice,
|
|
159
|
+
microservicesMetadatasPath,
|
|
160
|
+
projectMicroservices,
|
|
161
|
+
getMicroserviceByName,
|
|
162
|
+
};
|
package/app/utils/local/path.js
CHANGED
|
@@ -49,6 +49,10 @@ function generateProjectFolderPath(projectName) {
|
|
|
49
49
|
return path.join(os.tmpdir(), projectName.replaceAll("/", "_"), uuidv4());
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
function extensionFolderPath(projectFolderPath, extensionID) {
|
|
53
|
+
return path.join(projectFolderPath, "extensions", extensionID);
|
|
54
|
+
}
|
|
55
|
+
|
|
52
56
|
async function lookForLocalExtensionDistPath(rootPath, extentionRepoName, frontendFile) {
|
|
53
57
|
const localExtensionPath = path.join(rootPath, "..", extentionRepoName);
|
|
54
58
|
const localExtensionDistPath = path.join(localExtensionPath, "dist");
|
|
@@ -108,6 +112,7 @@ async function extensionFrontendPath(unzippedExtensionPath, frontendFile, rootPa
|
|
|
108
112
|
export {
|
|
109
113
|
createPath,
|
|
110
114
|
extensionFrontendPath,
|
|
115
|
+
extensionFolderPath,
|
|
111
116
|
executablePath,
|
|
112
117
|
executableName,
|
|
113
118
|
generateProjectFolderPath,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geode/opengeodeweb-front",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.25.0-rc.2",
|
|
4
4
|
"description": "OpenSource Vue/Nuxt/Pinia/Vuetify framework for web applications",
|
|
5
5
|
"homepage": "https://github.com/Geode-solutions/OpenGeodeWeb-Front",
|
|
6
6
|
"bugs": {
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"build": ""
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@geode/opengeodeweb-back": "
|
|
38
|
-
"@geode/opengeodeweb-viewer": "
|
|
37
|
+
"@geode/opengeodeweb-back": "next",
|
|
38
|
+
"@geode/opengeodeweb-viewer": "next",
|
|
39
39
|
"@google-cloud/run": "3.2.0",
|
|
40
40
|
"@kitware/vtk.js": "33.3.0",
|
|
41
41
|
"@mdi/font": "7.4.47",
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Node imports
|
|
2
|
+
|
|
3
|
+
// Third party imports
|
|
4
|
+
import { createError, defineEventHandler, readBody } from "h3";
|
|
5
|
+
|
|
6
|
+
// Local imports
|
|
7
|
+
import {
|
|
8
|
+
deleteFolderRecursive,
|
|
9
|
+
getMicroserviceByName,
|
|
10
|
+
killMicroservice,
|
|
11
|
+
projectMicroservices,
|
|
12
|
+
} from "@geode/opengeodeweb-front/app/utils/local/cleanup.js";
|
|
13
|
+
import { extensionFolderPath } from "@geode/opengeodeweb-front/app/utils/local/path.js";
|
|
14
|
+
import { removeExtensionFromConf } from "@geode/opengeodeweb-front/app/utils/config.js";
|
|
15
|
+
|
|
16
|
+
export default defineEventHandler(async (event) => {
|
|
17
|
+
try {
|
|
18
|
+
const body = await readBody(event);
|
|
19
|
+
const { projectFolderPath, projectName, extensionId } = body;
|
|
20
|
+
|
|
21
|
+
console.log({ projectFolderPath, projectName, extensionId });
|
|
22
|
+
|
|
23
|
+
const microservices = projectMicroservices(projectFolderPath);
|
|
24
|
+
const microservice = getMicroserviceByName(microservices, extensionId);
|
|
25
|
+
if (!microservice) {
|
|
26
|
+
throw new Error(`Microservice ${extensionId} not found`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await removeExtensionFromConf(projectName, extensionId);
|
|
30
|
+
await deleteFolderRecursive(extensionFolderPath(projectFolderPath, extensionId));
|
|
31
|
+
await killMicroservice(microservice, microservices);
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
statusCode: 200,
|
|
35
|
+
};
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error("Error killing extension:", error);
|
|
38
|
+
throw createError({
|
|
39
|
+
statusCode: 500,
|
|
40
|
+
statusMessage: error.message,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
@@ -12,13 +12,12 @@ import {
|
|
|
12
12
|
} from "@geode/opengeodeweb-front/app/utils/local/microservices.js";
|
|
13
13
|
import {
|
|
14
14
|
executableName,
|
|
15
|
+
extensionFolderPath,
|
|
15
16
|
extensionFrontendPath,
|
|
16
17
|
} from "@geode/opengeodeweb-front/app/utils/local/path.js";
|
|
17
18
|
import { extensionsConf } from "@geode/opengeodeweb-front/app/utils/config.js";
|
|
18
19
|
import { unzipFile } from "@geode/opengeodeweb-front/app/utils/server.js";
|
|
19
20
|
|
|
20
|
-
const CODE_200 = 200;
|
|
21
|
-
|
|
22
21
|
export default defineEventHandler(async (event) => {
|
|
23
22
|
try {
|
|
24
23
|
const body = await readBody(event);
|
|
@@ -30,7 +29,7 @@ export default defineEventHandler(async (event) => {
|
|
|
30
29
|
const extensionPath = extensionsConfig[extensionID].path;
|
|
31
30
|
const unzippedExtensionPath = await unzipFile(
|
|
32
31
|
extensionPath,
|
|
33
|
-
|
|
32
|
+
extensionFolderPath(projectFolderPath, extensionID),
|
|
34
33
|
);
|
|
35
34
|
const metadataPath = path.join(unzippedExtensionPath, "metadata.json");
|
|
36
35
|
const metadataContent = await fs.promises.readFile(metadataPath, "utf8");
|
|
@@ -95,7 +94,7 @@ export default defineEventHandler(async (event) => {
|
|
|
95
94
|
);
|
|
96
95
|
|
|
97
96
|
return {
|
|
98
|
-
statusCode:
|
|
97
|
+
statusCode: 200,
|
|
99
98
|
extensionsArray,
|
|
100
99
|
};
|
|
101
100
|
} catch (error) {
|