@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.
- package/CHANGELOG.md +19 -0
- package/config/compositions.js +18 -14
- package/config/interactionLinks.js +30 -10
- package/i18n/de-DE.json +27 -1
- package/i18n/en-EU.json +27 -1
- package/i18n/sk-SK.json +26 -0
- package/package.json +3 -3
- package/plugins/pacifico__compositions/frontend/widgets/CompositionListWidget.vue +207 -45
- package/plugins/pacifico__interactionLinks/frontend/widgets/InteractionLinkListWidget.vue +226 -42
- package/plugins/pacifico__project/frontend/components/ProjectConfiguration.vue +107 -0
- package/plugins/pacifico__project/frontend/widgets/ProjectDetailWidget.vue +34 -0
- package/plugins/pacifico__project/raclette.plugin.ts +8 -0
- package/plugins/pacifico__tags/frontend/widgets/TagListWidget.vue +203 -34
- package/plugins/pacifico__users/frontend/widgets/UserListWidget.vue +20 -2
- package/raclette.config.js +0 -3
- package/services/frontend/src/app/components/BaseDataTable.vue +3 -0
- package/services/frontend/src/app/components/FileUpload.vue +98 -0
- package/services/frontend/src/app/components/SelectionDialog.vue +182 -0
- package/services/frontend/src/app/components/SummaryDialog.vue +140 -0
- package/services/frontend/src/app/components/dynamicForm/typedInputs/CompositionInput.vue +1 -0
- package/services/frontend/src/app/components/dynamicForm/typedInputs/TriggerInput.vue +4 -6
- package/services/frontend/src/app/lib/jsonTools.ts +81 -0
- package/yarn.lock +8 -8
|
@@ -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>
|
|
@@ -23,9 +23,7 @@
|
|
|
23
23
|
<div class="tw:grid tw:gap-2 tw:p-2">
|
|
24
24
|
<template
|
|
25
25
|
v-if="
|
|
26
|
-
['
|
|
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
|
|
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 === "
|
|
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
|
|
480
|
-
version "0.1.
|
|
481
|
-
resolved "https://registry.yarnpkg.com/@raclettejs/core/-/core-0.1.
|
|
482
|
-
integrity sha512-
|
|
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
|
|
496
|
-
version "0.1.
|
|
497
|
-
resolved "https://registry.yarnpkg.com/@raclettejs/types/-/types-0.1.
|
|
498
|
-
integrity sha512-
|
|
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"
|