@raclettejs/workbench 0.1.35 → 0.1.36-canary.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +10 -2
  2. package/config/compositions.js +18 -0
  3. package/config/interactionLinks.js +19 -0
  4. package/i18n/de-DE.json +15 -1
  5. package/i18n/en-EU.json +52 -1
  6. package/i18n/sk-SK.json +15 -1
  7. package/package.json +3 -4
  8. package/packages.json +3 -1
  9. package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/CompositionConfiguration.vue +96 -14
  10. package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/CompositionIntegration.vue +29 -1
  11. package/plugins/pacifico__compositions/frontend/components/compositionConfiguration/widgetsLayout/WidgetRenderer.vue +1 -6
  12. package/plugins/pacifico__compositions/frontend/composables/prefillInteractionLinkFromComposition.ts +54 -0
  13. package/plugins/pacifico__compositions/frontend/widgets/CompositionCreateWidget.vue +145 -9
  14. package/plugins/pacifico__compositions/frontend/widgets/CompositionEditWidget.vue +11 -2
  15. package/plugins/pacifico__compositions/frontend/widgets/CompositionListWidget.vue +25 -5
  16. package/plugins/pacifico__core/frontend/generated-config.ts +22 -0
  17. package/plugins/pacifico__interactionLinks/frontend/components/InteractionLinkConfiguration.vue +3 -65
  18. package/plugins/pacifico__plugins/frontend/widgets/PluginListWidget.vue +20 -3
  19. package/plugins/raclette__cache/backend/helpers/cacheEntryBuilder.ts +94 -0
  20. package/plugins/raclette__cache/backend/helpers/cacheEntrySanitizer.ts +86 -0
  21. package/plugins/raclette__cache/backend/helpers/valkeyExplorer.ts +89 -0
  22. package/plugins/raclette__cache/backend/index.ts +21 -0
  23. package/plugins/raclette__cache/backend/routes/route.cache.cacheEntries.get.ts +118 -0
  24. package/plugins/raclette__cache/backend/routes/route.cache.cacheEntry.get.ts +91 -0
  25. package/plugins/raclette__cache/backend/routes.ts +8 -0
  26. package/plugins/raclette__cache/frontend/components/TableColumnConfigDialog.vue +95 -0
  27. package/plugins/raclette__cache/frontend/composables/useTableColumnConfig.ts +66 -0
  28. package/plugins/raclette__cache/frontend/generated-config.ts +33 -0
  29. package/plugins/raclette__cache/frontend/utils/cacheValueTableRows.ts +340 -0
  30. package/plugins/raclette__cache/frontend/widgets/CacheListWidget.vue +742 -0
  31. package/plugins/raclette__cache/raclette.plugin.ts +8 -0
  32. package/services/frontend/src/app/components/dynamicForm/DynamicForm.vue +3 -1
  33. package/services/frontend/src/app/components/interactionLink/InteractionLinkBehaviorForm.vue +99 -0
  34. package/services/frontend/src/app/components/stepNavigator/StepNavigator.vue +175 -24
  35. package/services/frontend/src/app/components/stepNavigator/StepNavigatorTypes.ts +18 -0
  36. package/services/frontend/src/app/composables/useInteractionLinkBehaviorFields.ts +83 -0
  37. package/services/frontend/src/app/composables/useRacletteUserIsAdmin.ts +25 -0
  38. package/services/frontend/src/orchestrator/assets/styles/themes/light.ts +1 -1
@@ -0,0 +1,8 @@
1
+ export default {
2
+ name: "cache",
3
+ author: "raclette",
4
+ version: "0.0.1",
5
+ description: "Workbench admin tools for inspecting the shared Valkey cache",
6
+ backendDir: "./backend",
7
+ frontendDir: "./frontend",
8
+ }
@@ -6,7 +6,7 @@
6
6
  >
7
7
  <div class="tw:flex tw:min-h-0 tw:w-full tw:flex-col">
8
8
  <header
9
- v-if="title || routeBackInteractionLinkId"
9
+ v-if="!hideTitle && (title || routeBackInteractionLinkId)"
10
10
  class="tw:flex tw:items-center tw:justify-between tw:gap-3 tw:pt-3"
