@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.
@@ -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"
@@ -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
- const emptyRef = ref({})
22
- emptyRef.fetch = async () => ({})
23
- return emptyRef
20
+ return ref({})
24
21
  }
25
- if (itemCache.has(id)) {
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
- const observable = useObservable(
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 getAllItems().fetch()
159
+ const items = await database.data.toArray()
171
160
  return { items }
172
161
  }
173
162
 
@@ -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 dataStore.getItem(id).fetch()
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 dataStore.getItem(id).fetch()
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 item = dataStore.getItem(id)
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()
@@ -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
- try {
182
- for (let i = 0; i <= MAX_DELETE_FOLDER_RETRIES; i += 1) {
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
- const tempDb = new Database()
18
- await tempDb.open()
17
+ await this.addTables({ [tableName]: schemaDefinition })
18
+ }
19
19
 
20
- if (tempDb.tables.some((table) => table.name === tableName)) {
21
- tempDb.close()
22
- return tempDb
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
- currentStores[table.name] = [keyPath, ...indexes].join(",")
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 newDb = new ExtendedDatabase(
37
- currentVersion,
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
- return newDb
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
- const database = new Database()
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, tableName, schemaDefinition) {
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
- [tableName]: schemaDefinition,
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.3.2",
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": "latest",
18
- "@geode/opengeodeweb-viewer": "latest",
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",