@raclettejs/workbench 0.1.32 → 0.1.33-canary.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/.raclette/backend/raclette.config.js +2 -2
- package/.raclette/backend/yarn.lock +71 -80
- package/.raclette/frontend/raclette.config.js +2 -2
- package/.raclette/frontend/yarn.lock +517 -471
- package/.raclette/virtual/backend/raclette.config.js +2 -2
- package/.raclette/virtual/backend/yarn.lock +71 -80
- package/.raclette/virtual/frontend/raclette.config.js +2 -2
- package/.raclette/virtual/frontend/yarn.lock +517 -471
- package/CHANGELOG.md +2 -0
- package/i18n/de-DE.json +1 -10
- package/i18n/en-EU.json +1 -10
- package/i18n/sk-SK.json +1 -10
- package/package.json +5 -3
- package/plugins/pacifico__compositions/frontend/widgets/CompositionListWidget.vue +63 -107
- package/plugins/pacifico__interactionLinks/frontend/widgets/InteractionLinkListWidget.vue +64 -122
- package/plugins/pacifico__plugins/frontend/widgets/PluginListWidget.vue +2 -2
- package/plugins/pacifico__tags/frontend/widgets/TagListWidget.vue +47 -104
- package/plugins/pacifico__users/frontend/widgets/UserListWidget.vue +24 -16
- package/services/frontend/src/app/lib/jsonTools.ts +69 -3
- package/services/frontend/src/app/components/BaseDataTable.vue +0 -303
- package/services/frontend/src/app/components/FileUpload.vue +0 -98
- package/services/frontend/src/app/components/SelectionDialog.vue +0 -182
- package/services/frontend/src/app/components/SummaryDialog.vue +0 -140
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
- set eslint version to latest
|
|
11
|
+
|
|
10
12
|
## [0.1.32] - 2026-04-30 <a href="https://gitlab.com/raclettejs/core-dev/-/compare/v0.1.31...v0.1.32" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
|
|
11
13
|
|
|
12
14
|
## [0.1.31] - 2026-04-27 <a href="https://gitlab.com/raclettejs/core-dev/-/compare/v0.1.30...v0.1.31" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
|
package/i18n/de-DE.json
CHANGED
|
@@ -38,15 +38,6 @@
|
|
|
38
38
|
"continue": "Weiter"
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
-
"baseDataTable": {
|
|
42
|
-
"searchPlaceholder": "{dataName} durchsuchen",
|
|
43
|
-
"createDataButton": "{dataName} erstellen",
|
|
44
|
-
"deleteDataTitle": "{dataName} löschen",
|
|
45
|
-
"restoreDataTitle": "{dataName} widerherstellen",
|
|
46
|
-
"deleteDataConfirmMessage": "Bist du sicher, dass du {article} {dataName} <strong>{value}</strong> löschen willst?",
|
|
47
|
-
"deleteDataConfirmButton": "Löschen",
|
|
48
|
-
"deleteDataConfirmCancel": "Abbrechen"
|
|
49
|
-
},
|
|
50
41
|
"compositionList": {
|
|
51
42
|
"dataName": "Komposition",
|
|
52
43
|
"dataArticle": "die",
|
|
@@ -290,4 +281,4 @@
|
|
|
290
281
|
}
|
|
291
282
|
}
|
|
292
283
|
}
|
|
293
|
-
}
|
|
284
|
+
}
|
package/i18n/en-EU.json
CHANGED
|
@@ -38,15 +38,6 @@
|
|
|
38
38
|
"continue": "Continue"
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
-
"baseDataTable": {
|
|
42
|
-
"searchPlaceholder": "Search {dataName}",
|
|
43
|
-
"createDataButton": "Create {dataName}",
|
|
44
|
-
"deleteDataTitle": "Delete {dataName}",
|
|
45
|
-
"restoreDataTitle": "Restore {dataName}",
|
|
46
|
-
"deleteDataConfirmMessage": "Are you sure you want to delete {article} {dataName} <strong>{value}</strong>?",
|
|
47
|
-
"deleteDataConfirmButton": "Delete",
|
|
48
|
-
"deleteDataConfirmCancel": "Cancel"
|
|
49
|
-
},
|
|
50
41
|
"compositionList": {
|
|
51
42
|
"dataName": "Composition",
|
|
52
43
|
"dataArticle": "the",
|
|
@@ -290,4 +281,4 @@
|
|
|
290
281
|
}
|
|
291
282
|
}
|
|
292
283
|
}
|
|
293
|
-
}
|
|
284
|
+
}
|
package/i18n/sk-SK.json
CHANGED
|
@@ -38,15 +38,6 @@
|
|
|
38
38
|
"continue": "Pokračovať"
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
|
-
"baseDataTable": {
|
|
42
|
-
"searchPlaceholder": "Hľadať {dataName}",
|
|
43
|
-
"createDataButton": "Vytvoriť {dataName}",
|
|
44
|
-
"deleteDataTitle": "Odstrániť {dataName}",
|
|
45
|
-
"restoreDataTitle": "Obnoviť {dataName}",
|
|
46
|
-
"deleteDataConfirmMessage": "Naozaj chcete odstrániť {article} {dataName} <strong>{value}</strong>?",
|
|
47
|
-
"deleteDataConfirmButton": "Odstrániť",
|
|
48
|
-
"deleteDataConfirmCancel": "Zrušiť"
|
|
49
|
-
},
|
|
50
41
|
"compositionList": {
|
|
51
42
|
"dataName": "Kompozícia",
|
|
52
43
|
"dataArticle": "",
|
|
@@ -285,4 +276,4 @@
|
|
|
285
276
|
}
|
|
286
277
|
}
|
|
287
278
|
}
|
|
288
|
-
}
|
|
279
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raclettejs/workbench",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33-canary.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "racletteJS Workbench - used to configure your application, for dev and prod",
|
|
6
6
|
"repository": "https://gitlab.com/raclettejs/workbench",
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
"update": "raclette update",
|
|
14
14
|
"restart": "raclette restart",
|
|
15
15
|
"add-package": "raclette add-package",
|
|
16
|
+
"format:check": "prettier --check .",
|
|
17
|
+
"format:fix": "prettier --write .",
|
|
16
18
|
"lint": "eslint",
|
|
17
19
|
"lint:fix": "eslint --fix"
|
|
18
20
|
},
|
|
@@ -31,7 +33,7 @@
|
|
|
31
33
|
".": "./index.ts"
|
|
32
34
|
},
|
|
33
35
|
"dependencies": {
|
|
34
|
-
"@raclettejs/core": "^0.1.
|
|
36
|
+
"@raclettejs/core": "^0.1.33-canary.1",
|
|
35
37
|
"@vueuse/integrations": "14.2.1",
|
|
36
38
|
"fuse.js": "7.1.0",
|
|
37
39
|
"three": "0.183.2",
|
|
@@ -41,7 +43,7 @@
|
|
|
41
43
|
"@emnapi/core": "1.9.2",
|
|
42
44
|
"@emnapi/runtime": "1.9.2",
|
|
43
45
|
"@eslint/js": "9.35.0",
|
|
44
|
-
"@raclettejs/types": "^0.1.
|
|
46
|
+
"@raclettejs/types": "^0.1.33-canary.1",
|
|
45
47
|
"@sinclair/typebox": "0.34.48",
|
|
46
48
|
"@types/ramda": "0.31.1",
|
|
47
49
|
"@vueuse/core": "14.2.1",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<BaseDataTable
|
|
4
4
|
:items="parsedCompositions"
|
|
5
|
+
:exportable-items="exportableCompositions"
|
|
5
6
|
:loading="compositionsLoading || tagsLoading"
|
|
6
7
|
:headers="headers"
|
|
7
8
|
create-interaction-link-id="compositionCreateInteractionLink"
|
|
@@ -9,16 +10,17 @@
|
|
|
9
10
|
:data-name="$t('workbench.compositionList.dataName')"
|
|
10
11
|
:data-article="$t('workbench.compositionList.dataArticle')"
|
|
11
12
|
@delete="deleteComposition"
|
|
12
|
-
:
|
|
13
|
+
:items-deleted="showDeleted"
|
|
14
|
+
:on-file-loaded="handleFileUpload"
|
|
13
15
|
>
|
|
14
|
-
<template #
|
|
16
|
+
<template #toolbar-leading>
|
|
15
17
|
<v-tooltip
|
|
16
18
|
:text="showDeleted ? $t('core.hideDeleted') : $t('core.showDeleted')"
|
|
17
19
|
>
|
|
18
|
-
<template
|
|
20
|
+
<template #activator="{ props: activatorProps }">
|
|
19
21
|
<v-btn-toggle
|
|
20
22
|
density="compact"
|
|
21
|
-
v-bind="
|
|
23
|
+
v-bind="activatorProps"
|
|
22
24
|
v-model="showDeleted"
|
|
23
25
|
mandatory
|
|
24
26
|
:color="showDeleted ? 'error' : 'success'"
|
|
@@ -30,29 +32,9 @@
|
|
|
30
32
|
</v-btn-toggle>
|
|
31
33
|
</template>
|
|
32
34
|
</v-tooltip>
|
|
33
|
-
<v-btn-group density="compact">
|
|
34
|
-
<v-tooltip :text="$t('core.export')">
|
|
35
|
-
<template v-slot:activator="{ props }">
|
|
36
|
-
<v-btn color="info" v-bind="props" flat @click="openExportDialog">
|
|
37
|
-
<v-icon>mdi-database-export</v-icon>
|
|
38
|
-
</v-btn>
|
|
39
|
-
</template>
|
|
40
|
-
</v-tooltip>
|
|
41
|
-
<v-tooltip :text="$t('core.import')">
|
|
42
|
-
<template v-slot:activator="{ props }">
|
|
43
|
-
<v-btn v-bind="props" color="warning">
|
|
44
|
-
<FileUpload
|
|
45
|
-
ref="uploadRef"
|
|
46
|
-
:onFileLoaded="handleFileUpload"
|
|
47
|
-
accept=".json"
|
|
48
|
-
readAs="text"
|
|
49
|
-
/></v-btn>
|
|
50
|
-
</template>
|
|
51
|
-
</v-tooltip>
|
|
52
|
-
</v-btn-group>
|
|
53
35
|
</template>
|
|
54
36
|
<!-- Custom status column -->
|
|
55
|
-
<template #item.status="{ item }">
|
|
37
|
+
<template #[`item.status`]="{ item }">
|
|
56
38
|
<v-icon
|
|
57
39
|
:icon="item.statusIcon"
|
|
58
40
|
:color="item.statusColor"
|
|
@@ -74,18 +56,8 @@
|
|
|
74
56
|
/>
|
|
75
57
|
</template>
|
|
76
58
|
</BaseDataTable>
|
|
77
|
-
<!-- Export Selection Dialog -->
|
|
78
|
-
<SelectionDialog
|
|
79
|
-
v-model="showExportDialog"
|
|
80
|
-
:items="exportableItems"
|
|
81
|
-
display-attribute="title"
|
|
82
|
-
:title="$t('core.selectItemsToExport')"
|
|
83
|
-
:confirm-text="$t('core.export')"
|
|
84
|
-
@confirm="handleExportConfirm"
|
|
85
|
-
/>
|
|
86
|
-
|
|
87
59
|
<!-- Import Selection Dialog -->
|
|
88
|
-
<
|
|
60
|
+
<ImportSelectionDialog
|
|
89
61
|
v-model="showImportDialog"
|
|
90
62
|
:items="importableItems"
|
|
91
63
|
display-attribute="title"
|
|
@@ -94,18 +66,8 @@
|
|
|
94
66
|
@confirm="handleImportConfirm"
|
|
95
67
|
/>
|
|
96
68
|
|
|
97
|
-
<!-- Export Summary Dialog -->
|
|
98
|
-
<SummaryDialog
|
|
99
|
-
v-model="showExportSummary"
|
|
100
|
-
display-attribute="title"
|
|
101
|
-
:items="exportedItems"
|
|
102
|
-
:title="$t('core.exportSummary')"
|
|
103
|
-
:message="$t('core.exportSuccessMessage')"
|
|
104
|
-
type="success"
|
|
105
|
-
/>
|
|
106
|
-
|
|
107
69
|
<!-- Import Summary Dialog -->
|
|
108
|
-
<
|
|
70
|
+
<ImportSummaryDialog
|
|
109
71
|
v-model="showImportSummary"
|
|
110
72
|
display-attribute="title"
|
|
111
73
|
:items="importedItems"
|
|
@@ -121,31 +83,27 @@
|
|
|
121
83
|
|
|
122
84
|
<script setup lang="ts">
|
|
123
85
|
import { usePluginApi } from "@raclettejs/core/orchestrator/composables"
|
|
124
|
-
import { computed, watch, ref
|
|
86
|
+
import { computed, watch, ref } from "vue"
|
|
125
87
|
import type { Composition } from "@raclettejs/core"
|
|
126
88
|
import { formatDistance } from "date-fns"
|
|
127
|
-
import BaseDataTable from "@
|
|
89
|
+
import BaseDataTable from "@raclettejs/core/orchestrator/components/dataTable/BaseDataTable.vue"
|
|
128
90
|
import { useI18n } from "vue-i18n"
|
|
129
|
-
import {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
91
|
+
import {
|
|
92
|
+
mapJsonValues,
|
|
93
|
+
parseAndNormalizeWorkbenchImportJson,
|
|
94
|
+
resolveWorkbenchImportSelection,
|
|
95
|
+
} from "@app/lib/jsonTools"
|
|
96
|
+
import ImportSelectionDialog from "@raclettejs/core/orchestrator/components/dataImport/ImportSelectionDialog.vue"
|
|
97
|
+
import ImportSummaryDialog from "@raclettejs/core/orchestrator/components/dataImport/ImportSummaryDialog.vue"
|
|
133
98
|
|
|
134
99
|
const { t } = useI18n()
|
|
135
100
|
const showDeleted = ref(false)
|
|
136
|
-
// Dialog states
|
|
137
|
-
const showExportDialog = ref(false)
|
|
138
101
|
const showImportDialog = ref(false)
|
|
139
|
-
const showExportSummary = ref(false)
|
|
140
102
|
const showImportSummary = ref(false)
|
|
141
103
|
|
|
142
|
-
// Data for dialogs
|
|
143
|
-
const exportableItems = ref<any[]>([])
|
|
144
104
|
const importableItems = ref<any[]>([])
|
|
145
|
-
const exportedItems = ref<any[]>([])
|
|
146
105
|
const importedItems = ref<any[]>([])
|
|
147
|
-
const
|
|
148
|
-
const uploadRef = useTemplateRef("uploadRef")
|
|
106
|
+
const pendingImportById = ref<Record<string, any>>({})
|
|
149
107
|
|
|
150
108
|
const headers = computed<
|
|
151
109
|
{ title: string; key: keyof Composition | "actions" }[]
|
|
@@ -204,25 +162,39 @@ const { execute: executeRestore } = await $data.composition.updateRestore({
|
|
|
204
162
|
const { execute: executeHardDelete } = await $data.composition.deleteHard({
|
|
205
163
|
options: { cb: () => execute({ isDeleted: showDeleted.value }) },
|
|
206
164
|
})
|
|
207
|
-
const
|
|
208
|
-
if (compositions.value
|
|
209
|
-
return
|
|
210
|
-
compositions.value as { [key: string]: Composition },
|
|
211
|
-
).map((composition) => ({
|
|
212
|
-
...composition,
|
|
213
|
-
tags: composition.tags.map((tag) => tags.value?.[tag]),
|
|
214
|
-
lastEditor: users.value?.[composition.author]?.email,
|
|
215
|
-
author: users.value?.[composition.author]?.email,
|
|
216
|
-
status: composition.status, // TODO: parse status
|
|
217
|
-
statusIcon: getStatusIcon(composition.status),
|
|
218
|
-
statusColor: getStatusColor(composition.status),
|
|
219
|
-
createdAt: formatDistance(new Date(composition.createdAt), new Date()),
|
|
220
|
-
updatedAt: formatDistance(new Date(composition.updatedAt), new Date()),
|
|
221
|
-
}))
|
|
165
|
+
const compositionTableRows = (relativeDates: boolean) => {
|
|
166
|
+
if (!compositions.value || !tags.value) {
|
|
167
|
+
return []
|
|
222
168
|
}
|
|
223
169
|
|
|
224
|
-
return
|
|
225
|
-
}
|
|
170
|
+
return Object.values(
|
|
171
|
+
compositions.value as { [key: string]: Composition },
|
|
172
|
+
).map((composition) => ({
|
|
173
|
+
...composition,
|
|
174
|
+
tags: composition.tags.map((tag) => tags.value?.[tag]),
|
|
175
|
+
lastEditor: users.value?.[composition.author]?.email,
|
|
176
|
+
author: users.value?.[composition.author]?.email,
|
|
177
|
+
status: composition.status, // TODO: parse status
|
|
178
|
+
statusIcon: getStatusIcon(composition.status),
|
|
179
|
+
statusColor: getStatusColor(composition.status),
|
|
180
|
+
...(relativeDates
|
|
181
|
+
? {
|
|
182
|
+
createdAt: formatDistance(
|
|
183
|
+
new Date(composition.createdAt),
|
|
184
|
+
new Date(),
|
|
185
|
+
),
|
|
186
|
+
updatedAt: formatDistance(
|
|
187
|
+
new Date(composition.updatedAt),
|
|
188
|
+
new Date(),
|
|
189
|
+
),
|
|
190
|
+
}
|
|
191
|
+
: {}),
|
|
192
|
+
}))
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const parsedCompositions = computed(() => compositionTableRows(true))
|
|
196
|
+
|
|
197
|
+
const exportableCompositions = computed(() => compositionTableRows(false))
|
|
226
198
|
|
|
227
199
|
// TODO: replace with composition status type
|
|
228
200
|
const getStatusIcon = (status: string) => {
|
|
@@ -246,42 +218,26 @@ const getStatusColor = (status: string) => {
|
|
|
246
218
|
return "#B66218"
|
|
247
219
|
}
|
|
248
220
|
}
|
|
249
|
-
// Export functions
|
|
250
|
-
const openExportDialog = () => {
|
|
251
|
-
exportableItems.value = Object.values(compositions.value || {})
|
|
252
|
-
showExportDialog.value = true
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const handleExportConfirm = (selectedIds: string[]) => {
|
|
256
|
-
const dataToExport = selectedIds.reduce((acc, id) => {
|
|
257
|
-
if (compositions.value?.[id]) {
|
|
258
|
-
acc[id] = compositions.value[id]
|
|
259
|
-
}
|
|
260
|
-
return acc
|
|
261
|
-
}, {} as any)
|
|
262
|
-
|
|
263
|
-
exportedItems.value = Object.values(dataToExport)
|
|
264
|
-
downloadJson(dataToExport, "compositions")
|
|
265
|
-
showExportSummary.value = true
|
|
266
|
-
}
|
|
267
|
-
|
|
268
221
|
// Import functions
|
|
269
|
-
const handleFileUpload = (content: string
|
|
222
|
+
const handleFileUpload = (content: string | ArrayBuffer) => {
|
|
223
|
+
if (typeof content !== "string") {
|
|
224
|
+
return
|
|
225
|
+
}
|
|
270
226
|
try {
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
importableItems.value = itemsArray
|
|
275
|
-
pendingImportData.value = parsedData
|
|
227
|
+
const { items, byId } = parseAndNormalizeWorkbenchImportJson(content)
|
|
228
|
+
importableItems.value = items
|
|
229
|
+
pendingImportById.value = byId
|
|
276
230
|
showImportDialog.value = true
|
|
277
231
|
} catch (error) {
|
|
278
|
-
console.error("Failed to
|
|
232
|
+
console.error("Failed to prepare import:", error)
|
|
279
233
|
}
|
|
280
234
|
}
|
|
281
235
|
|
|
282
236
|
const handleImportConfirm = (selectedIds: string[]) => {
|
|
283
|
-
|
|
284
|
-
|
|
237
|
+
importedItems.value = resolveWorkbenchImportSelection(
|
|
238
|
+
pendingImportById.value,
|
|
239
|
+
selectedIds,
|
|
240
|
+
)
|
|
285
241
|
showImportSummary.value = true
|
|
286
242
|
}
|
|
287
243
|
|
|
@@ -303,7 +259,7 @@ const finalizeImport = async () => {
|
|
|
303
259
|
// e.g., call an API endpoint to save the imported compositions
|
|
304
260
|
|
|
305
261
|
// Reset states
|
|
306
|
-
|
|
262
|
+
pendingImportById.value = {}
|
|
307
263
|
importableItems.value = []
|
|
308
264
|
importedItems.value = []
|
|
309
265
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<BaseDataTable
|
|
4
4
|
:items="parsedInteractionLinks"
|
|
5
|
+
:exportable-items="exportableInteractionLinks"
|
|
5
6
|
:loading="interactionLinksLoading || tagsLoading"
|
|
6
7
|
:headers="headers"
|
|
7
8
|
create-interaction-link-id="interactionLinkCreateInteractionLink"
|
|
@@ -9,16 +10,17 @@
|
|
|
9
10
|
:data-name="$t('workbench.interactionLinkList.dataName')"
|
|
10
11
|
:data-article="$t('workbench.interactionLinkList.dataArticle')"
|
|
11
12
|
@delete="deleteInteractionLink"
|
|
12
|
-
:
|
|
13
|
+
:items-deleted="showDeleted"
|
|
14
|
+
:on-file-loaded="handleFileUpload"
|
|
13
15
|
>
|
|
14
|
-
<template #
|
|
16
|
+
<template #toolbar-leading>
|
|
15
17
|
<v-tooltip
|
|
16
18
|
:text="showDeleted ? $t('core.hideDeleted') : $t('core.showDeleted')"
|
|
17
19
|
>
|
|
18
|
-
<template
|
|
20
|
+
<template #activator="{ props: activatorProps }">
|
|
19
21
|
<v-btn-toggle
|
|
20
22
|
density="compact"
|
|
21
|
-
v-bind="
|
|
23
|
+
v-bind="activatorProps"
|
|
22
24
|
v-model="showDeleted"
|
|
23
25
|
mandatory
|
|
24
26
|
:color="showDeleted ? 'error' : 'success'"
|
|
@@ -30,29 +32,9 @@
|
|
|
30
32
|
</v-btn-toggle>
|
|
31
33
|
</template>
|
|
32
34
|
</v-tooltip>
|
|
33
|
-
<v-btn-group density="compact">
|
|
34
|
-
<v-tooltip :text="$t('core.export')">
|
|
35
|
-
<template v-slot:activator="{ props }">
|
|
36
|
-
<v-btn color="info" v-bind="props" flat @click="openExportDialog">
|
|
37
|
-
<v-icon>mdi-database-export</v-icon>
|
|
38
|
-
</v-btn>
|
|
39
|
-
</template>
|
|
40
|
-
</v-tooltip>
|
|
41
|
-
<v-tooltip :text="$t('core.import')">
|
|
42
|
-
<template v-slot:activator="{ props }">
|
|
43
|
-
<v-btn v-bind="props" color="warning">
|
|
44
|
-
<FileUpload
|
|
45
|
-
ref="uploadRef"
|
|
46
|
-
:onFileLoaded="handleFileUpload"
|
|
47
|
-
accept=".json"
|
|
48
|
-
readAs="text"
|
|
49
|
-
/></v-btn>
|
|
50
|
-
</template>
|
|
51
|
-
</v-tooltip>
|
|
52
|
-
</v-btn-group>
|
|
53
35
|
</template>
|
|
54
36
|
<!-- Custom triggers column -->
|
|
55
|
-
<template #item.triggers="{ item }">
|
|
37
|
+
<template #[`item.triggers`]="{ item }">
|
|
56
38
|
<span class="tw:flex tw:gap-2">
|
|
57
39
|
<span>{{ item.triggers }}</span>
|
|
58
40
|
<v-icon icon="mdi-link" />
|
|
@@ -73,18 +55,8 @@
|
|
|
73
55
|
/>
|
|
74
56
|
</template>
|
|
75
57
|
</BaseDataTable>
|
|
76
|
-
<!-- Export Selection Dialog -->
|
|
77
|
-
<SelectionDialog
|
|
78
|
-
v-model="showExportDialog"
|
|
79
|
-
:items="exportableItems"
|
|
80
|
-
display-attribute="description"
|
|
81
|
-
:title="$t('core.selectItemsToExport')"
|
|
82
|
-
:confirm-text="$t('core.export')"
|
|
83
|
-
@confirm="handleExportConfirm"
|
|
84
|
-
/>
|
|
85
|
-
|
|
86
58
|
<!-- Import Selection Dialog -->
|
|
87
|
-
<
|
|
59
|
+
<ImportSelectionDialog
|
|
88
60
|
v-model="showImportDialog"
|
|
89
61
|
:items="importableItems"
|
|
90
62
|
display-attribute="description"
|
|
@@ -93,18 +65,8 @@
|
|
|
93
65
|
@confirm="handleImportConfirm"
|
|
94
66
|
/>
|
|
95
67
|
|
|
96
|
-
<!-- Export Summary Dialog -->
|
|
97
|
-
<SummaryDialog
|
|
98
|
-
v-model="showExportSummary"
|
|
99
|
-
display-attribute="description"
|
|
100
|
-
:items="exportedItems"
|
|
101
|
-
:title="$t('core.exportSummary')"
|
|
102
|
-
:message="$t('core.exportSuccessMessage')"
|
|
103
|
-
type="success"
|
|
104
|
-
/>
|
|
105
|
-
|
|
106
68
|
<!-- Import Summary Dialog -->
|
|
107
|
-
<
|
|
69
|
+
<ImportSummaryDialog
|
|
108
70
|
v-model="showImportSummary"
|
|
109
71
|
:items="importedItems"
|
|
110
72
|
display-attribute="description"
|
|
@@ -119,31 +81,26 @@
|
|
|
119
81
|
</template>
|
|
120
82
|
|
|
121
83
|
<script setup lang="ts">
|
|
122
|
-
import
|
|
123
|
-
import BaseDataTable from "@app/components/BaseDataTable.vue"
|
|
84
|
+
import BaseDataTable from "@raclettejs/core/orchestrator/components/dataTable/BaseDataTable.vue"
|
|
124
85
|
import { InteractionLink } from "@raclettejs/core"
|
|
125
86
|
import { usePluginApi } from "@raclettejs/core/orchestrator/composables"
|
|
126
87
|
import { formatDistance } from "date-fns"
|
|
127
|
-
import { computed, ref, watch
|
|
88
|
+
import { computed, ref, watch } from "vue"
|
|
128
89
|
import { useI18n } from "vue-i18n"
|
|
129
|
-
import {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
90
|
+
import {
|
|
91
|
+
mapJsonValues,
|
|
92
|
+
parseAndNormalizeWorkbenchImportJson,
|
|
93
|
+
resolveWorkbenchImportSelection,
|
|
94
|
+
} from "@app/lib/jsonTools"
|
|
95
|
+
import ImportSelectionDialog from "@raclettejs/core/orchestrator/components/dataImport/ImportSelectionDialog.vue"
|
|
96
|
+
import ImportSummaryDialog from "@raclettejs/core/orchestrator/components/dataImport/ImportSummaryDialog.vue"
|
|
133
97
|
const showDeleted = ref(false)
|
|
134
|
-
// Dialog states
|
|
135
|
-
const showExportDialog = ref(false)
|
|
136
98
|
const showImportDialog = ref(false)
|
|
137
|
-
const showExportSummary = ref(false)
|
|
138
99
|
const showImportSummary = ref(false)
|
|
139
100
|
|
|
140
|
-
// Data for dialogs
|
|
141
|
-
const exportableItems = ref<any[]>([])
|
|
142
101
|
const importableItems = ref<any[]>([])
|
|
143
|
-
const exportedItems = ref<any[]>([])
|
|
144
102
|
const importedItems = ref<any[]>([])
|
|
145
|
-
const
|
|
146
|
-
const uploadRef = useTemplateRef("uploadRef")
|
|
103
|
+
const pendingImportById = ref<Record<string, any>>({})
|
|
147
104
|
|
|
148
105
|
const { t } = useI18n()
|
|
149
106
|
|
|
@@ -217,32 +174,40 @@ const { execute: executeHardDelete } = await $data.interactionLink.deleteHard({
|
|
|
217
174
|
const { execute: executeRestore } = await $data.interactionLink.updateRestore({
|
|
218
175
|
options: { cb: () => execute({ isDeleted: showDeleted.value }) },
|
|
219
176
|
})
|
|
220
|
-
const
|
|
221
|
-
if (interactionLinks.value
|
|
222
|
-
return
|
|
223
|
-
interactionLinks.value as { [key: string]: InteractionLink },
|
|
224
|
-
).map((interactionLink) => {
|
|
225
|
-
return {
|
|
226
|
-
...interactionLink,
|
|
227
|
-
composition: compositions.value?.[interactionLink.composition]?.title,
|
|
228
|
-
tags: interactionLink.tags.map((tag) => tags.value?.[tag]),
|
|
229
|
-
lastEditor: users.value?.[interactionLink.author]?.email,
|
|
230
|
-
author: users.value?.[interactionLink.author]?.email,
|
|
231
|
-
triggers: interactionLink.triggers.length,
|
|
232
|
-
createdAt: formatDistance(
|
|
233
|
-
new Date(interactionLink.createdAt),
|
|
234
|
-
new Date(),
|
|
235
|
-
),
|
|
236
|
-
updatedAt: formatDistance(
|
|
237
|
-
new Date(interactionLink.updatedAt),
|
|
238
|
-
new Date(),
|
|
239
|
-
),
|
|
240
|
-
}
|
|
241
|
-
})
|
|
177
|
+
const interactionLinkTableRows = (relativeDates: boolean) => {
|
|
178
|
+
if (!interactionLinks.value || !tags.value) {
|
|
179
|
+
return []
|
|
242
180
|
}
|
|
243
181
|
|
|
244
|
-
return
|
|
245
|
-
}
|
|
182
|
+
return Object.values(
|
|
183
|
+
interactionLinks.value as { [key: string]: InteractionLink },
|
|
184
|
+
).map((interactionLink) => ({
|
|
185
|
+
...interactionLink,
|
|
186
|
+
composition: compositions.value?.[interactionLink.composition]?.title,
|
|
187
|
+
tags: interactionLink.tags.map((tag) => tags.value?.[tag]),
|
|
188
|
+
lastEditor: users.value?.[interactionLink.author]?.email,
|
|
189
|
+
author: users.value?.[interactionLink.author]?.email,
|
|
190
|
+
triggers: interactionLink.triggers.length,
|
|
191
|
+
...(relativeDates
|
|
192
|
+
? {
|
|
193
|
+
createdAt: formatDistance(
|
|
194
|
+
new Date(interactionLink.createdAt),
|
|
195
|
+
new Date(),
|
|
196
|
+
),
|
|
197
|
+
updatedAt: formatDistance(
|
|
198
|
+
new Date(interactionLink.updatedAt),
|
|
199
|
+
new Date(),
|
|
200
|
+
),
|
|
201
|
+
}
|
|
202
|
+
: {}),
|
|
203
|
+
}))
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const parsedInteractionLinks = computed(() => interactionLinkTableRows(true))
|
|
207
|
+
|
|
208
|
+
const exportableInteractionLinks = computed(() =>
|
|
209
|
+
interactionLinkTableRows(false),
|
|
210
|
+
)
|
|
246
211
|
const restore = async (_id: string) => {
|
|
247
212
|
executeRestore({ _id })
|
|
248
213
|
}
|
|
@@ -267,50 +232,27 @@ const createTitleString = (link) => {
|
|
|
267
232
|
link.description = linkTitleString + link.description
|
|
268
233
|
return link
|
|
269
234
|
}
|
|
270
|
-
const createLinkDescriptions = (linkArr) => {
|
|
271
|
-
linkArr.forEach((link) => {
|
|
272
|
-
link = createTitleString(link)
|
|
273
|
-
})
|
|
274
|
-
return linkArr
|
|
275
|
-
}
|
|
276
|
-
// Export functions
|
|
277
|
-
const openExportDialog = () => {
|
|
278
|
-
exportableItems.value = createLinkDescriptions(
|
|
279
|
-
Object.values(clone(interactionLinks.value) || {}),
|
|
280
|
-
)
|
|
281
|
-
showExportDialog.value = true
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const handleExportConfirm = (selectedIds: string[]) => {
|
|
285
|
-
const _interactionLinks = clone(interactionLinks.value)
|
|
286
|
-
const dataToExport = clone(selectedIds).reduce((acc, id) => {
|
|
287
|
-
if (_interactionLinks?.[id]) {
|
|
288
|
-
acc[id] = createTitleString(_interactionLinks[id])
|
|
289
|
-
}
|
|
290
|
-
return acc
|
|
291
|
-
}, {} as any)
|
|
292
|
-
exportedItems.value = Object.values(dataToExport)
|
|
293
|
-
downloadJson(dataToExport, "interactionLinks")
|
|
294
|
-
showExportSummary.value = true
|
|
295
|
-
}
|
|
296
235
|
|
|
297
236
|
// Import functions
|
|
298
|
-
const handleFileUpload = (content: string
|
|
237
|
+
const handleFileUpload = (content: string | ArrayBuffer) => {
|
|
238
|
+
if (typeof content !== "string") {
|
|
239
|
+
return
|
|
240
|
+
}
|
|
299
241
|
try {
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
importableItems.value = itemsArray
|
|
304
|
-
pendingImportData.value = parsedData
|
|
242
|
+
const { items, byId } = parseAndNormalizeWorkbenchImportJson(content)
|
|
243
|
+
importableItems.value = items
|
|
244
|
+
pendingImportById.value = byId
|
|
305
245
|
showImportDialog.value = true
|
|
306
246
|
} catch (error) {
|
|
307
|
-
console.error("Failed to
|
|
247
|
+
console.error("Failed to prepare import:", error)
|
|
308
248
|
}
|
|
309
249
|
}
|
|
310
250
|
|
|
311
251
|
const handleImportConfirm = (selectedIds: string[]) => {
|
|
312
|
-
|
|
313
|
-
|
|
252
|
+
importedItems.value = resolveWorkbenchImportSelection(
|
|
253
|
+
pendingImportById.value,
|
|
254
|
+
selectedIds,
|
|
255
|
+
)
|
|
314
256
|
showImportSummary.value = true
|
|
315
257
|
}
|
|
316
258
|
|
|
@@ -332,7 +274,7 @@ const finalizeImport = async () => {
|
|
|
332
274
|
// e.g., call an API endpoint to save the imported compositions
|
|
333
275
|
|
|
334
276
|
// Reset states
|
|
335
|
-
|
|
277
|
+
pendingImportById.value = {}
|
|
336
278
|
importableItems.value = []
|
|
337
279
|
importedItems.value = []
|
|
338
280
|
}
|
|
@@ -8,20 +8,20 @@
|
|
|
8
8
|
:show-delete-action="false"
|
|
9
9
|
:show-actions-column="false"
|
|
10
10
|
:row-click-handler="onRowClick"
|
|
11
|
+
:show-export="false"
|
|
11
12
|
>
|
|
12
13
|
</BaseDataTable>
|
|
13
14
|
</template>
|
|
14
15
|
|
|
15
16
|
<script setup lang="ts">
|
|
16
17
|
import useWorkbenchPlugins from "@app/composables/useWorkbenchPlugins"
|
|
17
|
-
import BaseDataTable from "@
|
|
18
|
+
import BaseDataTable from "@raclettejs/core/orchestrator/components/dataTable/BaseDataTable.vue"
|
|
18
19
|
import type { PluginMetadata } from "@raclettejs/core"
|
|
19
20
|
import { computed } from "vue"
|
|
20
21
|
import {
|
|
21
22
|
usePluginApi,
|
|
22
23
|
useRouteState,
|
|
23
24
|
} from "@raclettejs/core/orchestrator/composables"
|
|
24
|
-
import { DEFAULT_SLOT_NAME } from "@raclettejs/core/orchestrator/router/routeParserHelper"
|
|
25
25
|
|
|
26
26
|
const { pluginMetadataFiles, hasPluginSettingsWidget } = useWorkbenchPlugins()
|
|
27
27
|
|