11
11
  >
12
12
  <div class="tw:flex tw:min-w-0 tw:items-center tw:gap-2">
@@ -86,6 +86,8 @@ const props = withDefaults(
86
86
  /** When false, constrains width (previous default). Default true fills the layout. */
87
87
  fluid?: boolean
88
88
  routeBackInteractionLinkId?: string
89
+ /** Hides title and inline back (e.g. when StepNavigator provides exit back) */
90
+ hideTitle?: boolean
89
91
  density?: "compact" | "comfortable" | "spacious"
90
92
  }>(),
91
93
  {
@@ -0,0 +1,99 @@
1
+ <template>
2
+ <div class="tw:box-border tw:flex tw:w-full tw:min-w-0 tw:flex-col">
3
+ <div v-if="intro" class="tw:grid tw:grid-cols-12 tw:px-4 tw:mdpx-5 tw:pt-3">
4
+ <div class="tw:col-span-12 tw:mb-2">
5
+ <v-alert type="info" variant="tonal" density="comfortable">
6
+ {{ intro }}
7
+ </v-alert>
8
+ </div>
9
+ </div>
10
+
11
+ <div
12
+ v-if="showLinkedComposition"
13
+ class="tw:grid tw:grid-cols-12 tw:rounded-md tw:p-2 tw:px-4 tw:mdpx-5"
14
+ >
15
+ <label class="tw:col-span-5 tw:py-2">
16
+ <div
17
+ class="tw:font-semibold tw:leading-5 tw:text-[color:rgb(var(--v-theme-on-surface))]"
18
+ >
19
+ {{ $t("workbench.interactionLinkConfiguration.composition.title") }}
20
+ </div>
21
+ <div
22
+ class="tw:mt-1 tw:max-w-prose tw:leading-snug tw:text-[color:rgb(var(--v-theme-on-surface))] tw:opacity-80 tw:text-sm"
23
+ >
24
+ {{
25
+ $t(
26
+ "workbench.compositionConfiguration.integration.linkedCompositionDescription",
27
+ )
28
+ }}
29
+ </div>
30
+ </label>
31
+ <div class="tw:col-span-7 tw:flex tw:items-center">
32
+ <v-text-field
33
+ :model-value="linkedCompositionTitle"
34
+ readonly
35
+ variant="outlined"
36
+ density="comfortable"
37
+ hide-details
38
+ prepend-inner-icon="mdi-file-document-outline"
39
+ class="tw:w-full"
40
+ />
41
+ </div>
42
+ </div>
43
+
44
+ <!-- @vue-generic {InteractionLinkCreate | InteractionLinkUpdate} -->
45
+ <DynamicForm
46
+ ref="dynamicFormRef"
47
+ v-model="interactionLink"
48
+ :data="behaviorFields"
49
+ :disabled
50
+ :fluid="fluid"
51
+ :validate-on-change="false"
52
+ :title="title"
53
+ />
54
+ </div>
55
+ </template>
56
+
57
+ <script setup lang="ts">
58
+ import type {
59
+ InteractionLinkCreate,
60
+ InteractionLinkUpdate,
61
+ } from "@raclettejs/core"
62
+ import DynamicForm from "@app/components/dynamicForm/DynamicForm.vue"
63
+ import { useTemplateRef } from "vue"
64
+ import { useInteractionLinkBehaviorFields } from "@app/composables/useInteractionLinkBehaviorFields"
65
+
66
+ withDefaults(
67
+ defineProps<{
68
+ disabled?: boolean
69
+ title?: string
70
+ fluid?: boolean
71
+ intro?: string
72
+ showLinkedComposition?: boolean
73
+ linkedCompositionTitle?: string
74
+ }>(),
75
+ {
76
+ fluid: true,
77
+ showLinkedComposition: false,
78
+ },
79
+ )
80
+
81
+ const interactionLink = defineModel<
82
+ InteractionLinkCreate | InteractionLinkUpdate
83
+ >({ required: true })
84
+
85
+ const dynamicFormRef = useTemplateRef("dynamicFormRef")
86
+ const { behaviorFields } = useInteractionLinkBehaviorFields()
87
+
88
+ const validate = (): boolean => {
89
+ const validateAllFields = dynamicFormRef.value?.validateAllFields
90
+
91
+ if (validateAllFields) {
92
+ return !!validateAllFields()
93
+ }
94
+
95
+ return true
96
+ }
97
+
98
+ defineExpose({ validate })
99
+ </script>
@@ -7,8 +7,25 @@
7
7
  permanent
8
8
  :width="NAVIGATION_HEIGHT"
9
9
  >
10
- <div class="tw:size-full tw:flex tw:items-center tw:align-center">
11
- <div class="tw:overflow-x-auto tw:w-full">
10
+ <div
11
+ class="tw:flex tw:size-full tw:w-full tw:items-center"
12
+ :class="showExitBack ? 'tw:gap-1 tw:px-2' : ''"
13
+ >
14
+ <div
15
+ v-if="showExitBack"
16
+ class="tw:flex tw:size-12 tw:flex-shrink-0 tw:items-center tw:justify-center"
17
+ >
18
+ <v-btn
19
+ v-if="isFirstStep"
20
+ @click="onExitBack"
21
+ :disabled="isSaving"
22
+ icon="mdi-chevron-left"
23
+ variant="text"
24
+ :aria-label="$t('workbench.global.back')"
25
+ />
26
+ </div>
27
+
28
+ <div class="tw:min-w-0 tw:flex-1 tw:overflow-x-auto">
12
29
  <div
13
30
  class="tw:flex tw:items-center tw:justify-center tw:min-w-max tw:px-4"
14
31
  >
@@ -19,8 +36,10 @@
19
36
  @click="
20
37
  allowFreeNavigation ? setCurrentStep(index + 1) : null
21
38
  "
22
- class="tw:flex tw:items-center tw:cursor-pointer tw:transition-all tw:duration-200 tw:group tw:flex-shrink-0"
39
+ class="tw:flex tw:items-center tw:transition-all tw:duration-200 tw:group tw:flex-shrink-0"
23
40
  :class="{
41
+ 'tw:cursor-pointer': allowFreeNavigation,
42
+ 'tw:cursor-default': !allowFreeNavigation,
24
43
  'tw:opacity-100': currentStepIndex >= index + 1,
25
44
  'tw:opacity-60':
26
45
  currentStepIndex < index + 1 &&
@@ -31,11 +50,15 @@
31
50
  <div
32
51
  class="tw:w-10 tw:h-10 tw:rounded-full tw:flex tw:items-center tw:justify-center tw:transition-all tw:duration-200 tw:border-2"
33
52
  :class="{
34
- 'tw:bg-[#DD8B41] tw:border-[#DD8B41] tw:text-white':
53
+ 'tw:bg-[color:rgb(var(--v-theme-primary))] tw:border-[color:rgb(var(--v-theme-primary-darken-1))] tw:text-white':
35
54
  currentStepIndex === index + 1,
36
55
  'tw:bg-green-500 tw:border-green-500 tw:text-white':
37
56
  currentStepIndex > index + 1,
38
- 'tw:bg-white tw:border-gray-300 tw:text-gray-500 group-hover:tw:border-blue-300':
57
+ 'tw:bg-white tw:border-gray-300 tw:text-gray-500':
58
+ currentStepIndex !== index + 1 &&
59
+ currentStepIndex < index + 1,
60
+ 'group-hover:tw:border-blue-300':
61
+ allowFreeNavigation &&
39
62
  currentStepIndex !== index + 1 &&
40
63
  currentStepIndex < index + 1,
41
64
  }"
