@raclettejs/workbench 0.1.17 → 0.1.19

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,140 @@
1
+ <template>
2
+ <!-- Dialog overlay -->
3
+ <div
4
+ v-if="dialog"
5
+ class="tw:fixed tw:inset-0 tw:flex tw:items-center tw:justify-center tw:bg-black/50 tw:z-50"
6
+ >
7
+ <!-- Dialog panel -->
8
+ <div
9
+ class="tw:bg-white tw:rounded-lg tw:shadow-xl tw:max-w-md tw:w-full tw:overflow-auto tw:h-[80%]"
10
+ >
11
+ <!-- Title bar -->
12
+ <div
13
+ class="tw:flex tw:justify-between tw:items-center tw:px-4 tw:py-3 tw:border-b tw:border-gray-200"
14
+ >
15
+ <span class="tw:text-lg tw:font-semibold">{{ title }}</span>
16
+
17
+ <button
18
+ @click="close"
19
+ class="tw:text-gray-500 hover:tw:text-gray-700 tw:p-1 tw:rounded tw:hover:bg-gray-100"
20
+ >
21
+ <i class="mdi mdi-close tw:text-xl"></i>
22
+ </button>
23
+ </div>
24
+
25
+ <!-- Content -->
26
+ <div class="tw:px-4 tw:py-4">
27
+ <!-- Alert -->
28
+ <div
29
+ :class="[
30
+ 'tw:rounded tw:p-4 tw:mb-4',
31
+ type === 'error' && 'tw:bg-red-50 tw:text-red-700',
32
+ type === 'warning' && 'tw:bg-yellow-50 tw:text-yellow-700',
33
+ type === 'info' && 'tw:bg-blue-50 tw:text-blue-700',
34
+ type === 'success' && 'tw:bg-green-50 tw:text-green-700',
35
+ ]"
36
+ >
37
+ <div class="tw:text-lg tw:font-medium tw:mb-2">
38
+ {{ message }}
39
+ </div>
40
+
41
+ <div class="tw:text-sm">
42
+ {{ $t("core.itemsCount") }}:
43
+ <strong>{{ itemCount }}</strong>
44
+ </div>
45
+ </div>
46
+
47
+ <!-- List -->
48
+ <div v-if="showItems && items.length > 0" class="tw:mt-4">
49
+ <div
50
+ class="tw:text-xs tw:uppercase tw:font-semibold tw:text-gray-500 tw:mb-2"
51
+ >
52
+ {{ $t("core.selectedItems") }}
53
+ </div>
54
+
55
+ <ul class="tw:space-y-1">
56
+ <li
57
+ v-for="item in items"
58
+ :key="item._id"
59
+ class="tw:px-3 tw:py-2 tw:bg-gray-50 tw:rounded tw:text-sm tw:text-gray-700"
60
+ >
61
+ {{ getDisplayValue(item) }}
62
+ </li>
63
+ </ul>
64
+ </div>
65
+ </div>
66
+
67
+ <!-- Actions -->
68
+ <div
69
+ class="tw:flex tw:justify-end tw:space-x-2 tw:px-4 tw:py-3 tw:border-t tw:border-gray-200"
70
+ >
71
+ <button
72
+ @click="close"
73
+ class="tw:px-4 tw:py-2 tw:text-sm tw:text-gray-700 hover:tw:bg-gray-100 tw:rounded"
74
+ >
75
+ {{ cancelText || $t("core.close") }}
76
+ </button>
77
+
78
+ <button
79
+ v-if="showConfirm"
80
+ @click="confirm"
81
+ :class="[
82
+ 'tw:px-4 tw:py-2 tw:text-sm tw:rounded tw:text-white',
83
+ type === 'error' && 'tw:bg-red-600 hover:tw:bg-red-700',
84
+ type === 'warning' && 'tw:bg-yellow-600 hover:tw:bg-yellow-700',
85
+ type === 'info' && 'tw:bg-blue-600 hover:tw:bg-blue-700',
86
+ type === 'success' && 'tw:bg-green-600 hover:tw:bg-green-700',
87
+ ]"
88
+ >
89
+ {{ confirmText }}
90
+ </button>
91
+ </div>
92
+ </div>
93
+ </div>
94
+ </template>
95
+
96
+ <script setup lang="ts">
97
+ import { computed } from "vue"
98
+
99
+ interface Props {
100
+ modelValue: boolean
101
+ items: any[]
102
+ title: string
103
+ message: string
104
+ type?: "info" | "success" | "warning" | "error"
105
+ showItems?: boolean
106
+ showConfirm?: boolean
107
+ displayAttribute: string
108
+ confirmText?: string
109
+ cancelText?: string
110
+ }
111
+
112
+ const props = withDefaults(defineProps<Props>(), {
113
+ type: "info",
114
+ showItems: true,
115
+ showConfirm: false,
116
+ })
117
+
118
+ const emit = defineEmits<{
119
+ "update:modelValue": [value: boolean]
120
+ confirm: []
121
+ }>()
122
+
123
+ const dialog = computed({
124
+ get: () => props.modelValue,
125
+ set: (value) => emit("update:modelValue", value),
126
+ })
127
+
128
+ const itemCount = computed(() => props.items.length)
129
+
130
+ const close = () => {
131
+ dialog.value = false
132
+ }
133
+ const getDisplayValue = (item: any) => {
134
+ return item[props.displayAttribute] || item._id
135
+ }
136
+ const confirm = () => {
137
+ emit("confirm")
138
+ close()
139
+ }
140
+ </script>
@@ -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 = {
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Downloads a JSON object as a .json file
3
+ * @param {Object|Array} data - The data to be downloaded as JSON
4
+ * @param {string} filename - The name of the file (without .json extension)
5
+ * @throws {Error} If data cannot be serialized to JSON
6
+ */
7
+ export function downloadJson(data, filename = "download") {
8
+ try {
9
+ // Convert data to JSON string with pretty formatting
10
+ const jsonString = JSON.stringify(data, null, 2)
11
+
12
+ // Create blob from JSON string
13
+ const blob = new Blob([jsonString], { type: "application/json" })
14
+
15
+ // Create download link
16
+ const url = URL.createObjectURL(blob)
17
+ const link = document.createElement("a")
18
+
19
+ // Ensure filename has .json extension
20
+ const normalizedFilename = filename.endsWith(".json")
21
+ ? filename
22
+ : `${filename}.json`
23
+
24
+ link.href = url
25
+ link.download = normalizedFilename
26
+
27
+ // Trigger download
28
+ document.body.appendChild(link)
29
+ link.click()
30
+
31
+ // Cleanup
32
+ document.body.removeChild(link)
33
+ URL.revokeObjectURL(url)
34
+ } catch (error) {
35
+ console.error("Failed to download JSON:", error)
36
+ throw new Error(`Unable to download JSON file: ${error.message}`)
37
+ }
38
+ }
39
+ /**
40
+ * Recursively maps values in a JSON object based on a mapping configuration
41
+ * @param {Object|Array} data - The source JSON data to transform
42
+ * @param {Object} mapping - Mapping object where keys are attribute names and values are replacement values
43
+ * @returns {Object|Array} New object with mapped values
44
+ * @throws {Error} If data cannot be processed
45
+ *
46
+ * @example
47
+ * const data = { owner: 'user123', name: 'Project A', lastEditor: 'user123' };
48
+ * const mapping = { owner: 'user456', lastEditor: 'user789' };
49
+ * const result = mapJsonValues(data, mapping);
50
+ * // Result: { owner: 'user456', name: 'Project A', lastEditor: 'user789' }
51
+ */
52
+ export function mapJsonValues(data, mapping = {}) {
53
+ if (!data || typeof data !== "object") {
54
+ return data
55
+ }
56
+
57
+ // Handle arrays
58
+ if (Array.isArray(data)) {
59
+ return data.map((item) => mapJsonValues(item, mapping))
60
+ }
61
+
62
+ // Handle objects
63
+ const result = {}
64
+
65
+ for (const [key, value] of Object.entries(data)) {
66
+ // If this key exists in mapping, use the mapped value
67
+ if (key in mapping) {
68
+ result[key] = mapping[key]
69
+ }
70
+ // If value is an object or array, recursively process it
71
+ else if (value && typeof value === "object") {
72
+ result[key] = mapJsonValues(value, mapping)
73
+ }
74
+ // Otherwise keep the original value
75
+ else {
76
+ result[key] = value
77
+ }
78
+ }
79
+
80
+ return result
81
+ }
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.17":
480
- version "0.1.17"
481
- resolved "https://registry.yarnpkg.com/@raclettejs/core/-/core-0.1.17.tgz#36712a73791a5115b09c50fcbe8856793dd9ed9c"
482
- integrity sha512-dMUW+/TikBRbZ4gOEvmSlwKJyRtvvGyJ9VFvhTbvYPMTjmnT/OzOIN9WMj6wG8b2tYFSNWtq+RNSQuc/G/nLxw==
479
+ "@raclettejs/core@^0.1.19":
480
+ version "0.1.19"
481
+ resolved "https://registry.yarnpkg.com/@raclettejs/core/-/core-0.1.19.tgz#a95b033cc297d2f9d6f6f9e7251e8aa71c58bf42"
482
+ integrity sha512-hScs5MuRiUUUuEcdd/DTrUUX5ohlHTnMTMuMZnxXwvLOciWbkxob++CQn/FOmdjzmC1PEoS+pEalVKor5FHVAA==
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.17":
496
- version "0.1.17"
497
- resolved "https://registry.yarnpkg.com/@raclettejs/types/-/types-0.1.17.tgz#ced377e5fa8879a5790b1c0c838f621917032690"
498
- integrity sha512-WBhi6Nf/XJPlisF1stEB0KGo5TWw+EMaTuYt39fJKc+Vtyf/SFmZqP2D3BKlssE5N/8bo2DFgf2qUeKowo0onA==
495
+ "@raclettejs/types@^0.1.19":
496
+ version "0.1.19"
497
+ resolved "https://registry.yarnpkg.com/@raclettejs/types/-/types-0.1.19.tgz#5f17afcc3b8f2d4849c828648711c426fdb2f74d"
498
+ integrity sha512-EdIMglaM+ivsvkVaXZKVKBoyXsLivulloveYPEV70Lm1iLeja6l7IywyM82dMdEgNMmpEMlG8r2TjHyXu9MPkg==
499
499
  dependencies:
500
500
  "@types/node" "24.5.2"
501
501
  fastify "5.6.0"