@geode/opengeodeweb-front 10.3.2 → 10.4.0-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/DeleteDialog.vue +122 -0
- package/app/components/GlassCard.vue +1 -2
- package/app/components/SearchBar.vue +34 -0
- package/app/components/Stepper.vue +2 -2
- package/app/stores/data.js +4 -15
- package/app/stores/data_style.js +3 -2
- package/app/stores/hybrid_viewer.js +2 -2
- package/app/utils/local.js +9 -5
- package/internal/database/database.js +38 -15
- package/internal/database/extended_database.js +2 -2
- package/package.json +3 -3
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import GlassCard from "./GlassCard.vue"
|
|
3
|
+
|
|
4
|
+
const { show, item, selectedCount } = defineProps({
|
|
5
|
+
show: {
|
|
6
|
+
type: Boolean,
|
|
7
|
+
default: false,
|
|
8
|
+
},
|
|
9
|
+
item: {
|
|
10
|
+
type: Object,
|
|
11
|
+
default: null,
|
|
12
|
+
},
|
|
13
|
+
selectedCount: {
|
|
14
|
+
type: Number,
|
|
15
|
+
default: 0,
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const emit = defineEmits(["update:show", "confirm"])
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<v-dialog
|
|
24
|
+
:model-value="show"
|
|
25
|
+
@update:model-value="emit('update:show', $event)"
|
|
26
|
+
max-width="400"
|
|
27
|
+
>
|
|
28
|
+
<GlassCard v-if="item" variant="panel" padding="pa-8">
|
|
29
|
+
<v-card-title
|
|
30
|
+
class="pb-2 text-h5 font-weight-bold d-flex align-center text-white"
|
|
31
|
+
>
|
|
32
|
+
<v-icon
|
|
33
|
+
icon="mdi-trash-can-outline"
|
|
34
|
+
class="mr-3 text-h4"
|
|
35
|
+
color="error"
|
|
36
|
+
></v-icon>
|
|
37
|
+
Delete Item
|
|
38
|
+
</v-card-title>
|
|
39
|
+
|
|
40
|
+
<v-card-text class="pa-0 mt-4 text-white opacity-80">
|
|
41
|
+
Are you sure you want to delete this item?
|
|
42
|
+
<div
|
|
43
|
+
class="bg-white-opacity-5 rounded-lg pa-4 my-6 font-weight-bold border-thin text-center"
|
|
44
|
+
>
|
|
45
|
+
{{ item.name }}
|
|
46
|
+
</div>
|
|
47
|
+
</v-card-text>
|
|
48
|
+
|
|
49
|
+
<v-card-actions class="px-0 pb-0">
|
|
50
|
+
<v-btn
|
|
51
|
+
variant="text"
|
|
52
|
+
color="white"
|
|
53
|
+
size="large"
|
|
54
|
+
@click="emit('update:show', false)"
|
|
55
|
+
class="text-none rounded-lg"
|
|
56
|
+
>
|
|
57
|
+
<v-icon start>mdi-close-circle-outline</v-icon>
|
|
58
|
+
Cancel
|
|
59
|
+
</v-btn>
|
|
60
|
+
|
|
61
|
+
<v-spacer />
|
|
62
|
+
|
|
63
|
+
<v-btn
|
|
64
|
+
color="error"
|
|
65
|
+
size="large"
|
|
66
|
+
variant="flat"
|
|
67
|
+
@click="emit('confirm')"
|
|
68
|
+
class="text-none rounded-lg font-weight-bold"
|
|
69
|
+
elevation="4"
|
|
70
|
+
>
|
|
71
|
+
<v-icon start>mdi-trash-can-outline</v-icon>
|
|
72
|
+
Delete
|
|
73
|
+
</v-btn>
|
|
74
|
+
</v-card-actions>
|
|
75
|
+
</GlassCard>
|
|
76
|
+
|
|
77
|
+
<GlassCard v-else variant="panel" padding="pa-8">
|
|
78
|
+
<v-card-title
|
|
79
|
+
class="pb-2 text-h5 font-weight-bold d-flex align-center text-white"
|
|
80
|
+
>
|
|
81
|
+
<v-icon
|
|
82
|
+
icon="mdi-alert-circle-outline"
|
|
83
|
+
class="mr-3 text-h4"
|
|
84
|
+
color="error"
|
|
85
|
+
></v-icon>
|
|
86
|
+
Delete Items
|
|
87
|
+
</v-card-title>
|
|
88
|
+
|
|
89
|
+
<v-card-text class="pa-0 mt-4 text-white opacity-80">
|
|
90
|
+
Are you sure you want to delete
|
|
91
|
+
<strong class="text-white">{{ selectedCount }}</strong> items?
|
|
92
|
+
</v-card-text>
|
|
93
|
+
|
|
94
|
+
<v-card-actions class="px-0 pb-0 mt-8">
|
|
95
|
+
<v-btn
|
|
96
|
+
variant="text"
|
|
97
|
+
color="white"
|
|
98
|
+
size="large"
|
|
99
|
+
@click="emit('update:show', false)"
|
|
100
|
+
class="text-none rounded-lg"
|
|
101
|
+
>
|
|
102
|
+
<v-icon start>mdi-close-circle-outline</v-icon>
|
|
103
|
+
Cancel
|
|
104
|
+
</v-btn>
|
|
105
|
+
|
|
106
|
+
<v-spacer />
|
|
107
|
+
|
|
108
|
+
<v-btn
|
|
109
|
+
color="error"
|
|
110
|
+
size="large"
|
|
111
|
+
variant="flat"
|
|
112
|
+
@click="emit('confirm')"
|
|
113
|
+
class="text-none rounded-lg font-weight-bold"
|
|
114
|
+
elevation="4"
|
|
115
|
+
>
|
|
116
|
+
<v-icon start>mdi-trash-can-outline</v-icon>
|
|
117
|
+
Delete All
|
|
118
|
+
</v-btn>
|
|
119
|
+
</v-card-actions>
|
|
120
|
+
</GlassCard>
|
|
121
|
+
</v-dialog>
|
|
122
|
+
</template>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { computed, useAttrs } from "vue"
|
|
2
3
|
defineProps({
|
|
3
4
|
variant: {
|
|
4
5
|
type: String,
|
|
@@ -16,11 +17,9 @@
|
|
|
16
17
|
|
|
17
18
|
<template>
|
|
18
19
|
<v-card
|
|
19
|
-
v-bind="$attrs"
|
|
20
20
|
@mousedown.stop
|
|
21
21
|
@click.stop
|
|
22
22
|
@dblclick.stop
|
|
23
|
-
@wheel.stop
|
|
24
23
|
@contextmenu.stop
|
|
25
24
|
flat
|
|
26
25
|
:ripple="isInteractive"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-text-field
|
|
3
|
+
:model-value="modelValue"
|
|
4
|
+
@update:model-value="$emit('update:modelValue', $event)"
|
|
5
|
+
prepend-inner-icon="mdi-magnify"
|
|
6
|
+
:label="label"
|
|
7
|
+
variant="outlined"
|
|
8
|
+
density="compact"
|
|
9
|
+
hide-details
|
|
10
|
+
bg-color="transparent"
|
|
11
|
+
color="white"
|
|
12
|
+
base-color="white"
|
|
13
|
+
v-bind="$attrs"
|
|
14
|
+
>
|
|
15
|
+
<template v-for="(_, slot) in $slots" v-slot:[slot]="scope">
|
|
16
|
+
<slot :name="slot" v-bind="scope || {}"></slot>
|
|
17
|
+
</template>
|
|
18
|
+
</v-text-field>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup>
|
|
22
|
+
defineProps({
|
|
23
|
+
modelValue: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: "",
|
|
26
|
+
},
|
|
27
|
+
label: {
|
|
28
|
+
type: String,
|
|
29
|
+
default: "Search...",
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
defineEmits(["update:modelValue"])
|
|
34
|
+
</script>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import Step from "@ogw_front/components/Step"
|
|
3
3
|
|
|
4
|
-
const emit = defineEmits(["reset_values"])
|
|
4
|
+
const emit = defineEmits(["reset_values", "close"])
|
|
5
5
|
const stepper_tree = inject("stepper_tree")
|
|
6
6
|
const { steps, current_step_index } = toRefs(stepper_tree)
|
|
7
7
|
</script>
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
@update:model-value="current_step_index = $event - 1"
|
|
29
29
|
flat
|
|
30
30
|
non-linear
|
|
31
|
-
class="pa-0 ma-0 bg-transparent rounded-xl overflow-hidden custom-stepper"
|
|
31
|
+
class="pa-0 ma-0 bg-transparent rounded-xl overflow-hidden custom-stepper flex-grow-1"
|
|
32
32
|
>
|
|
33
33
|
<Step
|
|
34
34
|
v-for="(step, index) in steps"
|
package/app/stores/data.js
CHANGED
|
@@ -15,32 +15,21 @@ const viewer_generic_schemas = viewer_schemas.opengeodeweb_viewer.generic
|
|
|
15
15
|
export const useDataStore = defineStore("data", () => {
|
|
16
16
|
const viewerStore = useViewerStore()
|
|
17
17
|
|
|
18
|
-
const itemCache = new Map()
|
|
19
18
|
function getItem(id) {
|
|
20
19
|
if (!id) {
|
|
21
|
-
|
|
22
|
-
emptyRef.fetch = async () => ({})
|
|
23
|
-
return emptyRef
|
|
20
|
+
return ref({})
|
|
24
21
|
}
|
|
25
|
-
|
|
26
|
-
return itemCache.get(id)
|
|
27
|
-
}
|
|
28
|
-
const observable = useObservable(
|
|
22
|
+
return useObservable(
|
|
29
23
|
liveQuery(() => database.data.get(id)),
|
|
30
24
|
{ initialValue: {} },
|
|
31
25
|
)
|
|
32
|
-
observable.fetch = () => database.data.get(id)
|
|
33
|
-
itemCache.set(id, observable)
|
|
34
|
-
return observable
|
|
35
26
|
}
|
|
36
27
|
|
|
37
28
|
function getAllItems() {
|
|
38
|
-
|
|
29
|
+
return useObservable(
|
|
39
30
|
liveQuery(() => database.data.toArray()),
|
|
40
31
|
{ initialValue: [] },
|
|
41
32
|
)
|
|
42
|
-
observable.fetch = () => database.data.toArray()
|
|
43
|
-
return observable
|
|
44
33
|
}
|
|
45
34
|
|
|
46
35
|
async function formatedMeshComponents(id) {
|
|
@@ -167,7 +156,7 @@ export const useDataStore = defineStore("data", () => {
|
|
|
167
156
|
}
|
|
168
157
|
|
|
169
158
|
async function exportStores() {
|
|
170
|
-
const items = await
|
|
159
|
+
const items = await database.data.toArray()
|
|
171
160
|
return { items }
|
|
172
161
|
}
|
|
173
162
|
|
package/app/stores/data_style.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getDefaultStyle } from "@ogw_front/utils/default_styles"
|
|
2
|
+
import { database } from "../../internal/database/database.js"
|
|
2
3
|
import { useDataStore } from "@ogw_front/stores/data"
|
|
3
4
|
import { useDataStyleStateStore } from "../../internal/stores/data_style/state"
|
|
4
5
|
import useMeshStyle from "../../internal/stores/data_style/mesh/index"
|
|
@@ -15,7 +16,7 @@ export const useDataStyleStore = defineStore("dataStyle", () => {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
async function setVisibility(id, visibility) {
|
|
18
|
-
const item = await
|
|
19
|
+
const item = await database.data.get(id)
|
|
19
20
|
const viewer_type = item?.viewer_type
|
|
20
21
|
if (!viewer_type) {
|
|
21
22
|
throw new Error(`Item not found or not loaded: ${id}`)
|
|
@@ -31,7 +32,7 @@ export const useDataStyleStore = defineStore("dataStyle", () => {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
async function applyDefaultStyle(id) {
|
|
34
|
-
const item = await
|
|
35
|
+
const item = await database.data.get(id)
|
|
35
36
|
const viewer_type = item?.viewer_type
|
|
36
37
|
if (!viewer_type) {
|
|
37
38
|
throw new Error(`Item not found or not loaded: ${id}`)
|
|
@@ -6,6 +6,7 @@ import { newInstance as vtkMapper } from "@kitware/vtk.js/Rendering/Core/Mapper"
|
|
|
6
6
|
import { newInstance as vtkXMLPolyDataReader } from "@kitware/vtk.js/IO/XML/XMLPolyDataReader"
|
|
7
7
|
|
|
8
8
|
import Status from "@ogw_front/utils/status"
|
|
9
|
+
import { database } from "../../internal/database/database.js"
|
|
9
10
|
import { useDataStore } from "@ogw_front/stores/data"
|
|
10
11
|
import { useViewerStore } from "@ogw_front/stores/viewer"
|
|
11
12
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json"
|
|
@@ -73,8 +74,7 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
73
74
|
if (!genericRenderWindow.value) {
|
|
74
75
|
return
|
|
75
76
|
}
|
|
76
|
-
const
|
|
77
|
-
const value = await item.fetch()
|
|
77
|
+
const value = await database.data.get(id)
|
|
78
78
|
console.log("hybridViewerStore.addItem", { value })
|
|
79
79
|
const reader = vtkXMLPolyDataReader()
|
|
80
80
|
const textEncoder = new TextEncoder()
|
package/app/utils/local.js
CHANGED
|
@@ -2,6 +2,7 @@ import { on, once } from "node:events"
|
|
|
2
2
|
import child_process from "node:child_process"
|
|
3
3
|
import fs from "node:fs"
|
|
4
4
|
import path from "node:path"
|
|
5
|
+
import { setTimeout } from "timers/promises"
|
|
5
6
|
|
|
6
7
|
// Third party imports
|
|
7
8
|
import { WebSocket } from "ws"
|
|
@@ -173,20 +174,23 @@ async function run_viewer(executable_name, executable_path, args = {}) {
|
|
|
173
174
|
return port
|
|
174
175
|
}
|
|
175
176
|
|
|
176
|
-
function delete_folder_recursive(data_folder_path) {
|
|
177
|
+
async function delete_folder_recursive(data_folder_path) {
|
|
177
178
|
if (!fs.existsSync(data_folder_path)) {
|
|
178
179
|
console.log(`Folder ${data_folder_path} does not exist.`)
|
|
179
180
|
return
|
|
180
181
|
}
|
|
181
|
-
|
|
182
|
-
|
|
182
|
+
for (let i = 0; i <= MAX_DELETE_FOLDER_RETRIES; i += 1) {
|
|
183
|
+
try {
|
|
183
184
|
console.log(`Deleting folder: ${data_folder_path}`)
|
|
184
185
|
fs.rmSync(data_folder_path, { recursive: true, force: true })
|
|
185
186
|
console.log(`Deleted folder: ${data_folder_path}`)
|
|
186
187
|
return
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error(`Error deleting folder ${data_folder_path}:`, error)
|
|
190
|
+
// Wait before retrying
|
|
191
|
+
const DELAY = 1000 * (i + 1)
|
|
192
|
+
await setTimeout(DELAY)
|
|
187
193
|
}
|
|
188
|
-
} catch (error) {
|
|
189
|
-
console.error(`Error deleting folder ${data_folder_path}:`, error)
|
|
190
194
|
}
|
|
191
195
|
}
|
|
192
196
|
|
|
@@ -14,37 +14,60 @@ class Database extends Dexie {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
static async addTable(tableName, schemaDefinition) {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
await this.addTables({ [tableName]: schemaDefinition })
|
|
18
|
+
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
20
|
+
static async addTables(newTables) {
|
|
21
|
+
const tempDb = new Dexie("Database")
|
|
22
|
+
await tempDb.open()
|
|
24
23
|
|
|
25
24
|
const currentVersion = tempDb.verno
|
|
26
25
|
const currentStores = {}
|
|
27
26
|
|
|
27
|
+
currentStores[dataTable.name] = dataTable.schema
|
|
28
|
+
currentStores[modelComponentsTable.name] = modelComponentsTable.schema
|
|
29
|
+
|
|
28
30
|
for (const table of tempDb.tables) {
|
|
29
31
|
const keyPath = table.schema.primKey.src
|
|
30
32
|
const indexes = table.schema.indexes.map((index) => index.src)
|
|
31
|
-
|
|
33
|
+
const parts = keyPath ? [keyPath, ...indexes] : indexes
|
|
34
|
+
currentStores[table.name] = parts.join(",")
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
tempDb.close()
|
|
35
38
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
currentStores,
|
|
39
|
-
tableName,
|
|
40
|
-
schemaDefinition,
|
|
39
|
+
const allExisting = Object.keys(newTables).every(
|
|
40
|
+
(tableName) => currentStores[tableName],
|
|
41
41
|
)
|
|
42
|
-
await newDb.open()
|
|
43
42
|
|
|
44
|
-
|
|
43
|
+
database.close()
|
|
44
|
+
|
|
45
|
+
if (allExisting) {
|
|
46
|
+
const existingDb = new Dexie("Database")
|
|
47
|
+
for (let version = 1; version <= currentVersion; version += 1) {
|
|
48
|
+
if (version === 1) {
|
|
49
|
+
existingDb.version(1).stores({
|
|
50
|
+
[dataTable.name]: dataTable.schema,
|
|
51
|
+
[modelComponentsTable.name]: modelComponentsTable.schema,
|
|
52
|
+
})
|
|
53
|
+
} else {
|
|
54
|
+
existingDb.version(version).stores(currentStores)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
await existingDb.open()
|
|
58
|
+
database = existingDb
|
|
59
|
+
} else {
|
|
60
|
+
const newDb = new ExtendedDatabase(
|
|
61
|
+
currentVersion,
|
|
62
|
+
currentStores,
|
|
63
|
+
newTables,
|
|
64
|
+
)
|
|
65
|
+
await newDb.open()
|
|
66
|
+
database = newDb
|
|
67
|
+
}
|
|
45
68
|
}
|
|
46
69
|
}
|
|
47
70
|
|
|
48
|
-
|
|
71
|
+
let database = new Database()
|
|
49
72
|
|
|
50
73
|
export { Database, database }
|
|
@@ -3,7 +3,7 @@ import { dataTable } from "./tables/data_table"
|
|
|
3
3
|
import { modelComponentsTable } from "./tables/model_components"
|
|
4
4
|
|
|
5
5
|
export class ExtendedDatabase extends Dexie {
|
|
6
|
-
constructor(currentVersion, currentStores,
|
|
6
|
+
constructor(currentVersion, currentStores, newTables) {
|
|
7
7
|
super("Database")
|
|
8
8
|
|
|
9
9
|
for (let version = 1; version <= currentVersion; version += 1) {
|
|
@@ -19,7 +19,7 @@ export class ExtendedDatabase extends Dexie {
|
|
|
19
19
|
|
|
20
20
|
this.version(currentVersion + 1).stores({
|
|
21
21
|
...currentStores,
|
|
22
|
-
|
|
22
|
+
...newTables,
|
|
23
23
|
})
|
|
24
24
|
}
|
|
25
25
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@geode/opengeodeweb-front",
|
|
3
3
|
"description": "OpenSource Vue/Nuxt/Pinia/Vuetify framework for web applications",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "10.
|
|
5
|
+
"version": "10.4.0-rc.1",
|
|
6
6
|
"main": "./nuxt.config.js",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"lint": "eslint --fix --ext .js,.vue --ignore-path .gitignore .",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"build": ""
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@geode/opengeodeweb-back": "
|
|
18
|
-
"@geode/opengeodeweb-viewer": "
|
|
17
|
+
"@geode/opengeodeweb-back": "next",
|
|
18
|
+
"@geode/opengeodeweb-viewer": "next",
|
|
19
19
|
"@kitware/vtk.js": "33.3.0",
|
|
20
20
|
"@mdi/font": "7.4.47",
|
|
21
21
|
"@pinia/nuxt": "0.11.3",
|