@@ -56,17 +79,20 @@
56
79
  v-if="step.title"
57
80
  class="tw:text-sm tw:font-medium tw:transition-colors tw:duration-200 tw:whitespace-nowrap"
58
81
  :class="{
59
- 'tw:text-[#DD8B41]': currentStepIndex === index + 1,
82
+ 'tw:text-[color:rgb(var(--v-theme-primary-darken-2))] tw:dark:text-[color:rgb(var(--v-theme-primary))]':
83
+ currentStepIndex === index + 1,
60
84
  'tw:text-green-600': currentStepIndex > index + 1,
61
- 'tw:text-gray-600 group-hover:tw:text-blue-600':
85
+ 'tw:text-gray-500 tw:dark:text-gray-300':
62
86
  currentStepIndex !== index + 1,
87
+ 'group-hover:tw:text-blue-600':
88
+ allowFreeNavigation && currentStepIndex !== index + 1,
63
89
  }"
64
90
  >
65
91
  {{ step.title }}
66
92
  </div>
67
93
  <div
68
94
  v-if="step.subtitle"
69
- class="tw:text-xs tw:text-gray-500 tw:whitespace-nowrap"
95
+ class="tw:text-xs tw:text-gray-500 tw:dark:text-gray-400 tw:whitespace-nowrap"
70
96
  >
