@geode/opengeodeweb-front 10.5.1 → 10.6.0
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/FileUploader.vue +4 -5
- package/app/stores/app.js +80 -3
- package/app/stores/geode.js +54 -7
- package/app/stores/infra.js +25 -14
- package/app/stores/lambda.js +2 -1
- package/app/stores/viewer.js +40 -11
- package/app/utils/config.js +45 -0
- package/app/utils/extension.js +109 -0
- package/app/utils/local/microservices.js +259 -0
- package/app/utils/local/path.js +86 -0
- package/app/utils/local/scripts.js +49 -0
- package/app/utils/server.js +45 -0
- package/{app → internal}/utils/upload_file.js +8 -8
- package/nuxt.config.js +22 -4
- package/package.json +9 -4
- package/server/api/app/kill.post.js +11 -0
- package/server/api/app/project_folder_path.post.js +29 -0
- package/server/api/app/run_back.post.js +33 -0
- package/server/api/app/run_viewer.post.js +33 -0
- package/server/api/extensions/run.post.js +98 -0
- package/server/api/extensions/upload.put.js +105 -0
- package/tests/integration/microservices/back/requirements.txt +1 -1
- package/tests/integration/setup.js +39 -45
- package/tests/integration/stores/data_style/mesh/cells.nuxt.test.js +11 -22
- package/tests/integration/stores/data_style/mesh/edges.nuxt.test.js +10 -20
- package/tests/integration/stores/data_style/mesh/index.nuxt.test.js +10 -20
- package/tests/integration/stores/data_style/mesh/points.nuxt.test.js +10 -20
- package/tests/integration/stores/data_style/mesh/polygons.nuxt.test.js +10 -21
- package/tests/integration/stores/data_style/mesh/polyhedra.nuxt.test.js +10 -20
- package/tests/integration/stores/data_style/model/blocks.nuxt.test.js +10 -20
- package/tests/integration/stores/data_style/model/corners.nuxt.test.js +10 -20
- package/tests/integration/stores/data_style/model/edges.nuxt.test.js +10 -20
- package/tests/integration/stores/data_style/model/index.nuxt.test.js +10 -20
- package/tests/integration/stores/data_style/model/lines.nuxt.test.js +10 -16
- package/tests/integration/stores/data_style/model/points.nuxt.test.js +10 -15
- package/tests/integration/stores/data_style/model/surfaces.nuxt.test.js +15 -26
- package/tests/integration/stores/viewer.nuxt.test.js +6 -10
- package/tests/unit/composables/upload_file.nuxt.test.js +7 -9
- package/tests/unit/stores/infra.nuxt.test.js +6 -6
- package/tests/unit/stores/lambda.nuxt.test.js +2 -2
- package/app/utils/local.js +0 -361
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
// Node imports
|
|
2
|
+
import child_process from "node:child_process"
|
|
3
|
+
import fs from "node:fs"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
|
|
6
|
+
// Third party imports
|
|
7
|
+
import { WebSocket } from "ws"
|
|
8
|
+
import { getPort } from "get-port-please"
|
|
9
|
+
import pTimeout from "p-timeout"
|
|
10
|
+
import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_schemas.json" with { type: "json" }
|
|
11
|
+
|
|
12
|
+
// Local imports
|
|
13
|
+
import {
|
|
14
|
+
deleteFolderRecursive,
|
|
15
|
+
executablePath,
|
|
16
|
+
executableName,
|
|
17
|
+
} from "./path.js"
|
|
18
|
+
import { commandExistsSync, waitForReady } from "./scripts.js"
|
|
19
|
+
|
|
20
|
+
const DEFAULT_TIMEOUT_SECONDS = 30
|
|
21
|
+
const MILLISECONDS_PER_SECOND = 1000
|
|
22
|
+
|
|
23
|
+
function getAvailablePort() {
|
|
24
|
+
return getPort({
|
|
25
|
+
host: "localhost",
|
|
26
|
+
random: true,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function runScript(
|
|
31
|
+
execName,
|
|
32
|
+
execPath,
|
|
33
|
+
args,
|
|
34
|
+
expectedResponse,
|
|
35
|
+
timeoutSeconds = DEFAULT_TIMEOUT_SECONDS,
|
|
36
|
+
) {
|
|
37
|
+
const command = commandExistsSync(execName)
|
|
38
|
+
? execName
|
|
39
|
+
: path.join(await executablePath(execPath), executableName(execName))
|
|
40
|
+
console.log("runScript", command, args)
|
|
41
|
+
const child = child_process.spawn(command, args, {
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
shell: true,
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
child.stdout.on("data", (data) =>
|
|
47
|
+
console.log(`[${execName}] ${data.toString()}`),
|
|
48
|
+
)
|
|
49
|
+
child.stderr.on("data", (data) =>
|
|
50
|
+
console.log(`[${execName}] ${data.toString()}`),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
child.on("error", async (error) => {
|
|
54
|
+
const electron = await import("electron")
|
|
55
|
+
electron.dialog.showMessageBox({
|
|
56
|
+
title: "Title",
|
|
57
|
+
type: "warning",
|
|
58
|
+
message: `Error occured.\r\n${error}`,
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
child.on("close", (code) =>
|
|
63
|
+
console.log(`[${execName}] exited with code ${code}`),
|
|
64
|
+
)
|
|
65
|
+
child.on("kill", () => {
|
|
66
|
+
console.log(`[${execName}] process killed`)
|
|
67
|
+
})
|
|
68
|
+
child.name = command.replace(/^.*[\\/]/, "")
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
return await pTimeout(waitForReady(child, expectedResponse), {
|
|
72
|
+
milliseconds: timeoutSeconds * MILLISECONDS_PER_SECOND,
|
|
73
|
+
message: `Timed out after ${timeoutSeconds} seconds`,
|
|
74
|
+
})
|
|
75
|
+
} catch (error) {
|
|
76
|
+
child.kill()
|
|
77
|
+
throw error
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function runBack(execName, execPath, args = {}) {
|
|
82
|
+
const { projectFolderPath } = args
|
|
83
|
+
if (!projectFolderPath) {
|
|
84
|
+
throw new Error("projectFolderPath is required")
|
|
85
|
+
}
|
|
86
|
+
let { uploadFolderPath } = args
|
|
87
|
+
if (!uploadFolderPath) {
|
|
88
|
+
uploadFolderPath = path.join(projectFolderPath, "uploads")
|
|
89
|
+
}
|
|
90
|
+
const port = await getAvailablePort()
|
|
91
|
+
const backArgs = [
|
|
92
|
+
`--port ${port}`,
|
|
93
|
+
`--data_folder_path ${projectFolderPath}`,
|
|
94
|
+
`--upload_folder_path ${uploadFolderPath}`,
|
|
95
|
+
`--allowed_origin http://localhost:*`,
|
|
96
|
+
`--timeout ${0}`,
|
|
97
|
+
]
|
|
98
|
+
if (process.env.NODE_ENV === "development" || !process.env.NODE_ENV) {
|
|
99
|
+
backArgs.push("--debug")
|
|
100
|
+
}
|
|
101
|
+
console.log("runBack", execName, execPath, backArgs)
|
|
102
|
+
await runScript(execName, execPath, backArgs, "Serving Flask app")
|
|
103
|
+
return port
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function runViewer(execName, execPath, args = {}) {
|
|
107
|
+
const { projectFolderPath } = args
|
|
108
|
+
if (!projectFolderPath) {
|
|
109
|
+
throw new Error("projectFolderPath is required")
|
|
110
|
+
}
|
|
111
|
+
const port = await getAvailablePort()
|
|
112
|
+
const viewerArgs = [
|
|
113
|
+
`--port ${port}`,
|
|
114
|
+
`--data_folder_path ${projectFolderPath}`,
|
|
115
|
+
`--timeout ${0}`,
|
|
116
|
+
]
|
|
117
|
+
console.log("runViewer", execName, execPath, viewerArgs)
|
|
118
|
+
await runScript(execName, execPath, viewerArgs, "Starting factory")
|
|
119
|
+
return port
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function killHttpMicroservice(microservice) {
|
|
123
|
+
console.log("killHttpMicroservice", { ...microservice })
|
|
124
|
+
const failMessage = `Failed to kill ${microservice.name}`
|
|
125
|
+
async function do_kill() {
|
|
126
|
+
try {
|
|
127
|
+
await fetch(microservice.url, {
|
|
128
|
+
method: microservice.method,
|
|
129
|
+
})
|
|
130
|
+
throw new Error(failMessage)
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.log(`${microservice.name} closed`, error)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return pTimeout(do_kill(), {
|
|
136
|
+
milliseconds: 5000,
|
|
137
|
+
message: failMessage,
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function killWebsocketMicroservice(microservice) {
|
|
142
|
+
console.log("killWebsocketMicroservice", { ...microservice })
|
|
143
|
+
const failMessage = `Failed to kill ${microservice.name}`
|
|
144
|
+
const successMessage = `Disconnected from ${microservice.name} WebSocket server`
|
|
145
|
+
function do_kill() {
|
|
146
|
+
return new Promise((resolve) => {
|
|
147
|
+
const socket = new WebSocket(microservice.url)
|
|
148
|
+
socket.on("open", () => {
|
|
149
|
+
console.log("Connected to WebSocket server")
|
|
150
|
+
socket.send(
|
|
151
|
+
JSON.stringify({
|
|
152
|
+
id: "system:hello",
|
|
153
|
+
method: "wslink.hello",
|
|
154
|
+
args: [{ secret: "wslink-secret" }],
|
|
155
|
+
}),
|
|
156
|
+
)
|
|
157
|
+
})
|
|
158
|
+
socket.on("message", (data) => {
|
|
159
|
+
const message = data.toString()
|
|
160
|
+
console.log("Received from server:", message)
|
|
161
|
+
if (message.includes("hello")) {
|
|
162
|
+
socket.send(
|
|
163
|
+
JSON.stringify({
|
|
164
|
+
id: "application.exit",
|
|
165
|
+
method: "application.exit",
|
|
166
|
+
}),
|
|
167
|
+
)
|
|
168
|
+
console.log(successMessage)
|
|
169
|
+
socket.close()
|
|
170
|
+
resolve()
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
socket.on("close", () => {
|
|
174
|
+
console.log(successMessage)
|
|
175
|
+
resolve()
|
|
176
|
+
})
|
|
177
|
+
socket.on("error", (error) => {
|
|
178
|
+
console.error("WebSocket error:", error)
|
|
179
|
+
socket.close()
|
|
180
|
+
resolve()
|
|
181
|
+
})
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
return pTimeout(do_kill(), {
|
|
185
|
+
milliseconds: 5000,
|
|
186
|
+
message: failMessage,
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function killMicroservice(microservice) {
|
|
191
|
+
if (microservice.type === "back") {
|
|
192
|
+
return killHttpMicroservice(microservice)
|
|
193
|
+
} else if (microservice.type === "viewer") {
|
|
194
|
+
return killWebsocketMicroservice(microservice)
|
|
195
|
+
} else {
|
|
196
|
+
throw new Error(`Unknown microservice type: ${microservice.type}`)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function killMicroservices(microservices) {
|
|
201
|
+
console.log("killMicroservices", { microservices })
|
|
202
|
+
return Promise.all(
|
|
203
|
+
microservices.map(
|
|
204
|
+
async (microservice) => await killMicroservice(microservice),
|
|
205
|
+
),
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
function projectMicroservices(projectFolderPath) {
|
|
209
|
+
console.log("projectMicroservices", { projectFolderPath })
|
|
210
|
+
const filePath = microservicesMetadatasPath(projectFolderPath)
|
|
211
|
+
|
|
212
|
+
if (!fs.existsSync(filePath)) {
|
|
213
|
+
const microservicesMetadatas = { microservices: [] }
|
|
214
|
+
fs.writeFileSync(
|
|
215
|
+
filePath,
|
|
216
|
+
JSON.stringify(microservicesMetadatas, null, 2),
|
|
217
|
+
"utf-8",
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
const content = JSON.parse(fs.readFileSync(filePath, "utf-8"))
|
|
221
|
+
return content.microservices
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function cleanupBackend(projectFolderPath) {
|
|
225
|
+
const microservices = projectMicroservices(projectFolderPath)
|
|
226
|
+
await killMicroservices(microservices)
|
|
227
|
+
await deleteFolderRecursive(projectFolderPath)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function microservicesMetadatasPath(projectFolderPath) {
|
|
231
|
+
return path.join(projectFolderPath, "microservices.json")
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function addMicroserviceMetadatas(projectFolderPath, serviceObj) {
|
|
235
|
+
const microservices = projectMicroservices(projectFolderPath)
|
|
236
|
+
if (serviceObj.type === "back") {
|
|
237
|
+
const schema = back_schemas.opengeodeweb_back.kill
|
|
238
|
+
serviceObj.url = `http://localhost:${serviceObj.port}/${schema.$id}`
|
|
239
|
+
serviceObj.method = schema.methods[0]
|
|
240
|
+
} else if (serviceObj.type === "viewer") {
|
|
241
|
+
serviceObj.url = `ws://localhost:${serviceObj.port}/ws`
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
microservices.push(serviceObj)
|
|
245
|
+
fs.writeFileSync(
|
|
246
|
+
microservicesMetadatasPath(projectFolderPath),
|
|
247
|
+
JSON.stringify({ microservices }, null, 2),
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export {
|
|
252
|
+
addMicroserviceMetadatas,
|
|
253
|
+
cleanupBackend,
|
|
254
|
+
getAvailablePort,
|
|
255
|
+
killMicroservices,
|
|
256
|
+
projectMicroservices,
|
|
257
|
+
runBack,
|
|
258
|
+
runViewer,
|
|
259
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Node imports
|
|
2
|
+
import fs from "node:fs"
|
|
3
|
+
import os from "node:os"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
import { setTimeout } from "node:timers/promises"
|
|
6
|
+
|
|
7
|
+
// Third party imports
|
|
8
|
+
import isElectron from "is-electron"
|
|
9
|
+
import { rimraf } from "rimraf"
|
|
10
|
+
import { v4 as uuidv4 } from "uuid"
|
|
11
|
+
|
|
12
|
+
const MAX_DELETE_FOLDER_RETRIES = 5
|
|
13
|
+
|
|
14
|
+
function venvScriptPath(microservicePath) {
|
|
15
|
+
const venvPath = path.join(microservicePath, "venv")
|
|
16
|
+
let scriptPath = ""
|
|
17
|
+
if (process.platform === "win32") {
|
|
18
|
+
scriptPath = path.join(venvPath, "Scripts")
|
|
19
|
+
} else {
|
|
20
|
+
scriptPath = path.join(venvPath, "bin")
|
|
21
|
+
}
|
|
22
|
+
return scriptPath
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function executablePath(microservicePath) {
|
|
26
|
+
if (isElectron()) {
|
|
27
|
+
const electron = await import("electron")
|
|
28
|
+
if (electron.app.isPackaged) {
|
|
29
|
+
return process.resourcesPath
|
|
30
|
+
} else {
|
|
31
|
+
return venvScriptPath(microservicePath)
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
return venvScriptPath(microservicePath)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function executableName(name) {
|
|
39
|
+
if (process.platform === "win32") {
|
|
40
|
+
return `${name}.exe`
|
|
41
|
+
}
|
|
42
|
+
return name
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function createPath(dirPath) {
|
|
46
|
+
if (!fs.existsSync(dirPath)) {
|
|
47
|
+
fs.mkdirSync(dirPath, { recursive: true })
|
|
48
|
+
console.log(`${dirPath} directory created successfully!`)
|
|
49
|
+
}
|
|
50
|
+
return dirPath
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function generateProjectFolderPath(projectName) {
|
|
54
|
+
return path.join(os.tmpdir(), projectName.replace(/\//g, "_"), uuidv4())
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function deleteFolderRecursive(folderPath) {
|
|
58
|
+
if (!fs.existsSync(folderPath)) {
|
|
59
|
+
console.log(`Folder ${folderPath} does not exist.`)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
for (let i = 0; i <= MAX_DELETE_FOLDER_RETRIES; i += 1) {
|
|
63
|
+
try {
|
|
64
|
+
console.log(`Deleting folder: ${folderPath}`)
|
|
65
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
66
|
+
await rimraf(folderPath)
|
|
67
|
+
console.log(`Deleted folder: ${folderPath}`)
|
|
68
|
+
return
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(`Error deleting folder ${folderPath}:`, error)
|
|
71
|
+
// Wait before retrying
|
|
72
|
+
const MILLISECONDS_PER_RETRY = 1000
|
|
73
|
+
const DELAY = MILLISECONDS_PER_RETRY * (i + 1)
|
|
74
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
75
|
+
await setTimeout(DELAY)
|
|
76
|
+
console.log("Retrying delete folder")
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
createPath,
|
|
82
|
+
executablePath,
|
|
83
|
+
executableName,
|
|
84
|
+
deleteFolderRecursive,
|
|
85
|
+
generateProjectFolderPath,
|
|
86
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Node imports
|
|
2
|
+
import { on } from "node:events"
|
|
3
|
+
import child_process from "node:child_process"
|
|
4
|
+
import fs from "node:fs"
|
|
5
|
+
import path from "node:path"
|
|
6
|
+
|
|
7
|
+
function commandExistsSync(execName) {
|
|
8
|
+
const envPath = process.env.PATH || ""
|
|
9
|
+
return envPath.split(path.delimiter).some((dir) => {
|
|
10
|
+
const filePath = path.join(dir, execName)
|
|
11
|
+
return fs.existsSync(filePath) && fs.statSync(filePath).isFile()
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function waitForReady(child, expectedResponse) {
|
|
16
|
+
for await (const [data] of on(child.stdout, "data")) {
|
|
17
|
+
if (data.toString().includes(expectedResponse)) {
|
|
18
|
+
return child
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
throw new Error("Process closed before signal")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function waitNuxt(nuxtProcess) {
|
|
25
|
+
for await (const [data] of on(nuxtProcess.stdout, "data")) {
|
|
26
|
+
const output = data.toString()
|
|
27
|
+
console.log("Nuxt:", output)
|
|
28
|
+
const portMatch = output.match(/Listening on http:\/\/\[::\]:(\d+)/)
|
|
29
|
+
if (portMatch) {
|
|
30
|
+
const [, nuxtPort] = portMatch
|
|
31
|
+
|
|
32
|
+
console.log("Nuxt listening on port", nuxtPort)
|
|
33
|
+
return nuxtPort
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw new Error("Nuxt process closed without accepting connections")
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function runBrowser(scriptName) {
|
|
40
|
+
process.env.BROWSER = true
|
|
41
|
+
|
|
42
|
+
const nuxtProcess = child_process.spawn("npm", ["run", scriptName], {
|
|
43
|
+
shell: true,
|
|
44
|
+
FORCE_COLOR: true,
|
|
45
|
+
})
|
|
46
|
+
return await waitNuxt(nuxtProcess)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { runBrowser, waitForReady, commandExistsSync }
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Node imports
|
|
2
|
+
import fs from "node:fs"
|
|
3
|
+
import path from "node:path"
|
|
4
|
+
|
|
5
|
+
// Third party imports
|
|
6
|
+
import JSZip from "jszip"
|
|
7
|
+
|
|
8
|
+
async function unzipFile(
|
|
9
|
+
zipFilePath,
|
|
10
|
+
outputDir = zipFilePath.replace(/\.[^/.]+$/, ""), // Remove the file extension
|
|
11
|
+
) {
|
|
12
|
+
console.log("Unzipping file...", zipFilePath, outputDir)
|
|
13
|
+
try {
|
|
14
|
+
const data = await fs.promises.readFile(zipFilePath)
|
|
15
|
+
const zip = await JSZip.loadAsync(data)
|
|
16
|
+
await fs.promises.mkdir(outputDir, { recursive: true })
|
|
17
|
+
const promises = []
|
|
18
|
+
|
|
19
|
+
zip.forEach((relativePath, zipEntry) => {
|
|
20
|
+
const outputPath = path.join(outputDir, relativePath)
|
|
21
|
+
|
|
22
|
+
if (zipEntry.dir) {
|
|
23
|
+
promises.push(fs.promises.mkdir(outputPath, { recursive: true }))
|
|
24
|
+
} else {
|
|
25
|
+
promises.push(
|
|
26
|
+
zipEntry.async("nodebuffer").then(async (content) => {
|
|
27
|
+
await fs.promises.mkdir(path.dirname(outputPath), {
|
|
28
|
+
recursive: true,
|
|
29
|
+
})
|
|
30
|
+
await fs.promises.writeFile(outputPath, content)
|
|
31
|
+
}),
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
await Promise.all(promises)
|
|
37
|
+
console.log("Extraction complete!")
|
|
38
|
+
return outputDir
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error("Error unzipping file:", error)
|
|
41
|
+
throw error
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { unzipFile }
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { useFeedbackStore } from "@ogw_front/stores/feedback"
|
|
2
|
-
import { useGeodeStore } from "@ogw_front/stores/geode"
|
|
1
|
+
import { useFeedbackStore } from "@ogw_front/stores/feedback.js"
|
|
3
2
|
|
|
4
3
|
async function upload_file(
|
|
4
|
+
microservice,
|
|
5
5
|
{ route, file },
|
|
6
6
|
{ request_error_function, response_function, response_error_function } = {},
|
|
7
7
|
) {
|
|
8
|
+
console.log("[UPLOAD_FILE] Uploading file", { route, file })
|
|
8
9
|
const feedbackStore = useFeedbackStore()
|
|
9
|
-
const geodeStore = useGeodeStore()
|
|
10
10
|
if (!(file instanceof File)) {
|
|
11
11
|
throw new Error("file must be a instance of File")
|
|
12
12
|
}
|
|
@@ -18,12 +18,12 @@ async function upload_file(
|
|
|
18
18
|
method: "PUT",
|
|
19
19
|
body: body,
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
microservice.start_request()
|
|
22
22
|
return $fetch(route, {
|
|
23
|
-
baseURL:
|
|
23
|
+
baseURL: microservice.base_url || "",
|
|
24
24
|
...request_options,
|
|
25
25
|
onRequestError({ error }) {
|
|
26
|
-
|
|
26
|
+
microservice.stop_request()
|
|
27
27
|
feedbackStore.add_error(error.code, route, error.message, error.stack)
|
|
28
28
|
if (request_error_function) {
|
|
29
29
|
request_error_function(error)
|
|
@@ -31,14 +31,14 @@ async function upload_file(
|
|
|
31
31
|
},
|
|
32
32
|
onResponse({ response }) {
|
|
33
33
|
if (response.ok) {
|
|
34
|
-
|
|
34
|
+
microservice.stop_request()
|
|
35
35
|
if (response_function) {
|
|
36
36
|
response_function(response)
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
onResponseError({ response }) {
|
|
41
|
-
|
|
41
|
+
microservice.stop_request()
|
|
42
42
|
feedbackStore.add_error(
|
|
43
43
|
response.status,
|
|
44
44
|
route,
|
package/nuxt.config.js
CHANGED
|
@@ -1,18 +1,36 @@
|
|
|
1
|
+
// Node imports
|
|
1
2
|
import path, { dirname } from "node:path"
|
|
2
3
|
import { fileURLToPath } from "node:url"
|
|
3
4
|
|
|
5
|
+
// Local imports
|
|
6
|
+
import package_json from "./package.json"
|
|
7
|
+
|
|
4
8
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
5
9
|
|
|
6
10
|
export default defineNuxtConfig({
|
|
7
11
|
runtimeConfig: {
|
|
8
12
|
public: {
|
|
9
13
|
API_URL: "api.geode-solutions.com",
|
|
14
|
+
BACK_COMMAND: "opengeodeweb-back",
|
|
15
|
+
BACK_PATH: path.join(
|
|
16
|
+
__dirname,
|
|
17
|
+
"tests",
|
|
18
|
+
"integration",
|
|
19
|
+
"microservices",
|
|
20
|
+
"back",
|
|
21
|
+
),
|
|
22
|
+
BROWSER: process.env.BROWSER ?? false,
|
|
23
|
+
PROJECT: package_json.name,
|
|
10
24
|
SITE_BRANCH:
|
|
11
25
|
process.env.NODE_ENV === "production" ? process.env.SITE_BRANCH : "",
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
VIEWER_COMMAND: "opengeodeweb-viewer",
|
|
27
|
+
VIEWER_PATH: path.join(
|
|
28
|
+
__dirname,
|
|
29
|
+
"tests",
|
|
30
|
+
"integration",
|
|
31
|
+
"microservices",
|
|
32
|
+
"viewer",
|
|
33
|
+
),
|
|
16
34
|
},
|
|
17
35
|
},
|
|
18
36
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geode/opengeodeweb-front",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.6.0",
|
|
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": {
|
|
@@ -41,15 +41,20 @@
|
|
|
41
41
|
"@vueuse/nuxt": "13.1.0",
|
|
42
42
|
"@vueuse/rxjs": "^14.1.0",
|
|
43
43
|
"ajv": "8.17.1",
|
|
44
|
+
"busboy": "1.6.0",
|
|
45
|
+
"conf": "15.1.0",
|
|
44
46
|
"dexie": "4.2.1",
|
|
45
47
|
"get-port-please": "3.2.0",
|
|
46
48
|
"is-electron": "2.2.2",
|
|
47
49
|
"js-file-download": "0.4.12",
|
|
50
|
+
"jszip": "3.10.1",
|
|
51
|
+
"node-stream-zip": "1.15.0",
|
|
48
52
|
"nuxt": "4.2.2",
|
|
49
53
|
"p-timeout": "7.0.1",
|
|
50
54
|
"pinia": "3.0.4",
|
|
51
55
|
"rimraf": "6.1.3",
|
|
52
56
|
"rxjs": "7.8.2",
|
|
57
|
+
"sanitize-filename": "1.6.3",
|
|
53
58
|
"sass": "1.87.0",
|
|
54
59
|
"semver": "7.7.1",
|
|
55
60
|
"uuid": "11.1.0",
|
|
@@ -62,7 +67,7 @@
|
|
|
62
67
|
"devDependencies": {
|
|
63
68
|
"@nuxt/test-utils": "3.21.0",
|
|
64
69
|
"@pinia/testing": "1.0.3",
|
|
65
|
-
"@vitejs/plugin-vue": "
|
|
70
|
+
"@vitejs/plugin-vue": "6.0.4",
|
|
66
71
|
"@vue/test-utils": "2.4.6",
|
|
67
72
|
"eslint": "9.26.0",
|
|
68
73
|
"eslint-plugin-import": "2.31.0",
|
|
@@ -77,11 +82,11 @@
|
|
|
77
82
|
"prettier": "3.3.3",
|
|
78
83
|
"resize-observer-polyfill": "1.5.1",
|
|
79
84
|
"unplugin-auto-import": "20.0.0",
|
|
80
|
-
"vite": "
|
|
85
|
+
"vite": "7.3.1",
|
|
81
86
|
"vite-plugin-vuetify": "2.1.1",
|
|
82
87
|
"vitest": "4.0.15",
|
|
83
88
|
"vitest-environment-nuxt": "1.0.1",
|
|
84
|
-
"vitest-indexeddb": "
|
|
89
|
+
"vitest-indexeddb": "0.0.1"
|
|
85
90
|
},
|
|
86
91
|
"peerDependencies": {
|
|
87
92
|
"electron": "36.4.0"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Node imports
|
|
2
|
+
|
|
3
|
+
// Third party imports
|
|
4
|
+
import { createError, defineEventHandler, readBody } from "h3"
|
|
5
|
+
|
|
6
|
+
// Local imports
|
|
7
|
+
import {
|
|
8
|
+
createPath,
|
|
9
|
+
generateProjectFolderPath,
|
|
10
|
+
} from "@geode/opengeodeweb-front/app/utils/local/path.js"
|
|
11
|
+
|
|
12
|
+
export default defineEventHandler(async (event) => {
|
|
13
|
+
try {
|
|
14
|
+
const { PROJECT } = await readBody(event)
|
|
15
|
+
const projectFolderPath = generateProjectFolderPath(PROJECT)
|
|
16
|
+
await createPath(projectFolderPath)
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
statusCode: 200,
|
|
20
|
+
projectFolderPath,
|
|
21
|
+
}
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.log(error)
|
|
24
|
+
throw createError({
|
|
25
|
+
statusCode: 500,
|
|
26
|
+
statusMessage: error.message,
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Node imports
|
|
2
|
+
|
|
3
|
+
// Third party imports
|
|
4
|
+
import { createError, defineEventHandler, readBody } from "h3"
|
|
5
|
+
|
|
6
|
+
// Local imports
|
|
7
|
+
import {
|
|
8
|
+
addMicroserviceMetadatas,
|
|
9
|
+
runBack,
|
|
10
|
+
} from "@geode/opengeodeweb-front/app/utils/local/microservices.js"
|
|
11
|
+
|
|
12
|
+
export default defineEventHandler(async (event) => {
|
|
13
|
+
try {
|
|
14
|
+
const { BACK_COMMAND, BACK_PATH, args } = await readBody(event)
|
|
15
|
+
const port = await runBack(BACK_COMMAND, BACK_PATH, args)
|
|
16
|
+
await addMicroserviceMetadatas(args.projectFolderPath, {
|
|
17
|
+
type: "back",
|
|
18
|
+
name: BACK_COMMAND,
|
|
19
|
+
port,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
statusCode: 200,
|
|
24
|
+
port,
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.log(error)
|
|
28
|
+
throw createError({
|
|
29
|
+
statusCode: 500,
|
|
30
|
+
statusMessage: error.message,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Node imports
|
|
2
|
+
|
|
3
|
+
// Third party imports
|
|
4
|
+
import { createError, defineEventHandler, readBody } from "h3"
|
|
5
|
+
|
|
6
|
+
// Local imports
|
|
7
|
+
import {
|
|
8
|
+
addMicroserviceMetadatas,
|
|
9
|
+
runViewer,
|
|
10
|
+
} from "@geode/opengeodeweb-front/app/utils/local/microservices.js"
|
|
11
|
+
|
|
12
|
+
export default defineEventHandler(async (event) => {
|
|
13
|
+
try {
|
|
14
|
+
const { VIEWER_COMMAND, VIEWER_PATH, args } = await readBody(event)
|
|
15
|
+
const port = await runViewer(VIEWER_COMMAND, VIEWER_PATH, args)
|
|
16
|
+
await addMicroserviceMetadatas(args.projectFolderPath, {
|
|
17
|
+
type: "viewer",
|
|
18
|
+
name: VIEWER_COMMAND,
|
|
19
|
+
port,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
statusCode: 200,
|
|
24
|
+
port,
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.log(error)
|
|
28
|
+
throw createError({
|
|
29
|
+
statusCode: 500,
|
|
30
|
+
statusMessage: error.message,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
})
|