@raclettejs/workbench 0.1.16 → 0.1.18

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/CHANGELOG.md CHANGED
@@ -7,11 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [0.1.16] - 05.11.2025 <a href="https://gitlab.com/raclettejs/workbench/-/compare/v0.1.15...v0.1.16" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
10
+ ## [0.1.18] - 05.12.2025 <a href="https://gitlab.com/raclettejs/workbench/-/compare/v0.1.17...v0.1.18" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
11
+
12
+ ### Removed
13
+
14
+ - Removed redundand authTokenExpiryDays config
15
+
16
+ ### Added
17
+
18
+ - Interaction Links can now have a trigger in the appbar
19
+ - possibility to restore items
20
+ - possibility to add prepend and append actions to base table row items
21
+ - added project configuration interface
22
+
23
+ ## [0.1.17] - 06.11.2025 <a href="https://gitlab.com/raclettejs/workbench/-/compare/v0.1.15...v0.1.17" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
11
24
 
12
25
  ### Added
13
26
 
14
27
  - added isDeleted switch to lists
28
+ - added hard deletion to all core types
15
29
 
16
30
  ## [0.1.15] - 02.11.2025 <a href="https://gitlab.com/raclettejs/workbench/-/compare/v0.1.13...v0.1.15" target="_blank" rel="noopener"><b>Overview of all changes</b></a>
17
31
 