71
97
  {{ step.subtitle }}
72
98
  </div>
@@ -86,22 +112,27 @@
86
112
  </div>
87
113
  </div>
88
114
  </div>
115
+
116
+ <!-- Spacer to make sure content is still centered -->
117
+ <div
118
+ v-if="showExitBack"
119
+ class="tw:w-12 tw:flex-shrink-0"
120
+ aria-hidden="true"
121
+ />
89
122
  </div>
90
123
  </v-navigation-drawer>
91
124
 
92
- <!-- Step Content Container -->
93
- <!-- <div class="tw:min-h-full"> -->
94
125
  <slot v-bind="{ currentStep, currentStepIndex }" />
95
126
  <!-- </div> -->
96
127
 
97
128
  <v-navigation-drawer location="bottom" permanent :width="84">
98
129
  <div
99
- class="tw:flex tw:h-full tw:items-center tw:justify-between tw:container tw:mx-auto tw:px-4"
130
+ class="tw:flex tw:h-full tw:items-center tw:justify-between tw:mx-auto tw:px-4"
100
131
  >
101
132
  <!-- Left side - Back button -->
102
133
  <div>
103
134
  <v-btn
104
- v-if="steps.length > 1"
135
+ v-if="showFooterBackButton"
105
136
  @click="previousStep"
106
137
  :disabled="isFirstStep || isSaving"
107
138
  color="primary"
@@ -122,8 +153,22 @@
122
153
  :text="$t('workbench.global.save')"
123
154
  />
124
155
 
156
+ <template v-if="currentSecondaryActions.length">
157
+ <v-btn
158
+ v-for="action in currentSecondaryActions"
159
+ :key="action.id"
160
+ @click="onCustomAction(action.id, action.skipValidation)"
161
+ :disabled="isSaving"
162
+ :color="action.color ?? 'primary'"
163
+ :variant="action.variant ?? 'outlined'"
164
+ :prepend-icon="action.prependIcon"
165
+ :append-icon="action.appendIcon"
166
+ :text="$t(action.labelKey)"
167
+ />
168
+ </template>
169
+
125
170
  <v-btn
126
- v-if="!isLastStep"
171
+ v-if="showDefaultNextButton"
127
172
  @click="nextStep()"
128
173
  :disabled="isSaving"
129
174
  color="primary"
@@ -132,7 +177,19 @@
132
177
  />
133
178
 
134
179
  <v-btn
135
- v-else-if="!showSaveButton"
180
+ v-else-if="showCustomPrimaryButton"
181
+ @click="onCustomAction(currentStep!.primaryActionId!)"
182
+ :disabled="isSaving"
183
+ :loading="isSaving"
184
+ :color="currentStepPrimaryColor"
185
+ variant="flat"
186
+ :prepend-icon="currentStepPrimaryPrependIcon"
187
+ :append-icon="currentStepPrimaryAppendIcon"
188
+ :text="currentStepPrimaryLabel"
189
+ />
190
+
191
+ <v-btn
192
+ v-else-if="showDefaultFinishButton"
136
193
  @click="save(true)"
137
194
  :disabled="isSaving"
138
195
  :loading="isSaving"
@@ -148,7 +205,9 @@
148
205
 
149
206
  <script setup lang="ts">
