viur-ui 0.0.1 → 0.0.2
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/README.md +67 -41
- package/index.d.ts +18 -9
- package/index.js +6 -3
- package/package.json +3 -5
- package/src/components/Browser/Browser.vue +58 -58
- package/src/components/Browser/TreeNav.vue +32 -32
- package/src/components/Browser/ViurBrowser.d.vue.ts +21 -21
- package/src/components/Browser/ViurBrowser.vue +47 -44
- package/src/components/Browser/dragSession.ts +27 -27
- package/src/components/Browser/index.ts +3 -3
- package/src/components/Browser/types.ts +9 -9
- package/src/components/DataTable/ColumnFilterPanel.vue +7 -7
- package/src/components/DataTable/DataTable.vue +346 -346
- package/src/components/DataTable/ViurDataTable.d.vue.ts +26 -26
- package/src/components/DataTable/ViurDataTable.vue +51 -50
- package/src/components/DataTable/columns.ts +30 -30
- package/src/components/DataTable/index.ts +12 -12
- package/src/components/DataTable/rows.ts +71 -72
- package/src/components/DataTable/types.ts +55 -55
- package/src/components/DataTable/useColumnLayout.ts +28 -28
- package/src/components/DataTable/useGridNavigation.ts +15 -15
- package/src/components/DataTable/useVirtualRows.ts +10 -10
- package/src/components/DataTable/viurColumns.ts +69 -69
- package/src/forms/ViForm.d.vue.ts +32 -32
- package/src/forms/ViForm.vue +17 -16
- package/src/forms/ViFormCategory.vue +3 -1
- package/src/forms/bones/Bone.vue +125 -108
- package/src/forms/bones/BoneActions.vue +21 -21
- package/src/forms/bones/BoneLabel.vue +1 -1
- package/src/forms/bones/BoneMultipleWrapper.vue +3 -3
- package/src/forms/bones/BoneNestedWrapper.vue +3 -3
- package/src/forms/bones/BoneSingleEntry.vue +2 -2
- package/src/forms/bones/FilterBone.vue +3 -3
- package/src/forms/bones/actions/ActionDialog.vue +2 -2
- package/src/forms/bones/actions/Debug.vue +6 -6
- package/src/forms/bones/actions/Delete.vue +2 -2
- package/src/forms/bones/actions/DescribeImage.vue +4 -3
- package/src/forms/bones/actions/Download.vue +4 -4
- package/src/forms/bones/actions/Placeholder.vue +2 -2
- package/src/forms/bones/actions/index.js +72 -74
- package/src/forms/bones/bone.d.ts +19 -19
- package/src/forms/bones/uploadAdapter.js +3 -3
- package/src/forms/bones/utils.js +40 -41
- package/src/forms/bones/view/base_item.vue +1 -1
- package/src/forms/bones/view/boneLogic.js +1 -1
- package/src/forms/bones/widgets/booleanBone.vue +19 -19
- package/src/forms/bones/widgets/booleanBoneChoose.vue +2 -2
- package/src/forms/bones/widgets/booleanBoneSelect.vue +3 -3
- package/src/forms/bones/widgets/codeBone.vue +22 -22
- package/src/forms/bones/widgets/colorBone.vue +18 -18
- package/src/forms/bones/widgets/dateBone.vue +22 -22
- package/src/forms/bones/widgets/emailBone.vue +20 -20
- package/src/forms/bones/widgets/fileBone.vue +32 -31
- package/src/forms/bones/widgets/keyBone.vue +21 -21
- package/src/forms/bones/widgets/numericBone.vue +21 -21
- package/src/forms/bones/widgets/passwordBone.vue +34 -31
- package/src/forms/bones/widgets/phoneBone.vue +20 -20
- package/src/forms/bones/widgets/rawBone.vue +19 -19
- package/src/forms/bones/widgets/recordBone.vue +16 -16
- package/src/forms/bones/widgets/relationalBone.vue +26 -26
- package/src/forms/bones/widgets/selectBone.vue +23 -23
- package/src/forms/bones/widgets/selectBoneChoose.vue +2 -2
- package/src/forms/bones/widgets/spatialBone.vue +21 -21
- package/src/forms/bones/widgets/stringBone.vue +27 -27
- package/src/forms/bones/widgets/textBone.vue +28 -26
- package/src/forms/install.d.ts +1 -1
- package/src/forms/install.js +7 -0
- package/src/forms/layouts/LayloutList2Columns.vue +1 -1
- package/src/forms/layouts/LayoutCategory.vue +1 -1
- package/src/forms/layouts/LayoutList.vue +1 -1
- package/src/forms/utils.js +22 -22
- package/src/request/configStore.js +4 -4
- package/src/request/envelope.js +6 -6
- package/src/request/request.js +22 -22
- package/src/translations/de.js +31 -0
- package/src/translations/en.js +31 -0
- package/src/user/LoginScreen.d.vue.ts +24 -24
- package/src/user/LoginScreen.vue +6 -7
- package/src/user/store.d.ts +16 -16
- package/src/vite/safeHtml.js +73 -0
- package/src/vite/sanitizeVHtml.d.ts +4 -0
- package/src/vite/sanitizeVHtml.js +15 -0
- package/src/webawesomeCompat.css +0 -40
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
<slot></slot>
|
|
13
13
|
</div>
|
|
14
14
|
<div class="wa-cluster wa-gap-xs">
|
|
15
|
-
<!--
|
|
16
|
-
(actions/index.js) —
|
|
17
|
-
|
|
15
|
+
<!-- ALWAYS rendered: the row X is the required action "removeEntry"
|
|
16
|
+
(actions/index.js) — without `boneactions`, BoneActions itself filters
|
|
17
|
+
down to the required actions. -->
|
|
18
18
|
<bone-actions
|
|
19
19
|
:value="state.value"
|
|
20
20
|
:name="name"
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
provide,
|
|
48
48
|
unref,
|
|
49
49
|
} from "vue"
|
|
50
|
-
import { getBoneWidget } from "./index"
|
|
50
|
+
import { getBoneWidget } from "./index.js"
|
|
51
51
|
import ViForm from "../ViForm.vue"
|
|
52
52
|
import { useTimeoutFn } from "@vueuse/core"
|
|
53
53
|
|
|
@@ -64,8 +64,8 @@ const props = defineProps({
|
|
|
64
64
|
const skelRef = ref(null)
|
|
65
65
|
const boneState = inject("boneState")
|
|
66
66
|
const mainformState = inject("mainformState")
|
|
67
|
-
// Action
|
|
68
|
-
//
|
|
67
|
+
// Action configuration of the surrounding form (ViForm `actions`) — the
|
|
68
|
+
// subform would otherwise provide its own (empty) one.
|
|
69
69
|
const parentActionsConfig = inject("boneActionsConfig", null)
|
|
70
70
|
const parentBonePath = inject("bonePath", [])
|
|
71
71
|
const bonePath = computed(() => {
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
@keypress.enter="updateValue"
|
|
14
14
|
></component>
|
|
15
15
|
</div>
|
|
16
|
-
<!--
|
|
17
|
-
|
|
16
|
+
<!-- Required actions (delete, download …) even without `boneactions`; on the
|
|
17
|
+
value of THIS entry, i.e. of its language when multilingual -->
|
|
18
18
|
<div
|
|
19
19
|
v-if="(boneactions && boneState?.hasActions) || boneState?.hasRequiredActions"
|
|
20
20
|
class="wa-cluster wa-gap-xs"
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
<wa-alert
|
|
101
101
|
v-for="message in state.errorMessages"
|
|
102
102
|
open
|
|
103
|
-
summary="
|
|
103
|
+
:summary="$t('bone.errors_summary')"
|
|
104
104
|
variant="danger"
|
|
105
105
|
class="bone-error"
|
|
106
106
|
>
|
|
@@ -141,9 +141,9 @@ import {
|
|
|
141
141
|
} from "vue"
|
|
142
142
|
import wrapperMultiple from "./BoneMultipleWrapper.vue"
|
|
143
143
|
import BoneLabel from "./BoneLabel.vue"
|
|
144
|
-
import { BoneHasMultipleHandling, getBoneActionbar } from "./index"
|
|
144
|
+
import { BoneHasMultipleHandling, getBoneActionbar } from "./index.js"
|
|
145
145
|
import rawBone from "./rawBone.vue"
|
|
146
|
-
import Utils, { buildBoneDomId } from "./utils"
|
|
146
|
+
import Utils, { buildBoneDomId } from "./utils.js"
|
|
147
147
|
import { VueDraggable } from "vue-draggable-plus"
|
|
148
148
|
import BoneActions from "./BoneActions.vue"
|
|
149
149
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
>
|
|
6
6
|
<wa-dialog
|
|
7
7
|
open
|
|
8
|
-
:label="action.name + (name ? ' - ' + name : '')"
|
|
8
|
+
:label="(action.name && $te(action.name) ? $t(action.name) : action.name) + (name ? ' - ' + name : '')"
|
|
9
9
|
class="bone-action-dialog"
|
|
10
10
|
@wa-after-hide="emit('close', null, null, action)"
|
|
11
11
|
>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
<script setup>
|
|
28
28
|
import { computed } from "vue"
|
|
29
|
-
import { getActionComponent } from "./index"
|
|
29
|
+
import { getActionComponent } from "./index.js"
|
|
30
30
|
|
|
31
31
|
const props = defineProps({
|
|
32
32
|
open: Boolean,
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="debug-wrapper">
|
|
3
3
|
<wa-details
|
|
4
|
-
summary="
|
|
4
|
+
:summary="t('actions.debug.structure')"
|
|
5
5
|
open
|
|
6
6
|
>
|
|
7
7
|
<pre>{{ stringify(params.bone) }}</pre>
|
|
8
8
|
</wa-details>
|
|
9
9
|
<wa-details
|
|
10
|
-
summary="
|
|
10
|
+
:summary="t('actions.debug.value')"
|
|
11
11
|
open
|
|
12
12
|
>
|
|
13
13
|
<pre>{{ stringify(params.value) }}</pre>
|
|
14
14
|
</wa-details>
|
|
15
|
-
<wa-details summary="
|
|
15
|
+
<wa-details :summary="t('actions.debug.state')">
|
|
16
16
|
<pre>{{ stringify(params.boneState) }}</pre>
|
|
17
17
|
</wa-details>
|
|
18
|
-
<wa-details summary="
|
|
18
|
+
<wa-details :summary="t('actions.debug.context')">
|
|
19
19
|
<pre>{{ stringify({ name: params.name, lang: params.lang, index: params.index }) }}</pre>
|
|
20
20
|
</wa-details>
|
|
21
21
|
</div>
|
|
@@ -50,8 +50,8 @@ const props = defineProps({
|
|
|
50
50
|
const emit = defineEmits(["close", "next"])
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
53
|
+
* Stringifies an object for the debug display.
|
|
54
|
+
* Skips internal fields (`_*`) and handles cycles.
|
|
55
55
|
*/
|
|
56
56
|
function stringify(obj) {
|
|
57
57
|
const seen = new WeakSet()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
/**
|
|
3
|
-
* Direct-fire
|
|
4
|
-
*
|
|
3
|
+
* Direct-fire action: resets the bone value to an empty string.
|
|
4
|
+
* Called directly by `BoneActions` for `type: "callback"` — no dialog.
|
|
5
5
|
*
|
|
6
6
|
* @param {{ value: object, name: string, lang: string, index: number, bone: object, boneState: object, update: Function }} ctx
|
|
7
7
|
*/
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
<div class="image-description-wrapper">
|
|
3
3
|
<div class="image-description-grid">
|
|
4
4
|
<div>
|
|
5
|
-
<
|
|
5
|
+
<img
|
|
6
6
|
:src="state.url"
|
|
7
|
+
alt=""
|
|
8
|
+
draggable="false"
|
|
7
9
|
style="height: 50px"
|
|
8
|
-
|
|
10
|
+
/>
|
|
9
11
|
</div>
|
|
10
12
|
|
|
11
13
|
<div class="image-description-flex">
|
|
@@ -83,7 +85,6 @@
|
|
|
83
85
|
import { useI18n } from "vue-i18n"
|
|
84
86
|
import { reactive, onMounted, inject, computed } from "vue"
|
|
85
87
|
import { createControllerFetch } from "../../../request/index.js"
|
|
86
|
-
import viImage from "@viur/vue-utils/generic/Image.vue"
|
|
87
88
|
|
|
88
89
|
const { t } = useI18n()
|
|
89
90
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { downloadUrlFor } from "../../../request/index.js"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Direct-fire
|
|
6
|
-
*
|
|
5
|
+
* Direct-fire action: downloads the file referenced in the bone value.
|
|
6
|
+
* Called directly by `BoneActions` for `type: "callback"` — no dialog.
|
|
7
7
|
*
|
|
8
8
|
* @param {{ value: object, name: string, lang: string, index: number, bone: object, boneState: object }} ctx
|
|
9
9
|
*/
|
|
@@ -11,8 +11,8 @@ export function handler(ctx) {
|
|
|
11
11
|
const url = downloadUrlFor(ctx.value)
|
|
12
12
|
if (!url) return
|
|
13
13
|
|
|
14
|
-
// Anchor
|
|
15
|
-
// (
|
|
14
|
+
// Anchor click instead of window.open: also works with data URLs
|
|
15
|
+
// (browsers block top-level navigation to data: URLs for phishing reasons).
|
|
16
16
|
const a = document.createElement("a")
|
|
17
17
|
a.href = url
|
|
18
18
|
a.download = ctx.value?.dest?.name ?? ""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* TODO:
|
|
3
|
+
* Placeholder action for testing the display of multiple buttons.
|
|
4
|
+
* TODO: remove again once no longer needed.
|
|
5
5
|
*
|
|
6
6
|
* @param {{ value: object, name: string, lang: string, index: number, bone: object, boneState: object }} ctx
|
|
7
7
|
*/
|
|
@@ -2,105 +2,103 @@ import { defineAsyncComponent, unref } from "vue"
|
|
|
2
2
|
import Translation from "./Translation.vue"
|
|
3
3
|
import Debug from "./Debug.vue"
|
|
4
4
|
|
|
5
|
-
// Lazy: DescribeImage
|
|
6
|
-
//
|
|
7
|
-
// Paket nicht haben — obwohl sie die Action gar nicht benutzen. So wird es erst
|
|
8
|
-
// beim tatsächlichen Öffnen des Dialogs geladen (wie die schweren Bones).
|
|
5
|
+
// Lazy: DescribeImage is only loaded when the dialog is actually opened
|
|
6
|
+
// (like the heavy bones).
|
|
9
7
|
const DescribeImage = defineAsyncComponent(() => import("./DescribeImage.vue"))
|
|
10
8
|
import { handler as downloadHandler } from "./Download.vue"
|
|
11
9
|
import { handler as placeholderHandler } from "./Placeholder.vue"
|
|
12
10
|
import { handler as deleteHandler } from "./Delete.vue"
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
|
-
* Default
|
|
16
|
-
* Strings in `bone.params.actions`
|
|
17
|
-
* Custom
|
|
13
|
+
* Default definitions: same inline format as formerly in BoneActions.
|
|
14
|
+
* Strings in `bone.params.actions` are looked up here.
|
|
15
|
+
* Custom objects from `bone.params.actions` are passed through in the same form.
|
|
18
16
|
*/
|
|
19
17
|
const defaultActions = {
|
|
20
18
|
translate: {
|
|
21
19
|
type: "assistant",
|
|
22
20
|
arg: "translate",
|
|
23
|
-
name: "
|
|
21
|
+
name: "actions.translate.name",
|
|
24
22
|
icon: "translate",
|
|
25
23
|
library: "default",
|
|
26
|
-
title: "
|
|
24
|
+
title: "actions.translate.name",
|
|
27
25
|
},
|
|
28
26
|
describe_image: {
|
|
29
27
|
type: "assistant",
|
|
30
28
|
arg: "describe_image",
|
|
31
|
-
name: "
|
|
29
|
+
name: "actions.describeImage.name",
|
|
32
30
|
icon: "file-richtext",
|
|
33
31
|
library: "default",
|
|
34
|
-
title: "
|
|
32
|
+
title: "actions.describeImage.title",
|
|
35
33
|
},
|
|
36
34
|
download: {
|
|
37
35
|
type: "callback",
|
|
38
36
|
arg: "download",
|
|
39
|
-
name: "
|
|
37
|
+
name: "bone.download",
|
|
40
38
|
icon: "download",
|
|
41
39
|
library: "default",
|
|
42
40
|
title: "bone.download",
|
|
43
|
-
//
|
|
44
|
-
//
|
|
41
|
+
// Scaffolding like the row X: present even without `boneactions` (formerly a button in the
|
|
42
|
+
// file widget) — and read-only, so also on readonly bones.
|
|
45
43
|
required: true,
|
|
46
44
|
allowReadonly: true,
|
|
47
45
|
},
|
|
48
46
|
debug: {
|
|
49
47
|
type: "assistant",
|
|
50
48
|
arg: "debug",
|
|
51
|
-
name: "
|
|
49
|
+
name: "actions.debug.name",
|
|
52
50
|
icon: "bug",
|
|
53
51
|
library: "default",
|
|
54
|
-
title: "
|
|
52
|
+
title: "actions.debug.title",
|
|
55
53
|
},
|
|
56
54
|
placeholder: {
|
|
57
55
|
type: "callback",
|
|
58
56
|
arg: "placeholder",
|
|
59
|
-
name: "
|
|
57
|
+
name: "actions.placeholder.name",
|
|
60
58
|
icon: "wrench",
|
|
61
59
|
library: "default",
|
|
62
|
-
title: "
|
|
60
|
+
title: "actions.placeholder.title",
|
|
63
61
|
},
|
|
64
62
|
delete: {
|
|
65
63
|
type: "callback",
|
|
66
64
|
arg: "delete",
|
|
67
|
-
name: "
|
|
65
|
+
name: "actions.delete.name",
|
|
68
66
|
icon: "xmark",
|
|
69
67
|
library: "default",
|
|
70
68
|
title: "bone.del",
|
|
71
69
|
position: "end",
|
|
72
70
|
variant: "danger",
|
|
73
|
-
//
|
|
74
|
-
// (
|
|
71
|
+
// Scaffolding: without it you can't get rid of a set relation/file
|
|
72
|
+
// (formerly a button in the widget) — hence present even without `boneactions`.
|
|
75
73
|
required: true,
|
|
76
|
-
//
|
|
74
|
+
// Only visible on relational single bones (not multiple).
|
|
77
75
|
when: (ctx) => prefixMatches("relational", ctx?.bone?.type) && !ctx?.bone?.multiple,
|
|
78
76
|
},
|
|
79
77
|
removeEntry: {
|
|
80
78
|
type: "callback",
|
|
81
79
|
arg: "removeEntry",
|
|
82
|
-
name: "
|
|
80
|
+
name: "bone.del",
|
|
83
81
|
icon: "xmark",
|
|
84
82
|
library: "default",
|
|
85
83
|
title: "bone.del",
|
|
86
84
|
position: "end",
|
|
87
85
|
variant: "danger",
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
// (BoneActions
|
|
86
|
+
// REQUIRED action (scaffolding): removes THIS row of a multiple bone —
|
|
87
|
+
// without it you could never get rid of an entry. Only visible in row contexts
|
|
88
|
+
// (BoneActions with index).
|
|
91
89
|
required: true,
|
|
92
90
|
when: (ctx) => ctx?.multipleRow === true,
|
|
93
91
|
},
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
/** Dialog
|
|
94
|
+
/** Dialog content for `type: "assistant"` actions, mapped by `arg`. */
|
|
97
95
|
const componentRegistry = {
|
|
98
96
|
translate: Translation,
|
|
99
97
|
describe_image: DescribeImage,
|
|
100
98
|
debug: Debug,
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
/**
|
|
101
|
+
/** Directly invoked handlers for `type: "callback"` actions, mapped by `arg`. */
|
|
104
102
|
const handlerRegistry = {
|
|
105
103
|
download: downloadHandler,
|
|
106
104
|
placeholder: placeholderHandler,
|
|
@@ -108,32 +106,32 @@ const handlerRegistry = {
|
|
|
108
106
|
removeEntry: (ctx) => ctx.removeEntry?.(),
|
|
109
107
|
}
|
|
110
108
|
|
|
111
|
-
/**
|
|
112
|
-
* null/undefined/
|
|
109
|
+
/** No value to act on: empty, or an object/array without content (only
|
|
110
|
+
* null/undefined/empty lists — like `isObjectEmpty` in the bone). */
|
|
113
111
|
function isEmptyValue(value) {
|
|
114
112
|
if (!value) return true
|
|
115
113
|
if (typeof value !== "object") return false
|
|
116
114
|
return Object.values(value).every((entry) => entry == null || (Array.isArray(entry) && entry.length === 0))
|
|
117
115
|
}
|
|
118
116
|
|
|
119
|
-
/** Disabled
|
|
117
|
+
/** Disabled check by `arg`. Receives the action context (name, value, index, lang, bone, boneState). */
|
|
120
118
|
const disabledRegistry = {
|
|
121
119
|
translate: (ctx) => !ctx.bone?.languages,
|
|
122
120
|
describe_image: (ctx) => !ctx.value?.dest?.key,
|
|
123
121
|
download: (ctx) => !ctx.value?.dest?.downloadUrl,
|
|
124
|
-
//
|
|
122
|
+
// on its OWN value — when multilingual that of one language, not of the bone
|
|
125
123
|
delete: (ctx) => isEmptyValue(ctx.value),
|
|
126
124
|
}
|
|
127
125
|
|
|
128
126
|
/**
|
|
129
|
-
* Default
|
|
130
|
-
*
|
|
127
|
+
* Default actions per bone type prefix. When resolving, ALL matching
|
|
128
|
+
* prefixes are merged (shortest first, deduplicated).
|
|
131
129
|
*
|
|
132
|
-
* Matching
|
|
133
|
-
* `boneType.startsWith(prefix + ".")` (
|
|
130
|
+
* Matching rule: a prefix matches if `boneType === prefix` (exact) OR
|
|
131
|
+
* `boneType.startsWith(prefix + ".")` (subtype). The empty prefix `""` matches everything.
|
|
134
132
|
*
|
|
135
|
-
*
|
|
136
|
-
* `boneactions`;
|
|
133
|
+
* Definitions with `required: true` (delete, download) appear even without
|
|
134
|
+
* `boneactions`; a host can still deselect them here (as with `"-name"`).
|
|
137
135
|
*/
|
|
138
136
|
const defaultActionsByType = {
|
|
139
137
|
"": ["debug", "placeholder"],
|
|
@@ -142,11 +140,11 @@ const defaultActionsByType = {
|
|
|
142
140
|
}
|
|
143
141
|
|
|
144
142
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* `when
|
|
149
|
-
*
|
|
143
|
+
* REQUIRED actions per bone type prefix (scaffolding functions). Unlike the
|
|
144
|
+
* defaults, they survive both a `bone.params.actions` list from the server
|
|
145
|
+
* and the host's `setDefaultActionsForType` — only their own
|
|
146
|
+
* `when` predicate (functional availability) hides them. They are
|
|
147
|
+
* also rendered WITHOUT `boneactions` (BoneActions filters for them).
|
|
150
148
|
*/
|
|
151
149
|
const requiredActionsByType = {
|
|
152
150
|
"": ["removeEntry"],
|
|
@@ -159,7 +157,7 @@ function prefixMatches(prefix, boneType) {
|
|
|
159
157
|
}
|
|
160
158
|
|
|
161
159
|
/**
|
|
162
|
-
*
|
|
160
|
+
* Extends the registry. Every field is optional.
|
|
163
161
|
* @param {string} name
|
|
164
162
|
* @param {{ default?: object, component?: object, handler?: Function, disabled?: Function }} opts
|
|
165
163
|
*/
|
|
@@ -170,21 +168,21 @@ export function addAction(name, opts) {
|
|
|
170
168
|
if (opts.disabled) disabledRegistry[name] = opts.disabled
|
|
171
169
|
}
|
|
172
170
|
|
|
173
|
-
/**
|
|
171
|
+
/** Sets the default actions for a bone type prefix. */
|
|
174
172
|
export function setDefaultActionsForType(typePrefix, actionNames) {
|
|
175
173
|
defaultActionsByType[typePrefix] = actionNames
|
|
176
174
|
}
|
|
177
175
|
|
|
178
|
-
/**
|
|
176
|
+
/** Sets the REQUIRED actions for a bone type prefix (host curation). */
|
|
179
177
|
export function setRequiredActionsForType(typePrefix, actionNames) {
|
|
180
178
|
requiredActionsByType[typePrefix] = actionNames
|
|
181
179
|
}
|
|
182
180
|
|
|
183
181
|
/**
|
|
184
|
-
*
|
|
185
|
-
* provide("boneActionsConfig") —
|
|
186
|
-
*
|
|
187
|
-
*
|
|
182
|
+
* Resolve the form-wide action configuration (ViForm `actions` prop, via
|
|
183
|
+
* provide("boneActionsConfig") — possibly a ref) for ONE bone:
|
|
184
|
+
* an array applies to all bones, an object per bone name with `"*"` for all.
|
|
185
|
+
* The entries have the same form as `bone.params.actions` (incl. `"-name"`).
|
|
188
186
|
*/
|
|
189
187
|
export function formConfiguredActions(config, boneName) {
|
|
190
188
|
const value = unref(config)
|
|
@@ -202,16 +200,16 @@ export function getActionHandler(arg) {
|
|
|
202
200
|
}
|
|
203
201
|
|
|
204
202
|
export function isActionDisabled(action, ctx) {
|
|
205
|
-
//
|
|
206
|
-
//
|
|
203
|
+
// In readonly mode all actions are disabled in principle — except for
|
|
204
|
+
// purely read-only ones (`allowReadonly`, e.g. download).
|
|
207
205
|
if (ctx?.boneState?.readonly && !action?.allowReadonly) return true
|
|
208
206
|
const fn = disabledRegistry[action?.arg]
|
|
209
207
|
return fn ? !!fn(ctx) : false
|
|
210
208
|
}
|
|
211
209
|
|
|
212
210
|
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
211
|
+
* Collects all action names of a prefix map for a bone type across
|
|
212
|
+
* matching prefixes (shortest first, deduplicated).
|
|
215
213
|
*
|
|
216
214
|
* @param {Record<string, string[]>} map
|
|
217
215
|
* @param {string} boneType
|
|
@@ -230,40 +228,40 @@ function collectFromMap(map, boneType) {
|
|
|
230
228
|
return names
|
|
231
229
|
}
|
|
232
230
|
|
|
233
|
-
/**
|
|
231
|
+
/** Returns the `arg` identifier of an entry (string or inline definition). */
|
|
234
232
|
function entryArg(entry) {
|
|
235
233
|
return typeof entry === "string" ? entry : entry?.arg
|
|
236
234
|
}
|
|
237
235
|
|
|
238
236
|
/**
|
|
239
|
-
*
|
|
240
|
-
* - Type
|
|
241
|
-
* (
|
|
242
|
-
* -
|
|
243
|
-
* - `configured` (
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* `params.actions
|
|
247
|
-
* -
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
* - Strings
|
|
251
|
-
* - Actions
|
|
237
|
+
* Resolves the action list for a bone.
|
|
238
|
+
* - Type defaults from `defaultActionsByType` are **always** applied
|
|
239
|
+
* (matching prefixes combined, shortest first).
|
|
240
|
+
* - REQUIRED actions from `requiredActionsByType` are ALWAYS added on top.
|
|
241
|
+
* - `configured` (typically `bone.params.actions`) is prepended and the
|
|
242
|
+
* defaults are merged in deduplicated. This way e.g. the `delete`
|
|
243
|
+
* action always stays available for relational bones, even if the backend sends a
|
|
244
|
+
* `params.actions` list.
|
|
245
|
+
* - EXPLICIT DESELECTION: a string entry `"-name"` in `configured` removes
|
|
246
|
+
* the action `name` — even a default or required action (the deliberate
|
|
247
|
+
* deselection on the bone overrides the requirement; only it does).
|
|
248
|
+
* - Strings are resolved via default lookup, inline objects are passed through.
|
|
249
|
+
* - Actions with `when(ctx)` are filtered out if the predicate returns falsy.
|
|
252
250
|
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
251
|
+
* Every returned action is a shallow copy so that `_opened` mutations
|
|
252
|
+
* don't change the source. Sorted: actions with `position: "end"` go last.
|
|
255
253
|
*
|
|
256
|
-
* @param {object} bone -
|
|
254
|
+
* @param {object} bone - complete bone definition (with type, multiple, params)
|
|
257
255
|
* @param {Array<string|object>|undefined} configured
|
|
258
|
-
* @param {object} [boneState] - reactive
|
|
259
|
-
* @param {object} [extras] -
|
|
256
|
+
* @param {object} [boneState] - reactive bone state (for when/disabled predicates)
|
|
257
|
+
* @param {object} [extras] - additional context for `when` (e.g. injected hosts like `relationSelector`)
|
|
260
258
|
* @returns {object[]}
|
|
261
259
|
*/
|
|
262
260
|
export function resolveActions(bone, configured, boneState, extras = {}) {
|
|
263
261
|
const defaults = collectFromMap(defaultActionsByType, bone?.type)
|
|
264
262
|
const required = collectFromMap(requiredActionsByType, bone?.type)
|
|
265
263
|
const entries = Array.isArray(configured) ? [...configured] : []
|
|
266
|
-
//
|
|
264
|
+
// Explicit deselection: collect "-name" entries and remove them from the list.
|
|
267
265
|
const disabled = new Set(entries.filter((e) => typeof e === "string" && e.startsWith("-")).map((e) => e.slice(1)))
|
|
268
266
|
const names = entries.filter((e) => !(typeof e === "string" && e.startsWith("-")))
|
|
269
267
|
for (const d of [...defaults, ...required]) {
|
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
import type { DefineComponent } from "vue"
|
|
2
2
|
|
|
3
3
|
export interface BoneProps {
|
|
4
|
-
/**
|
|
4
|
+
/** The bone widget component object (e.g. StringBone). Typically set by ViForm. */
|
|
5
5
|
is?: object
|
|
6
|
-
/** Bone
|
|
6
|
+
/** Bone identifier; must match a key in structure and skel. */
|
|
7
7
|
name: string
|
|
8
|
-
/**
|
|
8
|
+
/** Explicit language list; overrides bonestructure.languages. */
|
|
9
9
|
languages?: unknown[]
|
|
10
|
-
/**
|
|
10
|
+
/** Explicit multiple flag; overrides bonestructure.multiple. */
|
|
11
11
|
multiple?: boolean
|
|
12
|
-
/**
|
|
12
|
+
/** Explicit readonly flag; overrides bonestructure.readonly. */
|
|
13
13
|
readonly?: boolean
|
|
14
|
-
/**
|
|
14
|
+
/** Explicit required flag; overrides bonestructure.required. */
|
|
15
15
|
required?: boolean
|
|
16
|
-
/**
|
|
16
|
+
/** Additional parameters; overrides bonestructure.params. */
|
|
17
17
|
params?: Record<string, unknown>
|
|
18
|
-
/**
|
|
18
|
+
/** Explicit value; overrides skel[name] if set. */
|
|
19
19
|
value?: object | string | number | boolean | unknown[]
|
|
20
|
-
/**
|
|
20
|
+
/** Complete skeleton structure (all bone definitions of the form). */
|
|
21
21
|
structure: Record<string, unknown>
|
|
22
|
-
/** Skeleton
|
|
22
|
+
/** Skeleton data object with the current values. */
|
|
23
23
|
skel: unknown
|
|
24
|
-
/**
|
|
24
|
+
/** Error array from the server response. Entries with a matching fieldPath are displayed. */
|
|
25
25
|
errors?: unknown[]
|
|
26
|
-
/** Label
|
|
26
|
+
/** Label mode. */
|
|
27
27
|
label?: "normal" | "top" | "hide" | "placeholder"
|
|
28
|
-
/**
|
|
28
|
+
/** Enables BoneActions buttons next to the input. */
|
|
29
29
|
boneactions?: boolean
|
|
30
|
-
/**
|
|
30
|
+
/** Shows tooltip content as wa-alert instead of a tooltip. */
|
|
31
31
|
showLabelInfo?: boolean
|
|
32
|
-
/**
|
|
32
|
+
/** Passes autofocus on to the bone widget. */
|
|
33
33
|
autofocus?: boolean
|
|
34
|
-
/**
|
|
34
|
+
/** Language active by default in the multilang tab. */
|
|
35
35
|
defaultLanguage?: string
|
|
36
|
-
/**
|
|
36
|
+
/** Forces the tooltip on the input area regardless of the label mode. */
|
|
37
37
|
showBoneTooltip?: boolean
|
|
38
|
-
/**
|
|
38
|
+
/** Error display style. */
|
|
39
39
|
errorStyle?: "default" | "decent"
|
|
40
|
-
/**
|
|
40
|
+
/** Enables debug mode: bone name as tooltip on the label. */
|
|
41
41
|
debug?: boolean
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -18,9 +18,9 @@ class ViURUploadAdapter {
|
|
|
18
18
|
this.loader.uploaded = 75
|
|
19
19
|
this.loader.uploaded = 100
|
|
20
20
|
resolve({
|
|
21
|
-
//
|
|
22
|
-
// (
|
|
23
|
-
// (
|
|
21
|
+
// The URL ends up in the text bone's HTML: as /file/download/…
|
|
22
|
+
// (only made absolute) — viur-core recognizes those again
|
|
23
|
+
// (blob reference, srcset) and it doesn't sit behind /vi.
|
|
24
24
|
default: downloadUrlFor(uploadedData["downloadUrl"]),
|
|
25
25
|
})
|
|
26
26
|
})
|