@@ -2,7 +2,6 @@ export default [
2
2
  // composition administration
3
3
  {
4
4
  _id: "compositionList",
5
- description: "Ein Test",
6
5
  pathname: {
7
6
  default: "composition-list",
8
7
  },
@@ -21,7 +20,6 @@ export default [
21
20
  },
22
21
  {
23
22
  _id: "compositionCreate",
24
- description: "Ein Test",
25
23
  pathname: {
26
24
  default: "composition-create",
27
25
  },
@@ -41,7 +39,6 @@ export default [
41
39
  },
42
40
  {
43
41
  _id: "compositionEdit",
44
- description: "Ein Test",
45
42
  pathname: {
46
43
  default: "composition-edit",
47
44
  },
@@ -63,7 +60,6 @@ export default [
63
60
  // interactionLinks administration
64
61
  {
65
62
  _id: "interactionLinkList",
66
- description: "Ein Test",
67
63
  pathname: {
68
64
  default: "interactionLink-list",
69
65
  },
@@ -82,7 +78,6 @@ export default [
82
78
  },
83
79
  {
84
80
  _id: "interactionLinkCreate",
85
- description: "Ein Test",
86
81
  pathname: {
87
82
  default: "interactionLink-create",
88
83
  },
@@ -101,7 +96,6 @@ export default [
101
96
  },
102
97
  {
103
98
  _id: "interactionLinkEdit",
104
- description: "Ein Test",
105
99
  pathname: {
106
100
  default: "interactionLink-edit",
107
101
  },
@@ -123,7 +117,6 @@ export default [
123
117
  // users administration
124
118
  {
125
119
  _id: "userList",
126
- description: "Ein Test",
127
120
  pathname: {
128
121
  default: "user-list",
129
122
  },
@@ -142,7 +135,6 @@ export default [
142
135
  },
143
136
  {
144
137
  _id: "userCreate",
145
- description: "Ein Test",
146
138
  pathname: {
147
139
  default: "user-create",
148
140
  },
@@ -161,7 +153,6 @@ export default [
161
153
  },
162
154
  {
163
155
  _id: "userEdit",
164
- description: "Ein Test",
165
156
  pathname: {
166
157
  default: "user-edit",
167
158
  },
@@ -182,7 +173,6 @@ export default [
182
173
  // tags administration
183
174
  {
184
175
  _id: "tagList",
185
- description: "Ein Test",
186
176
  pathname: {
187
177
  default: "tag-list",
188
178
  },
@@ -201,7 +191,6 @@ export default [
201
191
  },
202
192
  {
203
193
  _id: "tagCreate",
204
- description: "Ein Test",
205
194
  pathname: {
206
195
  default: "tag-create",
207
196
  },
@@ -220,7 +209,6 @@ export default [
220
209
  },
221
210
  {
222
211
  _id: "tagEdit",
223
- description: "Ein Test",
224
212
  pathname: {
225
213
  default: "tag-edit",
226
214
  },
@@ -242,7 +230,6 @@ export default [
242
230
  // plugins configuration
243
231
  {
244
232
  _id: "pluginList",
245
- description: "Ein Test",
246
233
  pathname: {
247
234
  default: "plugin-list",
248
235
  },
@@ -261,7 +248,6 @@ export default [
261
248
  },
262
249
  {
263
250
  _id: "pluginDetail",
264
- description: "Ein Test",
265
251
  pathname: {
266
252
  default: "plugin-detail",
267
253
  },
@@ -279,4 +265,22 @@ export default [
279
265
  ],
280
266
  queryParameters: ["id"],
281
267
  },
268
+ {
269
+ _id: "projectDetail",
270
+ pathname: {
271
+ default: "project-detail",
272
+ },
273
+ widgetsLayout: [
274
+ [
275
+ {
276
+ column: 12,
277
+ widget: {
278
+ uuid: "ProjectDetail",
279
+ name: "ProjectDetail",
280
+ pluginKey: "pacifico__project",
281
+ },
282
+ },
283
+ ],
284
+ ],
285
+ },
282
286
  ] //satisfies Composition[]
@@ -45,8 +45,8 @@ export default [
45
45
  settings: {
46
46
  icon: "mdi-link-box-variant",
47
47
  title: {
48
- default: "interactionLink",
49
- de: "interactionLink",
48
+ default: "Interaction Links",
49
+ de: "Interaktionslinks",
50
50
  },
51
51
  sortOrder: 1,
52
52
  navigationBarType: "navItem",
@@ -78,8 +78,8 @@ export default [
78
78
  settings: {
79
79
  icon: "mdi-account-details",
80
80
  title: {
81
- default: "users",
82
- de: "users",
81
+ default: "Users",
82
+ de: "Nutzer",
83
83
  },
84
84
  sortOrder: 2,
85
85
  navigationBarType: "navItem",
@@ -111,10 +111,10 @@ export default [
111
111
  settings: {
112
112
  icon: "mdi-tag",
113
113
  title: {
114
- default: "tags",
115
- de: "tags",
114
+ default: "Tags",
115
+ de: "Tags",
116
116
  },
117
- sortOrder: 2,
117
+ sortOrder: 3,
118
118
  navigationBarType: "navItem",
119
119
  },
120
120
  },
@@ -145,10 +145,10 @@ export default [
145
145
  settings: {
146
146
  icon: "mdi-puzzle",
147
147
  title: {
148
- default: "plugins",
149
- de: "plugins",
148
+ default: "Plugins",
149
+ de: "Plugins",
150
150
  },
151
- sortOrder: 2,
151
+ sortOrder: 4,
152
152
  navigationBarType: "navItem",
153
153
  },
154
154
  },
@@ -161,4 +161,24 @@ export default [
161
161
  triggers: [],
162
162
  queryParameters: ["pluginKey"],
163
163
  },
164
+ // project configuration
165
+ {
166
+ _id: "projectDetailInteractionLink",
167
+ composition: compositions[14]._id,
168
+ slotType: "page",
169
+ triggers: [
170
+ {
171
+ type: "page-navigation",
172
+ settings: {
173
+ icon: "mdi-application-cog",
174
+ title: {
175
+ default: "Project",
176
+ de: "Projekt",
177
+ },
178
+ sortOrder: 0,
179
+ navigationBarType: "footerItem",
180
+ },
181
+ },
182
+ ],
183
+ },
164
184
  ] // satisfies Partial<InteractionLink>[]
package/i18n/de-DE.json CHANGED
@@ -42,6 +42,7 @@
42
42
  "searchPlaceholder": "{dataName} durchsuchen",
43
43
  "createDataButton": "{dataName} erstellen",
44
44
  "deleteDataTitle": "{dataName} löschen",
45
+ "restoreDataTitle": "{dataName} widerherstellen",
45
46
  "deleteDataConfirmMessage": "Bist du sicher, dass du {article} {dataName} <strong>{value}</strong> löschen willst?",
46
47
  "deleteDataConfirmButton": "Löschen",
47
48
  "deleteDataConfirmCancel": "Abbrechen"
@@ -246,6 +247,31 @@
246
247
  "invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
247
248
  "invalidUrl": "Bitte geben Sie eine gültige URL ein"
248
249
  }
250
+ },
251
+ "project": {
252
+ "formtitle": "Projekt bearbeiten",
253
+ "dataName": "Projekt",
254
+ "dividers": {
255
+ "general": "Allgemein",
256
+ "config": "Konfiguration"
257
+ },
258
+ "title": {
259
+ "title": "Projekt name",
260
+ "description": "Der Name des Projekts"
261
+ },
262
+ "tags": {
263
+ "title": "Tags",
264
+ "description": "Dieses Feld dient nur der internen Zuordnung der Komposition und wird nicht im Produkt angezeigt."
265
+ },
266
+ "description": {
267
+ "title": "Projekt Beschreibung",
268
+ "description": "Die Beschreibung des Portal/Platform Inhalts"
269
+ },
270
+ "config": "Projekt Konfiguration",
271
+ "railPageNavigation": {
272
+ "title": "Ausklappbare Navigation",
273
+ "description": "Wenn aktiviert wird die Seitennavigation automatisch ein- und aufgeklappt"
274
+ }
249
275
  }
250
276
  }
251
- }
277
+ }
package/i18n/en-EU.json CHANGED
@@ -42,6 +42,7 @@
42
42
  "searchPlaceholder": "Search {dataName}",
43
43
  "createDataButton": "Create {dataName}",
44
44
  "deleteDataTitle": "Delete {dataName}",
45
+ "restoreDataTitle": "Restore {dataName}",
45
46
  "deleteDataConfirmMessage": "Are you sure you want to delete {article} {dataName} <strong>{value}</strong>?",
46
47
  "deleteDataConfirmButton": "Delete",
47
48
  "deleteDataConfirmCancel": "Cancel"
@@ -246,6 +247,31 @@
246
247
  "invalidEmail": "Please enter a valid email address",
247
248
  "invalidUrl": "Please enter a valid URL"
248
249
  }
250
+ },
251
+ "project": {
252
+ "formtitle": "Edit Project",
253
+ "dataName": "Project",
254
+ "dividers": {
255
+ "general": "General",
256
+ "config": "Configuration"
257
+ },
258
+ "title": {
259
+ "title": "Project Name",
260
+ "description": "The name of the project"
261
+ },
262
+ "tags": {
263
+ "title": "Tags",
264
+ "description": "This field is only used for internal categorization of the composition and is not displayed in the product."
265
+ },
266
+ "description": {
267
+ "title": "Project Description",
268
+ "description": "The description of the portal/platform content"
269
+ },
270
+ "config": "Project Configuration",
271
+ "railPageNavigation": {
272
+ "title": "Collapsible Navigation",
273
+ "description": "When enabled, the page navigation is automatically collapsed and expanded"
274
+ }
249
275
  }
250
276
  }
251
- }
277
+ }
package/i18n/sk-SK.json CHANGED
@@ -42,6 +42,7 @@
42
42
  "searchPlaceholder": "Hľadať {dataName}",
43
43
  "createDataButton": "Vytvoriť {dataName}",
44
44
  "deleteDataTitle": "Odstrániť {dataName}",
45
+ "restoreDataTitle": "Obnoviť {dataName}",
45
46
  "deleteDataConfirmMessage": "Naozaj chcete odstrániť {article} {dataName} <strong>{value}</strong>?",
46
47
  "deleteDataConfirmButton": "Odstrániť",
47
48
  "deleteDataConfirmCancel": "Zrušiť"
@@ -241,6 +242,31 @@
241
242
  "invalidEmail": "Zadajte platnú emailovú adresu",
242
243
  "invalidUrl": "Zadajte platnú URL adresu"
243
244
  }
245
+ },
246
+ "project": {
247
+ "formtitle": "Upraviť projekt",
248
+ "dataName": "Projekt",
249
+ "dividers": {
250
+ "general": "Všeobecné",
251
+ "config": "Konfigurácia"
252
+ },
253
+ "title": {
254
+ "title": "Názov projektu",
255
+ "description": "Názov projektu"
256
+ },
257
+ "description": {
258
+ "title": "Popis projektu",
259
+ "description": "Popis obsahu portálu/platformy"
260
+ },
261
+ "config": "Projekt Konfigurácia",
262
+ "railPageNavigation": {
263
+ "title": "Sklopná navigácia",
264
+ "description": "Ak je povolená, stránková navigácia sa automaticky sklopí a rozbalí"
265
+ },
266
+ "tags": {
267
+ "title": "Značky",
268
+ "description": "Toto pole slúži len na internú kategorizáciu kompozície a nezobrazuje sa v produkte."
269
+ }
244
270
  }
245
271
  }
246
272
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raclettejs/workbench",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
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",
@@ -31,13 +31,13 @@
31
31
  ".": "./index.ts"
32
32
  },
33
33
  "dependencies": {
34
- "@raclettejs/core": "0.1.16",
34
+ "@raclettejs/core": "^0.1.18",
35
35
  "three": "0.180.0",
36
36
  "vanta": "0.5.24"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@eslint/js": "9.35.0",
40
- "@raclettejs/types": "0.1.16",
40
+ "@raclettejs/types": "^0.1.18",
41
41
  "@sinclair/typebox": "0.34.41",
42
42
  "@types/ramda": "0.31.1",
43
43
  "@vueuse/core": "13.9.0",
@@ -8,6 +8,7 @@
8
8
  :data-name="$t('workbench.compositionList.dataName')"
9
9
  :data-article="$t('workbench.compositionList.dataArticle')"
10
10
  @delete="deleteComposition"
11
+ :itemsDeleted="showDeleted"
11
12
  >
12
13
  <template #actions>
13
14
  <v-tooltip
@@ -37,6 +38,20 @@
37
38
  size="x-large"
38
39
  />
39
40
  </template>
41
+ <template #prepend-row-actions="{ item }">
42
+ <v-icon
43
+ v-if="showDeleted"
44
+ color="green"
45
+ class="mr-2"
46
+ @click.stop.prevent="restore(item._id)"
47
+ :title="
48
+ $t('workbench.baseDataTable.restoreDataTitle', {
49
+ dataName: item.title,
50
+ })
51
+ "
52
+ icon="mdi-delete-restore"
53
+ />
54
+ </template>
40
55
  </BaseDataTable>
41
56
  </template>
42
57
 
@@ -90,7 +105,6 @@ const {
90
105
  execute,
91
106
  isLoading: compositionsLoading,
92
107
  } = $data.composition.getAll()
93
-
94
108
  const { data: tags, isLoading: tagsLoading } = $data.tag.getAll({
95
109
  options: { immediate: true },
96
110
  })
@@ -100,7 +114,12 @@ const { data: users } = $data.user.getAll({
100
114
  const { execute: executeDelete } = await $data.composition.delete({
101
115
  options: { cb: () => execute({ isDeleted: showDeleted.value }) },
102
116
  })
103
-
117
+ const { execute: executeRestore } = await $data.composition.updateRestore({
118
+ options: { cb: () => execute({ isDeleted: showDeleted.value }) },
119
+ })
120
+ const { execute: executeHardDelete } = await $data.composition.deleteHard({
121
+ options: { cb: () => execute({ isDeleted: showDeleted.value }) },
122
+ })
104
123
  const parsedCompositions = computed(() => {
105
124
  if (compositions.value && tags.value) {
106
125
  return Object.values(
@@ -144,9 +163,16 @@ const getStatusColor = (status: string) => {
144
163
  }
145
164
  }
146
165
 
147
- const deleteComposition = async (composition: Composition) =>
148
- await executeDelete({ _id: composition._id })
149
-
166
+ const deleteComposition = async (composition: Composition) => {
167
+ if (showDeleted.value) {
168
+ await executeHardDelete({ _id: composition._id })
169
+ } else {
170
+ await executeDelete({ _id: composition._id })
171
+ }
172
+ }
173
+ const restore = (_id: string) => {
174
+ executeRestore({ _id })
175
+ }
150
176
  $socket.on("compositionCreated", () =>
151
177
  execute({ isDeleted: showDeleted.value }),
152
178
  )
@@ -8,6 +8,7 @@
8
8
  :data-name="$t('workbench.interactionLinkList.dataName')"
9
9
  :data-article="$t('workbench.interactionLinkList.dataArticle')"
10
10
  @delete="deleteInteractionLink"
11
+ :itemsDeleted="showDeleted"
11
12
  >
12
13
  <template #actions>
13
14
  <v-tooltip
@@ -36,6 +37,20 @@
36
37
  <v-icon icon="mdi-link" />
37
38
  </span>
38
39
  </template>
40
+ <template #prepend-row-actions="{ item }">
41
+ <v-icon
42
+ v-if="showDeleted"
43
+ color="green"
44
+ class="mr-2"
45
+ @click="restore(item._id)"
46
+ :title="
47
+ $t('workbench.baseDataTable.restoreDataTitle', {
48
+ dataName: item.title,
49
+ })
50
+ "
51
+ icon="mdi-delete-restore"
52
+ />
53
+ </template>
39
54
  </BaseDataTable>
40
55
  </template>
41
56
 
@@ -104,13 +119,19 @@ const { data: users } = $data.user.getAll({
104
119
  })
105
120
 
106
121
  const { data: compositions } = $data.composition.getAll({
122
+ params: { isDeleted: false },
107
123
  options: { immediate: true },
108
124
  })
109
125
 
110
126
  const { execute: executeDelete } = $data.interactionLink.delete({
111
127
  options: { cb: () => execute({ isDeleted: showDeleted.value }) },
112
128
  })
113
-
129
+ const { execute: executeHardDelete } = await $data.interactionLink.deleteHard({
130
+ options: { cb: () => execute({ isDeleted: showDeleted.value }) },
131
+ })
132
+ const { execute: executeRestore } = await $data.interactionLink.updateRestore({
133
+ options: { cb: () => execute({ isDeleted: showDeleted.value }) },
134
+ })
114
135
  const parsedInteractionLinks = computed(() => {
115
136
  if (interactionLinks.value && tags.value) {
116
137
  return Object.values(
@@ -137,9 +158,16 @@ const parsedInteractionLinks = computed(() => {
137
158
 
138
159
  return []
139
160
  })
140
-
141
- const deleteInteractionLink = async (interactionLink: InteractionLink) =>
142
- await executeDelete({ _id: interactionLink._id })
161
+ const restore = async (_id: string) => {
162
+ executeRestore({ _id })
163
+ }
164
+ const deleteInteractionLink = async (interactionLink: InteractionLink) => {
165
+ if (showDeleted.value) {
166
+ await executeHardDelete({ _id: interactionLink._id })
167
+ } else {
168
+ await executeDelete({ _id: interactionLink._id })
169
+ }
170
+ }
143
171
 
144
172
  $socket.on("interactionLinkCreated", () =>
145
173
  execute({ isDeleted: showDeleted.value }),
@@ -0,0 +1,107 @@
1
+ <template>
2
+ <StepNavigator
3
+ :steps
4
+ :is-saving="disabled"
5
+ :show-save-button="isEditing"
6
+ @save="$emit('save')"
7
+ @save-and-finish="$emit('save-and-finish')"
8
+ >
9
+ <!-- @vue-generic {ProjectUpdate} -->
10
+ <DynamicForm
11
+ ref="dynamicFormRef"
12
+ v-model="project"
13
+ :data="projectInputFields"
14
+ :disabled
15
+ :title="$t('workbench.project.formtitle')"
16
+ />
17
+ <DynamicForm
18
+ ref="dynamicFormRef"
19
+ v-model="project.config"
20
+ :data="configInputFields"
21
+ :disabled
22
+ />
23
+ </StepNavigator>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import type { ProjectUpdate } from "@raclettejs/core"
28
+ import DynamicForm from "@app/components/dynamicForm/DynamicForm.vue"
29
+ import type { DynamicFormItem } from "@app/components/dynamicForm/DynamicFormTypes"
30
+ import { useI18n } from "vue-i18n"
31
+ import { computed, useTemplateRef } from "vue"
32
+ import { Step } from "@app/components/stepNavigator/StepNavigatorTypes"
33
+ import StepNavigator from "@app/components/stepNavigator/StepNavigator.vue"
34
+
35
+ defineProps<{ disabled?: boolean; isEditing?: boolean }>()
36
+
37
+ defineEmits<{
38
+ (e: "save"): void
39
+ (e: "save-and-finish"): void
40
+ }>()
41
+
42
+ const project = defineModel<ProjectUpdate>({ required: true })
43
+
44
+ const dynamicFormRef = useTemplateRef("dynamicFormRef")
45
+
46
+ const { t } = useI18n()
47
+
48
+ const projectInputFields = computed<DynamicFormItem<ProjectUpdate>[]>(() => [
49
+ { divider: t("workbench.project.dividers.general") },
50
+ {
51
+ title: t("workbench.project.title.title"),
52
+ description: t("workbench.project.title.description"),
53
+ inputType: "textarea",
54
+ field: "title",
55
+ prependIcon: "text",
56
+ },
57
+ {
58
+ title: t("workbench.project.description.title"),
59
+ description: t("workbench.project.description.description"),
60
+ inputType: "textarea",
61
+ field: "description",
62
+ prependIcon: "text",
63
+ },
64
+ /* {
65
+ title: t("workbench.interactionLinkConfiguration.tags.title"),
66
+ description: t("workbench.project.tags.description"),
67
+ inputType: "tags",
68
+ field: "tags",
69
+ prependIcon: "tag-multiple",
70
+ },*/
71
+ ])
72
+ const configInputFields = computed<DynamicFormItem<ProjectUpdate["config"]>[]>(
73
+ () => [
74
+ { divider: t("workbench.project.dividers.config") },
75
+ {
76
+ title: t("workbench.project.railPageNavigation.title"),
77
+ description: t("workbench.project.railPageNavigation.description"),
78
+ inputType: "switch",
79
+ field: "railPageNavigation",
80
+ },
81
+ /*{
82
+ title: t("workbench.project.tags.title"),
83
+ description: t("workbench.project.tags.description"),
84
+ inputType: "tags",
85
+ field: "tags",
86
+ prependIcon: "tag-multiple",
87
+ },*/
88
+ ],
89
+ )
90
+ const validateForm = (): boolean => {
91
+ const validateAllFields = dynamicFormRef.value?.validateAllFields
92
+
93
+ if (validateAllFields) {
94
+ const isValid = !!validateAllFields()
95
+
96
+ return isValid
97
+ }
98
+ return true
99
+ }
100
+
101
+ const steps = computed<Step[]>(() => [
102
+ {
103
+ id: "config",
104
+ validator: validateForm,
105
+ },
106
+ ])
107
+ </script>
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <ProjectConfiguration
3
+ v-if="editableProject"
4
+ v-model="editableProject"
5
+ :disabled="isLoading"
6
+ is-editing
7
+ @save="onSubmit"
8
+ />
9
+ </template>
10
+
11
+ <script setup lang="ts">
12
+ import { clone } from "ramda"
13
+ import type { Project } from "@raclettejs/core"
14
+ import { usePluginApi } from "@raclettejs/core/orchestrator/composables"
15
+ import { onMounted, ref, toRaw } from "vue"
16
+ import ProjectConfiguration from "../components/ProjectConfiguration.vue"
17
+
18
+ const props = defineProps<{
19
+ uuid: string
20
+ }>()
21
+
22
+ const { $data } = usePluginApi("raclette__core")
23
+ const { $store } = usePluginApi()
24
+ const project = $store.get(["project"])
25
+
26
+ const { execute: executeUpdate, isLoading } = $data.project.update()
27
+
28
+ const editableProject = ref<Project>()
29
+
30
+ const onSubmit = async () => await executeUpdate(toRaw(editableProject.value))
31
+ onMounted(() => {
32
+ editableProject.value = clone({ config: {}, ...project.value })
33
+ })
34
+ </script>
@@ -0,0 +1,8 @@
1
+ export default {
2
+ name: "project",
3
+ author: "pacifico",
4
+ version: "0.0.1",
5
+ description: "A plugin for project configuration",
6
+ // Specify where the main frontend and backend entry points are
7
+ frontendDir: "./frontend",
8
+ }
@@ -8,6 +8,7 @@
8
8
  :data-name="$t('workbench.tagList.dataName')"
9
9
  :data-article="$t('workbench.tagList.dataArticle')"
10
10
  @delete="deleteTag"
11
+ :itemsDeleted="showDeleted"
11
12
  >
12
13
  <template #actions>
13
14
  <v-tooltip
@@ -29,6 +30,20 @@
29
30
  </template>
30
31
  </v-tooltip>
31
32
  </template>
33
+ <template #prepend-row-actions="{ item }">
34
+ <v-icon
35
+ v-if="showDeleted"
36
+ color="green"
37
+ class="mr-2"
38
+ @click="restore(item._id)"
39
+ :title="
40
+ $t('workbench.baseDataTable.restoreDataTitle', {
41
+ dataName: item.title,
42
+ })
43
+ "
44
+ icon="mdi-delete-restore"
45
+ />
46
+ </template>
32
47
  </BaseDataTable>
33
48
  </template>
34
49
 
@@ -79,7 +94,12 @@ const {
79
94
  const { execute: executeDelete } = $data.tag.delete({
80
95
  options: { cb: () => execute({ isDeleted: showDeleted.value }) },
81
96
  })
82
-
97
+ const { execute: executeHardDelete } = await $data.tag.deleteHard({
98
+ options: { cb: () => execute({ isDeleted: showDeleted.value }) },
99
+ })
100
+ const { execute: executeRestore } = await $data.tag.updateRestore({
101
+ options: { cb: () => execute({ isDeleted: showDeleted.value }) },
102
+ })
83
103
  const parsedTags = computed(() => {
84
104
  if (tags.value) {
85
105
  return Object.values(tags.value as { [key: string]: Tag }).map((tag) => ({
@@ -91,8 +111,16 @@ const parsedTags = computed(() => {
91
111
  return []
92
112
  })
93
113
 
94
- const deleteTag = async (tag: Tag) => await executeDelete({ _id: tag._id })
95
-
114
+ const deleteTag = async (tag: Tag) => {
115
+ if (showDeleted.value) {
116
+ await executeHardDelete({ _id: tag._id })
117
+ } else {
118
+ await executeDelete({ _id: tag._id })
119
+ }
120
+ }
121
+ const restore = async (_id: string) => {
122
+ executeRestore({ _id })
123
+ }
96
124
  $socket.on("tagCreated", () => execute({ isDeleted: showDeleted.value }))
97
125
  watch(
98
126
  showDeleted,
@@ -9,6 +9,7 @@
9
9
  :data-article="$t('workbench.userList.dataArticle')"
10
10
  :delete-validator="(user) => user._id !== $user?._id"
11
11
  @delete="deleteUser"
12
+ :itemsDeleted="showDeleted"
12
13
  >
13
14
  <template #actions>
14
15
  <v-tooltip
@@ -30,6 +31,20 @@
30
31
  </template>
31
32
  </v-tooltip>
32
33
  </template>
34
+ <template #prepend-row-actions="{ item }">
35
+ <v-icon
36
+ v-if="showDeleted"
37
+ color="green"
38
+ class="mr-2"
39
+ @click.stop.prevent="restore(item._id)"
40
+ :title="
41
+ $t('workbench.baseDataTable.restoreDataTitle', {
42
+ dataName: item.title,
43
+ })
44
+ "
45
+ icon="mdi-delete-restore"
46
+ />
47
+ </template>
33
48
  </BaseDataTable>
34
49
  </template>
35
50
 
@@ -78,11 +93,15 @@ const { data: users, execute, isLoading: usersLoading } = $data.user.getAll()
78
93
  const { data: tags, isLoading: tagsLoading } = $data.tag.getAll({
79
94
  options: { immediate: true },
80
95
  })
81
-
82
96
  const { execute: executeDelete } = $data.user.delete({
83
97
  options: { cb: () => execute({ isDeleted: showDeleted.value }) },
84
98
  })
85
-
99
+ const { execute: executeHardDelete } = await $data.user.deleteHard({
100
+ options: { cb: () => execute({ isDeleted: showDeleted.value }) },
101
+ })
102
+ const { execute: executeRestore } = await $data.user.updateRestore({
103
+ options: { cb: () => execute({ isDeleted: showDeleted.value }) },
104
+ })
86
105
  const parsedUsers = computed(() => {
87
106
  if (users.value && tags.value) {
88
107
  return Object.values(users.value as { [key: string]: User }).map(
@@ -95,9 +114,16 @@ const parsedUsers = computed(() => {
95
114
  }
96
115
  return []
97
116
  })
98
-
99
- const deleteUser = async (user: User) => await executeDelete({ _id: user._id })
100
-
117
+ const deleteUser = async (user: User) => {
118
+ if (showDeleted.value) {
119
+ await executeHardDelete({ _id: user._id })
120
+ } else {
121
+ await executeDelete({ _id: user._id })
122
+ }
123
+ }
124
+ const restore = async (_id: string) => {
125
+ executeRestore({ _id })
126
+ }
101
127
  $socket.on("userCreated", () => execute({ isDeleted: showDeleted.value }))
102
128
  watch(
103
129
  showDeleted,
@@ -62,9 +62,6 @@ export default defineRacletteConfig({
62
62
  },
63
63
  production: {},
64
64
  },
65
- global: {
66
- authTokenExpiryDays: 1,
67
- },
68
65
  frontend: {
69
66
  meta: {
70
67
  title: "Workbench",
@@ -35,7 +35,6 @@
35
35
  <!-- Additional action buttons slot -->
36
36
  <slot name="actions" />
37
37
  </div>
38
-
39
38
  <!-- Data Table -->
40
39
  <v-data-table
41
40
  v-model:search="search"
@@ -47,6 +46,7 @@
47
46
  :items="items"
48
47
  :loading="loading"
49
48
  @click:row="handleRowClick"
49
+ :class="{ itemsDeleted }"
50
50
  >
51
51
  <template
52
52
  #item.color="{ item }"
@@ -81,6 +81,7 @@
81
81
 
82
82
  <!-- Actions column template -->
83
83
  <template #item.actions="{ item }" v-if="showActionsColumn">
84
+ <slot name="prepend-row-actions" :item="item"> </slot>
84
85
  <slot name="row-actions" :item="item">
85
86
  <!-- Default delete action -->
86
87
  <v-icon
@@ -96,6 +97,7 @@
96
97
  icon="mdi-delete"
97
98
  />
98
99
  </slot>
100
+ <slot name="append-row-actions" :item="item"> </slot>
99
101
  </template>
100
102
 
101
103
  <!-- Loading template -->
@@ -168,7 +170,7 @@ export interface BaseDataTableProps<T> {
168
170
  // Data props
169
171
  items?: T[]
170
172
  loading?: boolean
171
-
173
+ itemsDeleted?: boolean
172
174
  // Table configuration
173
175
  headers: Array<{
174
176
  title: string
@@ -201,6 +203,7 @@ export interface BaseDataTableProps<T> {
201
203
  const props = withDefaults(defineProps<BaseDataTableProps<T>>(), {
202
204
  uuid: undefined,
203
205
  items: () => [],
206
+ itemsDeleted: false,
204
207
  itemsPerPage: 50,
205
208
  showCreateButton: true,
206
209
  showActionsColumn: true,
@@ -292,3 +295,9 @@ const isDeleteDisabled = (item: T): boolean => {
292
295
  return props.deleteValidator ? !props.deleteValidator(item) : false
293
296
  }
294
297
  </script>
298
+ <style lang="css">
299
+ .itemsDeleted .v-data-table__tr {
300
+ background-color: rgb(233, 190, 190);
301
+ color: #000;
302
+ }
303
+ </style>
@@ -25,6 +25,7 @@ const modelValue = defineModel<string | null>({ required: true })
25
25
  const { $data } = usePluginApi("raclette__core")
26
26
 
27
27
  const { data, query } = $data.composition.getAll({
28
+ params: { isDeleted: false },
28
29
  options: { immediate: true },
29
30
  })
30
31
 
@@ -23,9 +23,7 @@
23
23
  <div class="tw:grid tw:gap-2 tw:p-2">
24
24
  <template
25
25
  v-if="
26
- ['top-navigation', 'page-navigation', 'user-menu'].includes(
27
- trigger.type,
28
- )
26
+ ['app-bar', 'page-navigation', 'user-menu'].includes(trigger.type)
29
27
  "
30
28
  >
31
29
  <IconInput v-model="trigger.settings.icon" v-bind="$attrs" />
@@ -96,8 +94,8 @@ defineOptions({
96
94
 
97
95
  const modelValue = defineModel<Trigger[]>({ required: true })
98
96
 
99
- // TODO readd "top-navigation", "shortcut" once they are implemented
100
- const triggerTypes = ["page-navigation", "user-menu"] as const
97
+ // TODO readd "shortcut" once they are implemented
98
+ const triggerTypes = ["page-navigation", "user-menu", "app-bar"] as const
101
99
  const pageNavigationTypes = ["footerItem", "navItem"] as const
102
100
  const virtualTrigger = ref<Trigger>({
103
101
  type: "",
@@ -123,7 +121,7 @@ const createSettingsObject = (
123
121
  ): Trigger["settings"] => {
124
122
  if (
125
123
  triggerType === "page-navigation" ||
126
- triggerType === "top-navigation" ||
124
+ triggerType === "app-bar" ||
127
125
  triggerType === "user-menu"
128
126
  ) {
129
127
  const clickLink = {
package/yarn.lock CHANGED
@@ -476,10 +476,10 @@
476
476
  resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.9.tgz#d229a7b7f9dac167a156992ef23c7f023653f53b"
477
477
  integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==
478
478
 
479
- "@raclettejs/core@^0.1.16":
480
- version "0.1.16"
481
- resolved "https://registry.yarnpkg.com/@raclettejs/core/-/core-0.1.16.tgz#609ea04e6d398208080e4c19203a98300dacd872"
482
- integrity sha512-pxKhWC5L1w7HLvXR045Qrfk71m3gpQTn8mkbXxUDgNjYQcjVOQyKrOWkq3LRGwsZ0VzfMgnSagxB5uAhZVA7sQ==
479
+ "@raclettejs/core@^0.1.18":
480
+ version "0.1.18"
481
+ resolved "https://registry.yarnpkg.com/@raclettejs/core/-/core-0.1.18.tgz#6bf2a7de62996b3e2bc038b35e572467d2871130"
482
+ integrity sha512-jftqZLGoUm3CxG8UZ8nsF0vrQiZ+mhFdOglu+AdECEqi0Jr+2MbStEkHsz5RRKau6TXiT4Prmtv9/x1ZS8aGbQ==
483
483
  dependencies:
484
484
  chalk "5.6.2"
485
485
  chokidar "3.6.0"
@@ -492,10 +492,10 @@
492
492
  ramda "0.31.3"
493
493
  tsc-alias "1.8.16"
494
494
 
495
- "@raclettejs/types@^0.1.16":
496
- version "0.1.16"
497
- resolved "https://registry.yarnpkg.com/@raclettejs/types/-/types-0.1.16.tgz#9b8e6122c831b98822ec35bf90430dfb9a482aa6"
498
- integrity sha512-HUkh4CP5yny3IwgYIHSh3zbpzakJgzmuRO3obtutVADO8tmRi9SAnQQMXK5X+3A51ZicdB9VPuhmw1r/Iv1SZA==
495
+ "@raclettejs/types@^0.1.18":
496
+ version "0.1.18"
497
+ resolved "https://registry.yarnpkg.com/@raclettejs/types/-/types-0.1.18.tgz#7df0eb1b86db015694fabfafa089a277e654b350"
498
+ integrity sha512-mvQI2sO48z6+QKj/s5A5JMBKnY8piE+8D8N0soctfsU7tAKg8nEwlxOiQHZiqJyR1k+gX2p+VBMRGbxHCYAGFw==
499
499
  dependencies:
500
500
  "@types/node" "24.5.2"
501
501
  fastify "5.6.0"