150
207
  import { ref, computed, watch } from "vue"
151
- import { Step, StepChangeType } from "./StepNavigatorTypes"
208
+ import { useI18n } from "vue-i18n"
209
+ import { useRouteState } from "@raclettejs/core/orchestrator/composables"
210
+ import { Step, StepChangeType, StepFooterAction } from "./StepNavigatorTypes"
152
211
 
153
212
  const NAVIGATION_HEIGHT = 84
154
213
 
@@ -161,6 +220,14 @@ const props = withDefaults(
161
220
  canFinish?: boolean
162
221
  isSaving?: boolean
163
222
  showSaveButton?: boolean
223
+ /** When true, Next is shown on non-last steps even if `showSaveButton` is enabled */
224
+ showNextWithSave?: boolean
225
+ /** When true with `showSaveButton`, last step shows Save & Finish in addition to Save */
226
+ showFinishOnLastStep?: boolean
227
+ /** Back + title above content on the first step (e.g. return to list) */
228
+ showExitBack?: boolean
229
+ headerTitle?: string
230
+ exitBackInteractionLinkId?: string
164
231
  paddingTop?: boolean
165
232
  paddingBottom?: boolean
166
233
  }>(),
@@ -177,14 +244,79 @@ const emit = defineEmits<{
177
244
  "validation-failed": [{ step: Step; stepIndex: number }]
178
245
  save: [void]
179
246
  "save-and-finish": [void]
247
+ "custom-action": [string]
248
+ "exit-back": [void]
180
249
  }>()
181
250
 
251
+ const { t } = useI18n()
252
+ const { triggerInteractionLinkById } = useRouteState()
253
+
182
254
  const currentStepIndex = ref(props.initialStep)
183
255
 
184
256
  const currentStep = computed(() => props.steps[currentStepIndex.value - 1])
185
257
  const isFirstStep = computed(() => currentStepIndex.value === 1)
186
258
  const isLastStep = computed(() => currentStepIndex.value === props.steps.length)
187
259
 
260
+ const showFooterBackButton = computed(
261
+ () => props.steps.length > 1 && !currentStep.value?.disableFooterBack,
262
+ )
263
+
264
+ const showDefaultNextButton = computed(() => {
265
+ if (isLastStep.value || currentStep.value?.primaryAction === "custom") {
266
+ return false
267
+ }
268
+
269
+ if (props.showNextWithSave) {
270
+ return true
271
+ }
272
+
273
+ return !props.showSaveButton
274
+ })
275
+
276
+ const showCustomPrimaryButton = computed(
277
+ () => currentStep.value?.primaryAction === "custom",
278
+ )
279
+
280
+ const showDefaultFinishButton = computed(() => {
281
+ if (!isLastStep.value || currentStep.value?.primaryAction === "custom") {
282
+ return false
283
+ }
284
+
285
+ if (props.showFinishOnLastStep) {
286
+ return true
287
+ }
288
+
289
+ return !props.showSaveButton
290
+ })
291
+
292
+ const currentStepPrimaryLabel = computed(() =>
293
+ currentStep.value?.primaryLabelKey
294
+ ? t(currentStep.value.primaryLabelKey)
295
+ : "",
296
+ )
297
+
298
+ const currentStepPrimaryColor = computed(() =>
299
+ isLastStep.value && currentStep.value?.primaryAction === "custom"
300
+ ? "success"
301
+ : "primary",
302
+ )
303
+
304
+ const currentStepPrimaryPrependIcon = computed(() =>
305
+ isLastStep.value && currentStep.value?.primaryAction === "custom"
306
+ ? "mdi-check"
307
+ : undefined,
308
+ )
309
+
310
+ const currentStepPrimaryAppendIcon = computed(() =>
311
+ !isLastStep.value && currentStep.value?.primaryAction === "custom"
312
+ ? "mdi-chevron-right"
313
+ : undefined,
314
+ )
315
+
316
+ const currentSecondaryActions = computed<StepFooterAction[]>(
317
+ () => currentStep.value?.secondaryActions ?? [],
318
+ )
319
+
188
320
  const isStepAccessible = (stepNumber: number) => {
189
321
  if (props.allowFreeNavigation) return true
190
322
 
@@ -208,7 +340,10 @@ const validateCurrentStep = () => {
208
340
  }
209
341
  }
210
342
 
211
- const setCurrentStep = (step: number) => {
343
+ const setCurrentStep = (
344
+ step: number,
345
+ options?: { skipValidation?: boolean },
346
+ ) => {
212
347
  if (currentStepIndex.value === step) {
213
348
  // Step is already active
214
349
  return
@@ -219,13 +354,8 @@ const setCurrentStep = (step: number) => {
219
354
  return
220
355
  }
221
356
 
222
- // // Validate step access
223
- // if (!isStepAccessible(step)) {
224
- // return
225
- // }
226
-
227
357
  // If moving forward (not backward), validate current step first
228
- if (step > currentStepIndex.value) {
358
+ if (!options?.skipValidation && step > currentStepIndex.value) {
229
359
  const isValid = validateCurrentStep()
230
360
  if (!isValid) {
231
361
  emit("validation-failed", {
@@ -249,6 +379,18 @@ const setCurrentStep = (step: number) => {
249
379
  })
250
380
  }
251
381
 
382
+ const onCustomAction = (actionId: string, skipValidation = false) => {
383
+ if (!skipValidation && !validateCurrentStep()) {
384
+ emit("validation-failed", {
385
+ step: currentStep.value,
386
+ stepIndex: currentStepIndex.value - 1,
387
+ })
388
+ return
389
+ }
390
+
391
+ emit("custom-action", actionId)
392
+ }
393
+
252
394
  const save = (finish = false) => {
253
395
  if (validateCurrentStep()) {
254
396
  if (finish) {
@@ -259,9 +401,18 @@ const save = (finish = false) => {
259
401
  }
260
402
  }
261
403
 
404
+ const onExitBack = () => {
405
+ if (props.exitBackInteractionLinkId) {
406
+ triggerInteractionLinkById(props.exitBackInteractionLinkId)
407
+ return
408
+ }
409
+
410
+ emit("exit-back")
411
+ }
412
+
262
413
  // Public methods (exposed to parent)
263
- const goToStep = (step) => {
264
- setCurrentStep(step)
414
+ const goToStep = (step: number, options?: { skipValidation?: boolean }) => {
415
+ setCurrentStep(step, options)
265
416
  }
266
417
 
267
418
  const nextStep = () => {
@@ -1,8 +1,26 @@
1
+ export type StepFooterAction = {
2
+ id: string
3
+ labelKey: string
4
+ color?: string
5
+ variant?: "flat" | "outlined" | "text" | "elevated" | "tonal" | "plain"
6
+ prependIcon?: string
7
+ appendIcon?: string
8
+ /** When true, the action does not run the step validator before emitting */
9
+ skipValidation?: boolean
10
+ }
11
+
1
12
  export type Step<T = string> = {
2
13
  id: T
3
14
  title?: string
4
15
  subtitle?: string
5
16
  validator?: () => boolean
17
+ /** Primary footer button: `next` (default for non-last steps) or `custom` */
18
+ primaryAction?: "next" | "custom"
19
+ primaryActionId?: string
20
+ primaryLabelKey?: string
21
+ secondaryActions?: StepFooterAction[]
22
+ /** When true, the footer Back button is hidden on this step */
23
+ disableFooterBack?: boolean
6
24
  }
7
25
 
8
26
  export type StepChangeType<T = string> = {
@@ -0,0 +1,83 @@
1
+ import type {
2
+ InteractionLinkCreate,
3
+ InteractionLinkUpdate,
4
+ } from "@raclettejs/core"
5
+ import type { DynamicFormItem } from "@app/components/dynamicForm/DynamicFormTypes"
6
+ import {
7
+ DEFAULT_SLOT_NAME,
8
+ DEFAULT_INLINE_SLOT_NAME,
9
+ DEFAULT_MODAL_SLOT_NAME,
10
+ } from "@raclettejs/core/orchestrator/router/routeParserHelper"
11
+ import { computed } from "vue"
12
+ import { useI18n } from "vue-i18n"
13
+
14
+ export const useInteractionLinkBehaviorFields = () => {
15
+ const { t } = useI18n()
16
+
17
+ const behaviorFields = computed<
18
+ DynamicFormItem<InteractionLinkCreate | InteractionLinkUpdate>[]
19
+ >(() => [
20
+ {
21
+ title: t("workbench.interactionLinkConfiguration.description.title"),
22
+ description: t(
23
+ "workbench.interactionLinkConfiguration.description.description",
24
+ ),
25
+ inputType: "textarea",
26
+ field: "description",
27
+ prependIcon: "text",
28
+ },
29
+ {
30
+ title: t("workbench.interactionLinkConfiguration.tags.title"),
31
+ description: t("workbench.interactionLinkConfiguration.tags.description"),
32
+ inputType: "tags",
33
+ field: "tags",
34
+ prependIcon: "tag-multiple",
35
+ },
36
+ {
37
+ divider: t("workbench.interactionLinkConfiguration.dividers.behavior"),
38
+ },
39
+ {
40
+ title: t("workbench.interactionLinkConfiguration.slotType.title"),
41
+ description: t(
42
+ "workbench.interactionLinkConfiguration.slotType.description",
43
+ ),
44
+ inputType: "select",
45
+ field: "slotType",
46
+ selectItems: [
47
+ DEFAULT_SLOT_NAME,
48
+ DEFAULT_MODAL_SLOT_NAME,
49
+ DEFAULT_INLINE_SLOT_NAME,
50
+ ],
51
+ prependIcon: "dock-window",
52
+ validation: {
53
+ required: true,
54
+ },
55
+ },
56
+ {
57
+ title: t("workbench.interactionLinkConfiguration.triggers.title"),
58
+ description: t(
59
+ "workbench.interactionLinkConfiguration.triggers.description",
60
+ ),
61
+ inputType: "triggers",
62
+ field: "triggers",
63
+ },
64
+ {
65
+ title: t("workbench.interactionLinkConfiguration.queryParameters.title"),
66
+ description: t(
67
+ "workbench.interactionLinkConfiguration.queryParameters.description",
68
+ ),
69
+ inputType: "list",
70
+ field: "queryParameters",
71
+ },
72
+ {
73
+ title: t("workbench.interactionLinkConfiguration.isLandingPage.title"),
74
+ description: t(
75
+ "workbench.interactionLinkConfiguration.isLandingPage.description",
76
+ ),
77
+ inputType: "switch",
78
+ field: "isLandingPage",
79
+ },
80
+ ])
81
+
82
+ return { behaviorFields }
83
+ }
@@ -0,0 +1,25 @@
1
+ import type { User } from "@raclettejs/core"
2
+ import {
3
+ isSystemAdminTag,
4
+ userHasAdminTag,
5
+ } from "@shared/helper/adminTag"
6
+ import { usePluginApi } from "@raclettejs/core/orchestrator/composables"
7
+ import { computed } from "vue"
8
+
9
+ export const useRacletteUserIsAdmin = () => {
10
+ const { $data } = usePluginApi("raclette__core")
11
+
12
+ const { data: tags, isLoading: tagsLoading } = $data.tag.getAll({
13
+ options: { immediate: true },
14
+ })
15
+
16
+ const adminTag = computed(() => {
17
+ if (!tags.value) return undefined
18
+ return Object.values(tags.value).find(isSystemAdminTag)
19
+ })
20
+
21
+ const isRacletteUserAdmin = (user: User | null | undefined): boolean =>
22
+ userHasAdminTag(user, adminTag.value)
23
+
24
+ return { isRacletteUserAdmin, adminTag, tagsLoading }
25
+ }
@@ -6,7 +6,7 @@ export default {
6
6
  surface: "#ffffff",
7
7
  "surface-light": "#ffffff",
8
8
  primary: "#DD8B41",
9
- "primary-darken-1": "#B26F34",
9
+ "primary-darken-1": "#DA7C2B",
10
10
  "primary-darken-2": "#9D612E",
11
11
  "primary-darken-3": "#875428",
12
12
  "primary-darken-4": "#724622",