@conduction/nextcloud-vue 2.56.0-beta.31 → 2.56.0-beta.32
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/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +55 -4
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +51 -15
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +13 -2
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +63 -52
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js +10 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js.map +1 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js +252 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js +140 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnChipsFieldWidget/index.js +26 -0
- package/dist/esm/components/CnChipsFieldWidget/index.js.map +1 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js +10 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js.map +1 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js +354 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js +172 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnChoicePickerWidget/index.js +27 -0
- package/dist/esm/components/CnChoicePickerWidget/index.js.map +1 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +25 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +3 -2
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -0
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +20 -3
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +7 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +77 -3
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +282 -69
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +0 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +65 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +6 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +10 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +174 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +75 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnRadioCardsWidget/index.js +28 -0
- package/dist/esm/components/CnRadioCardsWidget/index.js.map +1 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +18 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +34 -25
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js +10 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js +222 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js +64 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSavedViewsWidget/index.js +30 -0
- package/dist/esm/components/CnSavedViewsWidget/index.js.map +1 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +10 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +347 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +184 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSettingsFormWidget/index.js +27 -0
- package/dist/esm/components/CnSettingsFormWidget/index.js.map +1 -0
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +87 -6
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +10 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +159 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js +60 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSwitchRowsWidget/index.js +26 -0
- package/dist/esm/components/CnSwitchRowsWidget/index.js.map +1 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +47 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +16 -14
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +80 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +75 -32
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +10 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js.map +1 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +269 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js +106 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnToggleTableWidget/index.js +27 -0
- package/dist/esm/components/CnToggleTableWidget/index.js.map +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +7 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js +4 -2
- package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js.map +1 -1
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +1 -0
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +1 -0
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +843 -4
- package/dist/esm/utils/contentHeaderLink.js +51 -0
- package/dist/esm/utils/contentHeaderLink.js.map +1 -0
- package/dist/esm/utils/fetchFilterCounts.js +40 -5
- package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
- package/dist/esm/utils/initials.js +32 -0
- package/dist/esm/utils/initials.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +7 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/objectWrite.js +59 -0
- package/dist/esm/utils/objectWrite.js.map +1 -0
- package/dist/esm/utils/widgetDispatch.js +1 -1
- package/dist/esm/utils/widgetDispatch.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +10510 -6830
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +843 -4
- package/l10n/en.json +1 -0
- package/l10n/nl.json +1 -0
- package/package.json +1 -1
- package/src/components/CnBannerWidget/CnBannerWidget.vue +93 -13
- package/src/components/CnCellRenderer/CnCellRenderer.md +2 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +43 -3
- package/src/components/CnChipsFieldWidget/CnChipsFieldWidget.vue +433 -0
- package/src/components/CnChipsFieldWidget/index.js +25 -0
- package/src/components/CnChoicePickerWidget/CnChoicePickerWidget.vue +556 -0
- package/src/components/CnChoicePickerWidget/index.js +26 -0
- package/src/components/CnDashboardPage/CnDashboardPage.vue +38 -2
- package/src/components/CnDataTable/CnDataTable.vue +2 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +45 -2
- package/src/components/CnFactsWidget/CnFactsWidget.vue +18 -3
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +265 -4
- package/src/components/CnIndexPage/CnIndexPage.vue +0 -1
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +69 -2
- package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +313 -0
- package/src/components/CnRadioCardsWidget/index.js +27 -0
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +43 -1
- package/src/components/CnSavedViewsWidget/CnSavedViewsWidget.vue +296 -0
- package/src/components/CnSavedViewsWidget/index.js +29 -0
- package/src/components/CnSegmentedControl/CnSegmentedControl.vue +13 -0
- package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +555 -0
- package/src/components/CnSettingsFormWidget/index.js +26 -0
- package/src/components/CnStatWidget/CnStatWidget.vue +87 -6
- package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +226 -0
- package/src/components/CnSwitchRowsWidget/index.js +25 -0
- package/src/components/CnTabsWidget/CnTabsWidget.vue +82 -3
- package/src/components/CnTasksWidget/CnTasksWidget.vue +175 -15
- package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +386 -0
- package/src/components/CnToggleTableWidget/index.js +26 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +7 -0
- package/src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue +28 -1
- package/src/components/index.js +7 -0
- package/src/css/look-board-detail.css +36 -2
- package/src/css/look-board-index.css +23 -0
- package/src/css/look-board.css +72 -0
- package/src/index.js +7 -0
- package/src/utils/contentHeaderLink.js +48 -0
- package/src/utils/fetchFilterCounts.js +39 -4
- package/src/utils/initials.js +29 -0
- package/src/utils/libraryWidgetKeys.js +7 -0
- package/src/utils/objectWrite.js +55 -0
- package/src/utils/widgetDispatch.js +1 -1
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { NcButton, NcNoteCard } from '@nextcloud/vue';
|
|
2
|
+
import __sfc_main from '../CnStatusBadge/CnStatusBadge.vue.js';
|
|
3
|
+
import { isBadgeVariant } from '../../utils/badgeVariants.js';
|
|
4
|
+
import { prefixUrl } from '../../utils/headers.js';
|
|
5
|
+
import { objectUrlOf } from '../../utils/objectWrite.js';
|
|
6
|
+
import { readPath } from '../../utils/readPath.js';
|
|
7
|
+
import { serverErrorMessage } from '../../utils/serverErrorMessage.js';
|
|
8
|
+
|
|
9
|
+
let uid = 0;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* CnChoicePickerWidget — the `choice-picker` widget: choice cards read from a
|
|
13
|
+
* source (or a static list), each with a radio, colour swatches read from the
|
|
14
|
+
* item, a title and a state pill (a verdict such as "Leesbaar" / "Slecht
|
|
15
|
+
* leesbaar"), bound to one field of the CURRENT object.
|
|
16
|
+
*
|
|
17
|
+
* Save is a button. A card that carries a warning (a list of lines read from
|
|
18
|
+
* the item) shows them in a warning band under the cards and adds a second
|
|
19
|
+
* button, the confirm action, so a risky choice is saved only on purpose: the
|
|
20
|
+
* request tells the server which one was pressed (`@confirmed`). A card the
|
|
21
|
+
* source marks as refused is listed with its reason and cannot be chosen.
|
|
22
|
+
*
|
|
23
|
+
* @spec openspec/changes/abstract-choice-picker/specs/choice-picker/spec.md
|
|
24
|
+
*/
|
|
25
|
+
var script = {
|
|
26
|
+
name: 'CnChoicePickerWidget',
|
|
27
|
+
|
|
28
|
+
components: { CnStatusBadge: __sfc_main, NcButton, NcNoteCard },
|
|
29
|
+
|
|
30
|
+
inject: {
|
|
31
|
+
cnTranslate: { default: () => (key) => key },
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
props: {
|
|
35
|
+
/**
|
|
36
|
+
* The widget configuration.
|
|
37
|
+
*
|
|
38
|
+
* - `field` (required) — the top-level field of the object holding the chosen key.
|
|
39
|
+
* - `source` — `{ url, path?, key, label, swatches?, state?, refusal?, warning? }` (tokens `@objectId`, `@object.<field>` in the url), or `items` — the same item shape as a static list.
|
|
40
|
+
* - `swatches` — path to an array of colours (CSS colour strings).
|
|
41
|
+
* - `state` — `{ path, map?, variantMap?, empty?, emptyVariant? }`: the pill; `map` turns the value into text, `variantMap` into a badge variant, `empty` is the text when the value is missing.
|
|
42
|
+
* - `refusal` — path to a string: the card is listed with it and cannot be chosen.
|
|
43
|
+
* - `warning` — `{ list, item? }`: `list` is a path to an array; `item` a template with `{path}` placeholders for object items (strings are used as they are).
|
|
44
|
+
* - `legend`, `warningIntro`, `saveLabel`, `confirmLabel`, `emptyText`, `hint`, `readOnly`.
|
|
45
|
+
* - `save` — `{ method?, url?, payload? }`: a custom request (tokens `@value`, `@confirmed`, `@objectId`, `@object.<field>`); without it the field is PATCHed on the object.
|
|
46
|
+
*
|
|
47
|
+
* @type {object}
|
|
48
|
+
*/
|
|
49
|
+
content: {
|
|
50
|
+
type: Object,
|
|
51
|
+
default: () => ({}),
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/** The current detail-page object. */
|
|
55
|
+
objectData: {
|
|
56
|
+
type: Object,
|
|
57
|
+
default: null,
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
/** The current object id. */
|
|
61
|
+
objectId: {
|
|
62
|
+
type: [String, Number],
|
|
63
|
+
default: '',
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/** OpenRegister register slug of the surface. */
|
|
67
|
+
register: {
|
|
68
|
+
type: [String, Object],
|
|
69
|
+
default: '',
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
/** OpenRegister schema slug of the surface. */
|
|
73
|
+
schema: {
|
|
74
|
+
type: [String, Object],
|
|
75
|
+
default: '',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
emits: ['saved'],
|
|
80
|
+
|
|
81
|
+
data() {
|
|
82
|
+
uid += 1;
|
|
83
|
+
return {
|
|
84
|
+
groupName: `cn-choice-picker-${uid}`,
|
|
85
|
+
sourced: [],
|
|
86
|
+
loading: false,
|
|
87
|
+
saved: '',
|
|
88
|
+
chosen: '',
|
|
89
|
+
saving: false,
|
|
90
|
+
notice: '',
|
|
91
|
+
noticeType: 'success',
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
computed: {
|
|
96
|
+
spec() {
|
|
97
|
+
return this.content.source || {}
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
/** The cards, from the static items then the source. */
|
|
101
|
+
options() {
|
|
102
|
+
const items = [...(Array.isArray(this.content.items) ? this.content.items : []), ...this.sourced];
|
|
103
|
+
return items
|
|
104
|
+
.filter((item) => item && readPath(item, this.spec.key || 'key') !== undefined)
|
|
105
|
+
.map((item) => {
|
|
106
|
+
const key = String(readPath(item, this.spec.key || 'key'));
|
|
107
|
+
const refusal = this.spec.refusal ? readPath(item, this.spec.refusal) : '';
|
|
108
|
+
return {
|
|
109
|
+
key,
|
|
110
|
+
title: String(readPath(item, this.spec.label || 'label') ?? key),
|
|
111
|
+
swatches: this.listOf(item, this.spec.swatches).filter((colour) => typeof colour === 'string'),
|
|
112
|
+
pill: this.pillOf(item),
|
|
113
|
+
refusal: typeof refusal === 'string' ? refusal : '',
|
|
114
|
+
warning: this.warningOf(item),
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
selected() {
|
|
120
|
+
return this.options.find((option) => option.key === this.chosen) || null
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
canSave() {
|
|
124
|
+
return this.chosen !== '' && this.chosen !== this.saved && (this.selected ? this.selected.refusal === '' : false)
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
legend() {
|
|
128
|
+
return this.tr(this.content.legend || 'Choose one')
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
warningIntro() {
|
|
132
|
+
return this.tr(this.content.warningIntro || '')
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
saveLabel() {
|
|
136
|
+
return this.tr(this.content.saveLabel || 'Save')
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
confirmLabel() {
|
|
140
|
+
return this.tr(this.content.confirmLabel || 'Use it anyway')
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
emptyLabel() {
|
|
144
|
+
return this.tr(this.content.emptyText || 'Nothing to choose from')
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
hint() {
|
|
148
|
+
return this.tr(this.content.hint || '')
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
readOnly() {
|
|
152
|
+
return this.content.readOnly === true
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
objectUrl() {
|
|
156
|
+
return objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
watch: {
|
|
161
|
+
objectData() {
|
|
162
|
+
this.adopt();
|
|
163
|
+
this.loadSource();
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
created() {
|
|
168
|
+
this.adopt();
|
|
169
|
+
this.loadSource();
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
methods: {
|
|
173
|
+
tr(text) {
|
|
174
|
+
if (typeof text !== 'string' || text === '') {
|
|
175
|
+
return ''
|
|
176
|
+
}
|
|
177
|
+
return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
/** Read the current choice off the object. */
|
|
181
|
+
adopt() {
|
|
182
|
+
const stored = readPath(this.objectData || {}, this.content.field);
|
|
183
|
+
this.saved = stored === undefined || stored === null ? '' : String(stored);
|
|
184
|
+
this.chosen = this.saved;
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* A list off an item.
|
|
189
|
+
*
|
|
190
|
+
* @param {object} item The item.
|
|
191
|
+
* @param {string} path The path, or undefined.
|
|
192
|
+
* @return {Array}
|
|
193
|
+
*/
|
|
194
|
+
listOf(item, path) {
|
|
195
|
+
const list = path ? readPath(item, path) : [];
|
|
196
|
+
return Array.isArray(list) ? list : []
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The state pill of an item.
|
|
201
|
+
*
|
|
202
|
+
* @param {object} item The item.
|
|
203
|
+
* @return {{label: string, variant: string}|null}
|
|
204
|
+
*/
|
|
205
|
+
pillOf(item) {
|
|
206
|
+
const state = this.spec.state;
|
|
207
|
+
if (!state || !state.path) {
|
|
208
|
+
return null
|
|
209
|
+
}
|
|
210
|
+
const raw = readPath(item, state.path);
|
|
211
|
+
const empty = raw === undefined || raw === null || raw === '';
|
|
212
|
+
if (empty) {
|
|
213
|
+
return state.empty ? { label: this.tr(state.empty), variant: isBadgeVariant(state.emptyVariant) ? state.emptyVariant : 'default' } : null
|
|
214
|
+
}
|
|
215
|
+
const label = state.map && Object.hasOwn(state.map, String(raw)) ? this.tr(state.map[String(raw)]) : String(raw);
|
|
216
|
+
const variant = state.variantMap && state.variantMap[String(raw)];
|
|
217
|
+
return { label, variant: isBadgeVariant(variant) ? variant : 'default' }
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The warning lines of an item.
|
|
222
|
+
*
|
|
223
|
+
* @param {object} item The item.
|
|
224
|
+
* @return {string[]}
|
|
225
|
+
*/
|
|
226
|
+
warningOf(item) {
|
|
227
|
+
const spec = this.spec.warning;
|
|
228
|
+
if (!spec || !spec.list) {
|
|
229
|
+
return []
|
|
230
|
+
}
|
|
231
|
+
return this.listOf(item, spec.list)
|
|
232
|
+
.map((entry) => {
|
|
233
|
+
if (typeof entry === 'string') {
|
|
234
|
+
return entry
|
|
235
|
+
}
|
|
236
|
+
if (!entry || typeof entry !== 'object' || !spec.item) {
|
|
237
|
+
return ''
|
|
238
|
+
}
|
|
239
|
+
return this.tr(spec.item).replace(/\{([\w.]+)\}/g, (m, path) => String(readPath(entry, path) ?? ''))
|
|
240
|
+
})
|
|
241
|
+
.filter((line) => line !== '')
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Resolve the tokens in a url or payload.
|
|
246
|
+
*
|
|
247
|
+
* @param {unknown} value The value.
|
|
248
|
+
* @param {object} vars `{ value, confirmed }`.
|
|
249
|
+
* @return {unknown}
|
|
250
|
+
*/
|
|
251
|
+
resolve(value, vars) {
|
|
252
|
+
if (Array.isArray(value)) {
|
|
253
|
+
return value.map((v) => this.resolve(v, vars))
|
|
254
|
+
}
|
|
255
|
+
if (value && typeof value === 'object') {
|
|
256
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.resolve(v, vars)]))
|
|
257
|
+
}
|
|
258
|
+
if (typeof value !== 'string') {
|
|
259
|
+
return value
|
|
260
|
+
}
|
|
261
|
+
const object = this.objectData || {};
|
|
262
|
+
if (value === '@value') {
|
|
263
|
+
return vars.value
|
|
264
|
+
}
|
|
265
|
+
if (value === '@confirmed') {
|
|
266
|
+
return vars.confirmed
|
|
267
|
+
}
|
|
268
|
+
const whole = value.match(/^@object\.([\w.@]+)$/);
|
|
269
|
+
if (whole) {
|
|
270
|
+
return readPath(object, whole[1])
|
|
271
|
+
}
|
|
272
|
+
return value
|
|
273
|
+
.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))
|
|
274
|
+
.replace(/@object\.([\w.@]+)/g, (m, path) => encodeURIComponent(String(readPath(object, path) ?? '')))
|
|
275
|
+
.replace(/@value/g, () => encodeURIComponent(String(vars.value)))
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
/** Read the cards of `source`. */
|
|
279
|
+
async loadSource() {
|
|
280
|
+
if (!this.spec.url) {
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
this.loading = true;
|
|
284
|
+
try {
|
|
285
|
+
const { default: axios } = await import('@nextcloud/axios');
|
|
286
|
+
const { data } = await axios.get(prefixUrl(String(this.resolve(this.spec.url, { value: '', confirmed: false }))));
|
|
287
|
+
const list = this.spec.path ? readPath(data, this.spec.path) : data;
|
|
288
|
+
this.sourced = Array.isArray(list) ? list : [];
|
|
289
|
+
} catch (e) {
|
|
290
|
+
this.noticeType = 'error';
|
|
291
|
+
this.notice = serverErrorMessage(e);
|
|
292
|
+
} finally {
|
|
293
|
+
this.loading = false;
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Choose a card (nothing is written until Save).
|
|
299
|
+
*
|
|
300
|
+
* @param {object} option The card.
|
|
301
|
+
*/
|
|
302
|
+
choose(option) {
|
|
303
|
+
this.chosen = option.key;
|
|
304
|
+
this.notice = '';
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Save the chosen card: the configured request, else a PATCH of the field.
|
|
309
|
+
*
|
|
310
|
+
* @param {boolean} confirmed Whether the confirm action was pressed.
|
|
311
|
+
* @return {Promise<void>}
|
|
312
|
+
* @spec openspec/changes/abstract-choice-picker/specs/choice-picker/spec.md#requirement-a-risky-choice-is-saved-only-on-purpose
|
|
313
|
+
*/
|
|
314
|
+
async save(confirmed) {
|
|
315
|
+
if (!this.selected) {
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
const request = this.content.save;
|
|
319
|
+
if (!request && !this.objectUrl) {
|
|
320
|
+
this.noticeType = 'error';
|
|
321
|
+
this.notice = this.tr('This choice cannot be saved here.');
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
this.saving = true;
|
|
325
|
+
this.notice = '';
|
|
326
|
+
try {
|
|
327
|
+
const { default: axios } = await import('@nextcloud/axios');
|
|
328
|
+
const vars = { value: this.selected.key, confirmed };
|
|
329
|
+
if (request && request.url) {
|
|
330
|
+
const method = String(request.method || 'POST').toLowerCase();
|
|
331
|
+
await axios[method](prefixUrl(String(this.resolve(request.url, vars))), this.resolve(request.payload || {}, vars));
|
|
332
|
+
} else {
|
|
333
|
+
await axios.patch(prefixUrl(this.objectUrl), { [this.content.field]: this.selected.key });
|
|
334
|
+
}
|
|
335
|
+
this.saved = this.selected.key;
|
|
336
|
+
this.noticeType = 'success';
|
|
337
|
+
this.notice = this.tr(this.content.savedText || 'Saved.');
|
|
338
|
+
/**
|
|
339
|
+
* @event saved The choice was written.
|
|
340
|
+
* @type {{field: string, value: string, confirmed: boolean}}
|
|
341
|
+
*/
|
|
342
|
+
this.$emit('saved', { field: this.content.field, value: this.saved, confirmed });
|
|
343
|
+
} catch (e) {
|
|
344
|
+
this.noticeType = 'error';
|
|
345
|
+
this.notice = serverErrorMessage(e);
|
|
346
|
+
} finally {
|
|
347
|
+
this.saving = false;
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
export { script as default };
|
|
354
|
+
//# sourceMappingURL=CnChoicePickerWidget.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnChoicePickerWidget.vue2.js","sources":["../../../../src/components/CnChoicePickerWidget/CnChoicePickerWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-choice-picker\" data-testid=\"cn-choice-picker\">\n\t\t<p v-if=\"loading\" class=\"cn-choice-picker__note\" data-testid=\"cn-choice-picker-loading\">\n\t\t\t{{ tr('Loading') }}\n\t\t</p>\n\t\t<p v-else-if=\"options.length === 0\" class=\"cn-choice-picker__note\" data-testid=\"cn-choice-picker-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<fieldset v-else class=\"cn-choice-picker__cards\">\n\t\t\t<legend class=\"cn-choice-picker__legend\">\n\t\t\t\t{{ legend }}\n\t\t\t</legend>\n\t\t\t<label\n\t\t\t\tv-for=\"option in options\"\n\t\t\t\t:key=\"option.key\"\n\t\t\t\tclass=\"cn-choice-picker__card\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'cn-choice-picker__card--selected': chosen === option.key,\n\t\t\t\t\t'cn-choice-picker__card--refused': option.refusal !== '',\n\t\t\t\t}\"\n\t\t\t\t:data-testid=\"`cn-choice-picker-option-${option.key}`\">\n\t\t\t\t<input\n\t\t\t\t\tclass=\"cn-choice-picker__input\"\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t:name=\"groupName\"\n\t\t\t\t\t:value=\"option.key\"\n\t\t\t\t\t:checked=\"chosen === option.key\"\n\t\t\t\t\t:disabled=\"option.refusal !== '' || saving\"\n\t\t\t\t\t@change=\"choose(option)\">\n\t\t\t\t<span class=\"cn-choice-picker__swatches\" aria-hidden=\"true\">\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-for=\"(colour, index) in option.swatches\"\n\t\t\t\t\t\t:key=\"index\"\n\t\t\t\t\t\tclass=\"cn-choice-picker__swatch\"\n\t\t\t\t\t\t:style=\"{ background: colour }\" />\n\t\t\t\t</span>\n\t\t\t\t<span class=\"cn-choice-picker__text\">\n\t\t\t\t\t<strong class=\"cn-choice-picker__title\">{{ option.title }}</strong>\n\t\t\t\t\t<span v-if=\"option.refusal\" class=\"cn-choice-picker__refusal\" :data-testid=\"`cn-choice-picker-refusal-${option.key}`\">\n\t\t\t\t\t\t{{ option.refusal }}\n\t\t\t\t\t</span>\n\t\t\t\t</span>\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"option.pill\"\n\t\t\t\t\t:label=\"option.pill.label\"\n\t\t\t\t\t:variant=\"option.pill.variant\"\n\t\t\t\t\tsize=\"small\" />\n\t\t\t</label>\n\t\t</fieldset>\n\n\t\t<NcNoteCard v-if=\"selected && selected.warning.length > 0\" type=\"warning\" data-testid=\"cn-choice-picker-warning\">\n\t\t\t<p v-if=\"warningIntro\" class=\"cn-choice-picker__warning-intro\">\n\t\t\t\t{{ warningIntro }}\n\t\t\t</p>\n\t\t\t<ul class=\"cn-choice-picker__warning-list\">\n\t\t\t\t<li v-for=\"(line, index) in selected.warning\" :key=\"index\">\n\t\t\t\t\t{{ line }}\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</NcNoteCard>\n\n\t\t<NcNoteCard v-if=\"notice\" :type=\"noticeType\" data-testid=\"cn-choice-picker-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\n\t\t<div v-if=\"options.length > 0 && !readOnly\" class=\"cn-choice-picker__actions\">\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"saving || !canSave\"\n\t\t\t\tdata-testid=\"cn-choice-picker-save\"\n\t\t\t\t@click=\"save(false)\">\n\t\t\t\t{{ saveLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"selected && selected.warning.length > 0\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:disabled=\"saving\"\n\t\t\t\tdata-testid=\"cn-choice-picker-confirm\"\n\t\t\t\t@click=\"save(true)\">\n\t\t\t\t{{ confirmLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<p v-if=\"hint\" class=\"cn-choice-picker__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport { NcButton, NcNoteCard } from '@nextcloud/vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { objectUrlOf } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\nlet uid = 0\n\n/**\n * CnChoicePickerWidget — the `choice-picker` widget: choice cards read from a\n * source (or a static list), each with a radio, colour swatches read from the\n * item, a title and a state pill (a verdict such as \"Leesbaar\" / \"Slecht\n * leesbaar\"), bound to one field of the CURRENT object.\n *\n * Save is a button. A card that carries a warning (a list of lines read from\n * the item) shows them in a warning band under the cards and adds a second\n * button, the confirm action, so a risky choice is saved only on purpose: the\n * request tells the server which one was pressed (`@confirmed`). A card the\n * source marks as refused is listed with its reason and cannot be chosen.\n *\n * @spec openspec/changes/abstract-choice-picker/specs/choice-picker/spec.md\n */\nexport default {\n\tname: 'CnChoicePickerWidget',\n\n\tcomponents: { CnStatusBadge, NcButton, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `field` (required) — the top-level field of the object holding the chosen key.\n\t\t * - `source` — `{ url, path?, key, label, swatches?, state?, refusal?, warning? }` (tokens `@objectId`, `@object.<field>` in the url), or `items` — the same item shape as a static list.\n\t\t * - `swatches` — path to an array of colours (CSS colour strings).\n\t\t * - `state` — `{ path, map?, variantMap?, empty?, emptyVariant? }`: the pill; `map` turns the value into text, `variantMap` into a badge variant, `empty` is the text when the value is missing.\n\t\t * - `refusal` — path to a string: the card is listed with it and cannot be chosen.\n\t\t * - `warning` — `{ list, item? }`: `list` is a path to an array; `item` a template with `{path}` placeholders for object items (strings are used as they are).\n\t\t * - `legend`, `warningIntro`, `saveLabel`, `confirmLabel`, `emptyText`, `hint`, `readOnly`.\n\t\t * - `save` — `{ method?, url?, payload? }`: a custom request (tokens `@value`, `@confirmed`, `@objectId`, `@object.<field>`); without it the field is PATCHed on the object.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\tuid += 1\n\t\treturn {\n\t\t\tgroupName: `cn-choice-picker-${uid}`,\n\t\t\tsourced: [],\n\t\t\tloading: false,\n\t\t\tsaved: '',\n\t\t\tchosen: '',\n\t\t\tsaving: false,\n\t\t\tnotice: '',\n\t\t\tnoticeType: 'success',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tspec() {\n\t\t\treturn this.content.source || {}\n\t\t},\n\n\t\t/** The cards, from the static items then the source. */\n\t\toptions() {\n\t\t\tconst items = [...(Array.isArray(this.content.items) ? this.content.items : []), ...this.sourced]\n\t\t\treturn items\n\t\t\t\t.filter((item) => item && readPath(item, this.spec.key || 'key') !== undefined)\n\t\t\t\t.map((item) => {\n\t\t\t\t\tconst key = String(readPath(item, this.spec.key || 'key'))\n\t\t\t\t\tconst refusal = this.spec.refusal ? readPath(item, this.spec.refusal) : ''\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\ttitle: String(readPath(item, this.spec.label || 'label') ?? key),\n\t\t\t\t\t\tswatches: this.listOf(item, this.spec.swatches).filter((colour) => typeof colour === 'string'),\n\t\t\t\t\t\tpill: this.pillOf(item),\n\t\t\t\t\t\trefusal: typeof refusal === 'string' ? refusal : '',\n\t\t\t\t\t\twarning: this.warningOf(item),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\tselected() {\n\t\t\treturn this.options.find((option) => option.key === this.chosen) || null\n\t\t},\n\n\t\tcanSave() {\n\t\t\treturn this.chosen !== '' && this.chosen !== this.saved && (this.selected ? this.selected.refusal === '' : false)\n\t\t},\n\n\t\tlegend() {\n\t\t\treturn this.tr(this.content.legend || 'Choose one')\n\t\t},\n\n\t\twarningIntro() {\n\t\t\treturn this.tr(this.content.warningIntro || '')\n\t\t},\n\n\t\tsaveLabel() {\n\t\t\treturn this.tr(this.content.saveLabel || 'Save')\n\t\t},\n\n\t\tconfirmLabel() {\n\t\t\treturn this.tr(this.content.confirmLabel || 'Use it anyway')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn this.tr(this.content.emptyText || 'Nothing to choose from')\n\t\t},\n\n\t\thint() {\n\t\t\treturn this.tr(this.content.hint || '')\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.adopt()\n\t\t\tthis.loadSource()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.adopt()\n\t\tthis.loadSource()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/** Read the current choice off the object. */\n\t\tadopt() {\n\t\t\tconst stored = readPath(this.objectData || {}, this.content.field)\n\t\t\tthis.saved = stored === undefined || stored === null ? '' : String(stored)\n\t\t\tthis.chosen = this.saved\n\t\t},\n\n\t\t/**\n\t\t * A list off an item.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @param {string} path The path, or undefined.\n\t\t * @return {Array}\n\t\t */\n\t\tlistOf(item, path) {\n\t\t\tconst list = path ? readPath(item, path) : []\n\t\t\treturn Array.isArray(list) ? list : []\n\t\t},\n\n\t\t/**\n\t\t * The state pill of an item.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {{label: string, variant: string}|null}\n\t\t */\n\t\tpillOf(item) {\n\t\t\tconst state = this.spec.state\n\t\t\tif (!state || !state.path) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = readPath(item, state.path)\n\t\t\tconst empty = raw === undefined || raw === null || raw === ''\n\t\t\tif (empty) {\n\t\t\t\treturn state.empty ? { label: this.tr(state.empty), variant: isBadgeVariant(state.emptyVariant) ? state.emptyVariant : 'default' } : null\n\t\t\t}\n\t\t\tconst label = state.map && Object.hasOwn(state.map, String(raw)) ? this.tr(state.map[String(raw)]) : String(raw)\n\t\t\tconst variant = state.variantMap && state.variantMap[String(raw)]\n\t\t\treturn { label, variant: isBadgeVariant(variant) ? variant : 'default' }\n\t\t},\n\n\t\t/**\n\t\t * The warning lines of an item.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string[]}\n\t\t */\n\t\twarningOf(item) {\n\t\t\tconst spec = this.spec.warning\n\t\t\tif (!spec || !spec.list) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.listOf(item, spec.list)\n\t\t\t\t.map((entry) => {\n\t\t\t\t\tif (typeof entry === 'string') {\n\t\t\t\t\t\treturn entry\n\t\t\t\t\t}\n\t\t\t\t\tif (!entry || typeof entry !== 'object' || !spec.item) {\n\t\t\t\t\t\treturn ''\n\t\t\t\t\t}\n\t\t\t\t\treturn this.tr(spec.item).replace(/\\{([\\w.]+)\\}/g, (m, path) => String(readPath(entry, path) ?? ''))\n\t\t\t\t})\n\t\t\t\t.filter((line) => line !== '')\n\t\t},\n\n\t\t/**\n\t\t * Resolve the tokens in a url or payload.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @param {object} vars `{ value, confirmed }`.\n\t\t * @return {unknown}\n\t\t */\n\t\tresolve(value, vars) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.map((v) => this.resolve(v, vars))\n\t\t\t}\n\t\t\tif (value && typeof value === 'object') {\n\t\t\t\treturn Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.resolve(v, vars)]))\n\t\t\t}\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tconst object = this.objectData || {}\n\t\t\tif (value === '@value') {\n\t\t\t\treturn vars.value\n\t\t\t}\n\t\t\tif (value === '@confirmed') {\n\t\t\t\treturn vars.confirmed\n\t\t\t}\n\t\t\tconst whole = value.match(/^@object\\.([\\w.@]+)$/)\n\t\t\tif (whole) {\n\t\t\t\treturn readPath(object, whole[1])\n\t\t\t}\n\t\t\treturn value\n\t\t\t\t.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))\n\t\t\t\t.replace(/@object\\.([\\w.@]+)/g, (m, path) => encodeURIComponent(String(readPath(object, path) ?? '')))\n\t\t\t\t.replace(/@value/g, () => encodeURIComponent(String(vars.value)))\n\t\t},\n\n\t\t/** Read the cards of `source`. */\n\t\tasync loadSource() {\n\t\t\tif (!this.spec.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { data } = await axios.get(prefixUrl(String(this.resolve(this.spec.url, { value: '', confirmed: false }))))\n\t\t\t\tconst list = this.spec.path ? readPath(data, this.spec.path) : data\n\t\t\t\tthis.sourced = Array.isArray(list) ? list : []\n\t\t\t} catch (e) {\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Choose a card (nothing is written until Save).\n\t\t *\n\t\t * @param {object} option The card.\n\t\t */\n\t\tchoose(option) {\n\t\t\tthis.chosen = option.key\n\t\t\tthis.notice = ''\n\t\t},\n\n\t\t/**\n\t\t * Save the chosen card: the configured request, else a PATCH of the field.\n\t\t *\n\t\t * @param {boolean} confirmed Whether the confirm action was pressed.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-choice-picker/specs/choice-picker/spec.md#requirement-a-risky-choice-is-saved-only-on-purpose\n\t\t */\n\t\tasync save(confirmed) {\n\t\t\tif (!this.selected) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst request = this.content.save\n\t\t\tif (!request && !this.objectUrl) {\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = this.tr('This choice cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.notice = ''\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst vars = { value: this.selected.key, confirmed }\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[method](prefixUrl(String(this.resolve(request.url, vars))), this.resolve(request.payload || {}, vars))\n\t\t\t\t} else {\n\t\t\t\t\tawait axios.patch(prefixUrl(this.objectUrl), { [this.content.field]: this.selected.key })\n\t\t\t\t}\n\t\t\t\tthis.saved = this.selected.key\n\t\t\t\tthis.noticeType = 'success'\n\t\t\t\tthis.notice = this.tr(this.content.savedText || 'Saved.')\n\t\t\t\t/**\n\t\t\t\t * @event saved The choice was written.\n\t\t\t\t * @type {{field: string, value: string, confirmed: boolean}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field: this.content.field, value: this.saved, confirmed })\n\t\t\t} catch (e) {\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-choice-picker {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmin-width: 0;\n}\n\n.cn-choice-picker__cards {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 10px;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n}\n\n.cn-choice-picker__legend {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n}\n\n.cn-choice-picker__card {\n\tposition: relative;\n\tdisplay: flex;\n\tflex: 1 1 220px;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 10px 12px;\n\tborder: 1px solid var(--cn-board-hairline, var(--color-border));\n\tborder-radius: 10px;\n\tbackground: var(--color-main-background);\n\tcursor: pointer;\n}\n\n.cn-choice-picker__card--selected {\n\tpadding: 9px 11px;\n\tborder: 2px solid var(--color-primary-element);\n}\n\n.cn-choice-picker__card--refused {\n\tcursor: not-allowed;\n\topacity: 0.7;\n}\n\n.cn-choice-picker__card:focus-within {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-choice-picker__input {\n\tflex: 0 0 auto;\n\twidth: 18px;\n\theight: 18px;\n\tmargin: 0;\n\taccent-color: var(--color-primary-element);\n}\n\n.cn-choice-picker__swatches {\n\tdisplay: flex;\n\tgap: 4px;\n}\n\n.cn-choice-picker__swatch {\n\twidth: 18px;\n\theight: 18px;\n\tbox-sizing: border-box;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 4px;\n}\n\n.cn-choice-picker__text {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-choice-picker__title {\n\tfont-size: 15px;\n}\n\n.cn-choice-picker__refusal,\n.cn-choice-picker__hint,\n.cn-choice-picker__note {\n\tmargin: 0;\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-choice-picker__warning-intro {\n\tmargin: 0 0 4px;\n}\n\n.cn-choice-picker__warning-list {\n\tmargin: 0;\n\tpadding-inline-start: 18px;\n}\n\n.cn-choice-picker__actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n</style>\n"],"names":["CnStatusBadge"],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { resolveComponent, openBlock, createElementBlock, toDisplayString, createElementVNode, Fragment, renderList, normalizeClass, normalizeStyle, createCommentVNode, createBlock, withCtx, createTextVNode, createVNode } from 'vue';
|
|
2
|
+
|
|
3
|
+
const _hoisted_1 = {
|
|
4
|
+
class: "cn-choice-picker",
|
|
5
|
+
"data-testid": "cn-choice-picker"
|
|
6
|
+
};
|
|
7
|
+
const _hoisted_2 = {
|
|
8
|
+
key: 0,
|
|
9
|
+
class: "cn-choice-picker__note",
|
|
10
|
+
"data-testid": "cn-choice-picker-loading"
|
|
11
|
+
};
|
|
12
|
+
const _hoisted_3 = {
|
|
13
|
+
key: 1,
|
|
14
|
+
class: "cn-choice-picker__note",
|
|
15
|
+
"data-testid": "cn-choice-picker-empty"
|
|
16
|
+
};
|
|
17
|
+
const _hoisted_4 = {
|
|
18
|
+
key: 2,
|
|
19
|
+
class: "cn-choice-picker__cards"
|
|
20
|
+
};
|
|
21
|
+
const _hoisted_5 = { class: "cn-choice-picker__legend" };
|
|
22
|
+
const _hoisted_6 = ["data-testid"];
|
|
23
|
+
const _hoisted_7 = ["name", "value", "checked", "disabled", "onChange"];
|
|
24
|
+
const _hoisted_8 = {
|
|
25
|
+
class: "cn-choice-picker__swatches",
|
|
26
|
+
"aria-hidden": "true"
|
|
27
|
+
};
|
|
28
|
+
const _hoisted_9 = { class: "cn-choice-picker__text" };
|
|
29
|
+
const _hoisted_10 = { class: "cn-choice-picker__title" };
|
|
30
|
+
const _hoisted_11 = ["data-testid"];
|
|
31
|
+
const _hoisted_12 = {
|
|
32
|
+
key: 0,
|
|
33
|
+
class: "cn-choice-picker__warning-intro"
|
|
34
|
+
};
|
|
35
|
+
const _hoisted_13 = { class: "cn-choice-picker__warning-list" };
|
|
36
|
+
const _hoisted_14 = {
|
|
37
|
+
key: 5,
|
|
38
|
+
class: "cn-choice-picker__actions"
|
|
39
|
+
};
|
|
40
|
+
const _hoisted_15 = {
|
|
41
|
+
key: 6,
|
|
42
|
+
class: "cn-choice-picker__hint"
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
46
|
+
const _component_CnStatusBadge = resolveComponent("CnStatusBadge");
|
|
47
|
+
const _component_NcNoteCard = resolveComponent("NcNoteCard");
|
|
48
|
+
const _component_NcButton = resolveComponent("NcButton");
|
|
49
|
+
|
|
50
|
+
return (openBlock(), createElementBlock("div", _hoisted_1, [
|
|
51
|
+
($data.loading)
|
|
52
|
+
? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString($options.tr('Loading')), 1 /* TEXT */))
|
|
53
|
+
: ($options.options.length === 0)
|
|
54
|
+
? (openBlock(), createElementBlock("p", _hoisted_3, toDisplayString($options.emptyLabel), 1 /* TEXT */))
|
|
55
|
+
: (openBlock(), createElementBlock("fieldset", _hoisted_4, [
|
|
56
|
+
createElementVNode("legend", _hoisted_5, toDisplayString($options.legend), 1 /* TEXT */),
|
|
57
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($options.options, (option) => {
|
|
58
|
+
return (openBlock(), createElementBlock("label", {
|
|
59
|
+
key: option.key,
|
|
60
|
+
class: normalizeClass(["cn-choice-picker__card", {
|
|
61
|
+
'cn-choice-picker__card--selected': $data.chosen === option.key,
|
|
62
|
+
'cn-choice-picker__card--refused': option.refusal !== '',
|
|
63
|
+
}]),
|
|
64
|
+
"data-testid": `cn-choice-picker-option-${option.key}`
|
|
65
|
+
}, [
|
|
66
|
+
createElementVNode("input", {
|
|
67
|
+
class: "cn-choice-picker__input",
|
|
68
|
+
type: "radio",
|
|
69
|
+
name: $data.groupName,
|
|
70
|
+
value: option.key,
|
|
71
|
+
checked: $data.chosen === option.key,
|
|
72
|
+
disabled: option.refusal !== '' || $data.saving,
|
|
73
|
+
onChange: $event => ($options.choose(option))
|
|
74
|
+
}, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_7),
|
|
75
|
+
createElementVNode("span", _hoisted_8, [
|
|
76
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(option.swatches, (colour, index) => {
|
|
77
|
+
return (openBlock(), createElementBlock("span", {
|
|
78
|
+
key: index,
|
|
79
|
+
class: "cn-choice-picker__swatch",
|
|
80
|
+
style: normalizeStyle({ background: colour })
|
|
81
|
+
}, null, 4 /* STYLE */))
|
|
82
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
83
|
+
]),
|
|
84
|
+
createElementVNode("span", _hoisted_9, [
|
|
85
|
+
createElementVNode("strong", _hoisted_10, toDisplayString(option.title), 1 /* TEXT */),
|
|
86
|
+
(option.refusal)
|
|
87
|
+
? (openBlock(), createElementBlock("span", {
|
|
88
|
+
key: 0,
|
|
89
|
+
class: "cn-choice-picker__refusal",
|
|
90
|
+
"data-testid": `cn-choice-picker-refusal-${option.key}`
|
|
91
|
+
}, toDisplayString(option.refusal), 9 /* TEXT, PROPS */, _hoisted_11))
|
|
92
|
+
: createCommentVNode("v-if", true)
|
|
93
|
+
]),
|
|
94
|
+
(option.pill)
|
|
95
|
+
? (openBlock(), createBlock(_component_CnStatusBadge, {
|
|
96
|
+
key: 0,
|
|
97
|
+
label: option.pill.label,
|
|
98
|
+
variant: option.pill.variant,
|
|
99
|
+
size: "small"
|
|
100
|
+
}, null, 8 /* PROPS */, ["label", "variant"]))
|
|
101
|
+
: createCommentVNode("v-if", true)
|
|
102
|
+
], 10 /* CLASS, PROPS */, _hoisted_6))
|
|
103
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
104
|
+
])),
|
|
105
|
+
($options.selected && $options.selected.warning.length > 0)
|
|
106
|
+
? (openBlock(), createBlock(_component_NcNoteCard, {
|
|
107
|
+
key: 3,
|
|
108
|
+
type: "warning",
|
|
109
|
+
"data-testid": "cn-choice-picker-warning"
|
|
110
|
+
}, {
|
|
111
|
+
default: withCtx(() => [
|
|
112
|
+
($options.warningIntro)
|
|
113
|
+
? (openBlock(), createElementBlock("p", _hoisted_12, toDisplayString($options.warningIntro), 1 /* TEXT */))
|
|
114
|
+
: createCommentVNode("v-if", true),
|
|
115
|
+
createElementVNode("ul", _hoisted_13, [
|
|
116
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($options.selected.warning, (line, index) => {
|
|
117
|
+
return (openBlock(), createElementBlock("li", { key: index }, toDisplayString(line), 1 /* TEXT */))
|
|
118
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
119
|
+
])
|
|
120
|
+
]),
|
|
121
|
+
_: 1 /* STABLE */
|
|
122
|
+
}))
|
|
123
|
+
: createCommentVNode("v-if", true),
|
|
124
|
+
($data.notice)
|
|
125
|
+
? (openBlock(), createBlock(_component_NcNoteCard, {
|
|
126
|
+
key: 4,
|
|
127
|
+
type: $data.noticeType,
|
|
128
|
+
"data-testid": "cn-choice-picker-notice"
|
|
129
|
+
}, {
|
|
130
|
+
default: withCtx(() => [
|
|
131
|
+
createTextVNode(toDisplayString($data.notice), 1 /* TEXT */)
|
|
132
|
+
]),
|
|
133
|
+
_: 1 /* STABLE */
|
|
134
|
+
}, 8 /* PROPS */, ["type"]))
|
|
135
|
+
: createCommentVNode("v-if", true),
|
|
136
|
+
($options.options.length > 0 && !$options.readOnly)
|
|
137
|
+
? (openBlock(), createElementBlock("div", _hoisted_14, [
|
|
138
|
+
createVNode(_component_NcButton, {
|
|
139
|
+
variant: "primary",
|
|
140
|
+
disabled: $data.saving || !$options.canSave,
|
|
141
|
+
"data-testid": "cn-choice-picker-save",
|
|
142
|
+
onClick: _cache[0] || (_cache[0] = $event => ($options.save(false)))
|
|
143
|
+
}, {
|
|
144
|
+
default: withCtx(() => [
|
|
145
|
+
createTextVNode(toDisplayString($options.saveLabel), 1 /* TEXT */)
|
|
146
|
+
]),
|
|
147
|
+
_: 1 /* STABLE */
|
|
148
|
+
}, 8 /* PROPS */, ["disabled"]),
|
|
149
|
+
($options.selected && $options.selected.warning.length > 0)
|
|
150
|
+
? (openBlock(), createBlock(_component_NcButton, {
|
|
151
|
+
key: 0,
|
|
152
|
+
variant: "secondary",
|
|
153
|
+
disabled: $data.saving,
|
|
154
|
+
"data-testid": "cn-choice-picker-confirm",
|
|
155
|
+
onClick: _cache[1] || (_cache[1] = $event => ($options.save(true)))
|
|
156
|
+
}, {
|
|
157
|
+
default: withCtx(() => [
|
|
158
|
+
createTextVNode(toDisplayString($options.confirmLabel), 1 /* TEXT */)
|
|
159
|
+
]),
|
|
160
|
+
_: 1 /* STABLE */
|
|
161
|
+
}, 8 /* PROPS */, ["disabled"]))
|
|
162
|
+
: createCommentVNode("v-if", true)
|
|
163
|
+
]))
|
|
164
|
+
: createCommentVNode("v-if", true),
|
|
165
|
+
($options.hint)
|
|
166
|
+
? (openBlock(), createElementBlock("p", _hoisted_15, toDisplayString($options.hint), 1 /* TEXT */))
|
|
167
|
+
: createCommentVNode("v-if", true)
|
|
168
|
+
]))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export { render };
|
|
172
|
+
//# sourceMappingURL=CnChoicePickerWidget.vue3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnChoicePickerWidget.vue3.js","sources":["../../../../src/components/CnChoicePickerWidget/CnChoicePickerWidget.vue?vue&type=template&id=7075cbe2&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-choice-picker\" data-testid=\"cn-choice-picker\">\n\t\t<p v-if=\"loading\" class=\"cn-choice-picker__note\" data-testid=\"cn-choice-picker-loading\">\n\t\t\t{{ tr('Loading') }}\n\t\t</p>\n\t\t<p v-else-if=\"options.length === 0\" class=\"cn-choice-picker__note\" data-testid=\"cn-choice-picker-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<fieldset v-else class=\"cn-choice-picker__cards\">\n\t\t\t<legend class=\"cn-choice-picker__legend\">\n\t\t\t\t{{ legend }}\n\t\t\t</legend>\n\t\t\t<label\n\t\t\t\tv-for=\"option in options\"\n\t\t\t\t:key=\"option.key\"\n\t\t\t\tclass=\"cn-choice-picker__card\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'cn-choice-picker__card--selected': chosen === option.key,\n\t\t\t\t\t'cn-choice-picker__card--refused': option.refusal !== '',\n\t\t\t\t}\"\n\t\t\t\t:data-testid=\"`cn-choice-picker-option-${option.key}`\">\n\t\t\t\t<input\n\t\t\t\t\tclass=\"cn-choice-picker__input\"\n\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t:name=\"groupName\"\n\t\t\t\t\t:value=\"option.key\"\n\t\t\t\t\t:checked=\"chosen === option.key\"\n\t\t\t\t\t:disabled=\"option.refusal !== '' || saving\"\n\t\t\t\t\t@change=\"choose(option)\">\n\t\t\t\t<span class=\"cn-choice-picker__swatches\" aria-hidden=\"true\">\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-for=\"(colour, index) in option.swatches\"\n\t\t\t\t\t\t:key=\"index\"\n\t\t\t\t\t\tclass=\"cn-choice-picker__swatch\"\n\t\t\t\t\t\t:style=\"{ background: colour }\" />\n\t\t\t\t</span>\n\t\t\t\t<span class=\"cn-choice-picker__text\">\n\t\t\t\t\t<strong class=\"cn-choice-picker__title\">{{ option.title }}</strong>\n\t\t\t\t\t<span v-if=\"option.refusal\" class=\"cn-choice-picker__refusal\" :data-testid=\"`cn-choice-picker-refusal-${option.key}`\">\n\t\t\t\t\t\t{{ option.refusal }}\n\t\t\t\t\t</span>\n\t\t\t\t</span>\n\t\t\t\t<CnStatusBadge\n\t\t\t\t\tv-if=\"option.pill\"\n\t\t\t\t\t:label=\"option.pill.label\"\n\t\t\t\t\t:variant=\"option.pill.variant\"\n\t\t\t\t\tsize=\"small\" />\n\t\t\t</label>\n\t\t</fieldset>\n\n\t\t<NcNoteCard v-if=\"selected && selected.warning.length > 0\" type=\"warning\" data-testid=\"cn-choice-picker-warning\">\n\t\t\t<p v-if=\"warningIntro\" class=\"cn-choice-picker__warning-intro\">\n\t\t\t\t{{ warningIntro }}\n\t\t\t</p>\n\t\t\t<ul class=\"cn-choice-picker__warning-list\">\n\t\t\t\t<li v-for=\"(line, index) in selected.warning\" :key=\"index\">\n\t\t\t\t\t{{ line }}\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</NcNoteCard>\n\n\t\t<NcNoteCard v-if=\"notice\" :type=\"noticeType\" data-testid=\"cn-choice-picker-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\n\t\t<div v-if=\"options.length > 0 && !readOnly\" class=\"cn-choice-picker__actions\">\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"saving || !canSave\"\n\t\t\t\tdata-testid=\"cn-choice-picker-save\"\n\t\t\t\t@click=\"save(false)\">\n\t\t\t\t{{ saveLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"selected && selected.warning.length > 0\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:disabled=\"saving\"\n\t\t\t\tdata-testid=\"cn-choice-picker-confirm\"\n\t\t\t\t@click=\"save(true)\">\n\t\t\t\t{{ confirmLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<p v-if=\"hint\" class=\"cn-choice-picker__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport { NcButton, NcNoteCard } from '@nextcloud/vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { objectUrlOf } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\nlet uid = 0\n\n/**\n * CnChoicePickerWidget — the `choice-picker` widget: choice cards read from a\n * source (or a static list), each with a radio, colour swatches read from the\n * item, a title and a state pill (a verdict such as \"Leesbaar\" / \"Slecht\n * leesbaar\"), bound to one field of the CURRENT object.\n *\n * Save is a button. A card that carries a warning (a list of lines read from\n * the item) shows them in a warning band under the cards and adds a second\n * button, the confirm action, so a risky choice is saved only on purpose: the\n * request tells the server which one was pressed (`@confirmed`). A card the\n * source marks as refused is listed with its reason and cannot be chosen.\n *\n * @spec openspec/changes/abstract-choice-picker/specs/choice-picker/spec.md\n */\nexport default {\n\tname: 'CnChoicePickerWidget',\n\n\tcomponents: { CnStatusBadge, NcButton, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `field` (required) — the top-level field of the object holding the chosen key.\n\t\t * - `source` — `{ url, path?, key, label, swatches?, state?, refusal?, warning? }` (tokens `@objectId`, `@object.<field>` in the url), or `items` — the same item shape as a static list.\n\t\t * - `swatches` — path to an array of colours (CSS colour strings).\n\t\t * - `state` — `{ path, map?, variantMap?, empty?, emptyVariant? }`: the pill; `map` turns the value into text, `variantMap` into a badge variant, `empty` is the text when the value is missing.\n\t\t * - `refusal` — path to a string: the card is listed with it and cannot be chosen.\n\t\t * - `warning` — `{ list, item? }`: `list` is a path to an array; `item` a template with `{path}` placeholders for object items (strings are used as they are).\n\t\t * - `legend`, `warningIntro`, `saveLabel`, `confirmLabel`, `emptyText`, `hint`, `readOnly`.\n\t\t * - `save` — `{ method?, url?, payload? }`: a custom request (tokens `@value`, `@confirmed`, `@objectId`, `@object.<field>`); without it the field is PATCHed on the object.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\tuid += 1\n\t\treturn {\n\t\t\tgroupName: `cn-choice-picker-${uid}`,\n\t\t\tsourced: [],\n\t\t\tloading: false,\n\t\t\tsaved: '',\n\t\t\tchosen: '',\n\t\t\tsaving: false,\n\t\t\tnotice: '',\n\t\t\tnoticeType: 'success',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tspec() {\n\t\t\treturn this.content.source || {}\n\t\t},\n\n\t\t/** The cards, from the static items then the source. */\n\t\toptions() {\n\t\t\tconst items = [...(Array.isArray(this.content.items) ? this.content.items : []), ...this.sourced]\n\t\t\treturn items\n\t\t\t\t.filter((item) => item && readPath(item, this.spec.key || 'key') !== undefined)\n\t\t\t\t.map((item) => {\n\t\t\t\t\tconst key = String(readPath(item, this.spec.key || 'key'))\n\t\t\t\t\tconst refusal = this.spec.refusal ? readPath(item, this.spec.refusal) : ''\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\ttitle: String(readPath(item, this.spec.label || 'label') ?? key),\n\t\t\t\t\t\tswatches: this.listOf(item, this.spec.swatches).filter((colour) => typeof colour === 'string'),\n\t\t\t\t\t\tpill: this.pillOf(item),\n\t\t\t\t\t\trefusal: typeof refusal === 'string' ? refusal : '',\n\t\t\t\t\t\twarning: this.warningOf(item),\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\tselected() {\n\t\t\treturn this.options.find((option) => option.key === this.chosen) || null\n\t\t},\n\n\t\tcanSave() {\n\t\t\treturn this.chosen !== '' && this.chosen !== this.saved && (this.selected ? this.selected.refusal === '' : false)\n\t\t},\n\n\t\tlegend() {\n\t\t\treturn this.tr(this.content.legend || 'Choose one')\n\t\t},\n\n\t\twarningIntro() {\n\t\t\treturn this.tr(this.content.warningIntro || '')\n\t\t},\n\n\t\tsaveLabel() {\n\t\t\treturn this.tr(this.content.saveLabel || 'Save')\n\t\t},\n\n\t\tconfirmLabel() {\n\t\t\treturn this.tr(this.content.confirmLabel || 'Use it anyway')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn this.tr(this.content.emptyText || 'Nothing to choose from')\n\t\t},\n\n\t\thint() {\n\t\t\treturn this.tr(this.content.hint || '')\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.adopt()\n\t\t\tthis.loadSource()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.adopt()\n\t\tthis.loadSource()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/** Read the current choice off the object. */\n\t\tadopt() {\n\t\t\tconst stored = readPath(this.objectData || {}, this.content.field)\n\t\t\tthis.saved = stored === undefined || stored === null ? '' : String(stored)\n\t\t\tthis.chosen = this.saved\n\t\t},\n\n\t\t/**\n\t\t * A list off an item.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @param {string} path The path, or undefined.\n\t\t * @return {Array}\n\t\t */\n\t\tlistOf(item, path) {\n\t\t\tconst list = path ? readPath(item, path) : []\n\t\t\treturn Array.isArray(list) ? list : []\n\t\t},\n\n\t\t/**\n\t\t * The state pill of an item.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {{label: string, variant: string}|null}\n\t\t */\n\t\tpillOf(item) {\n\t\t\tconst state = this.spec.state\n\t\t\tif (!state || !state.path) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = readPath(item, state.path)\n\t\t\tconst empty = raw === undefined || raw === null || raw === ''\n\t\t\tif (empty) {\n\t\t\t\treturn state.empty ? { label: this.tr(state.empty), variant: isBadgeVariant(state.emptyVariant) ? state.emptyVariant : 'default' } : null\n\t\t\t}\n\t\t\tconst label = state.map && Object.hasOwn(state.map, String(raw)) ? this.tr(state.map[String(raw)]) : String(raw)\n\t\t\tconst variant = state.variantMap && state.variantMap[String(raw)]\n\t\t\treturn { label, variant: isBadgeVariant(variant) ? variant : 'default' }\n\t\t},\n\n\t\t/**\n\t\t * The warning lines of an item.\n\t\t *\n\t\t * @param {object} item The item.\n\t\t * @return {string[]}\n\t\t */\n\t\twarningOf(item) {\n\t\t\tconst spec = this.spec.warning\n\t\t\tif (!spec || !spec.list) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.listOf(item, spec.list)\n\t\t\t\t.map((entry) => {\n\t\t\t\t\tif (typeof entry === 'string') {\n\t\t\t\t\t\treturn entry\n\t\t\t\t\t}\n\t\t\t\t\tif (!entry || typeof entry !== 'object' || !spec.item) {\n\t\t\t\t\t\treturn ''\n\t\t\t\t\t}\n\t\t\t\t\treturn this.tr(spec.item).replace(/\\{([\\w.]+)\\}/g, (m, path) => String(readPath(entry, path) ?? ''))\n\t\t\t\t})\n\t\t\t\t.filter((line) => line !== '')\n\t\t},\n\n\t\t/**\n\t\t * Resolve the tokens in a url or payload.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @param {object} vars `{ value, confirmed }`.\n\t\t * @return {unknown}\n\t\t */\n\t\tresolve(value, vars) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.map((v) => this.resolve(v, vars))\n\t\t\t}\n\t\t\tif (value && typeof value === 'object') {\n\t\t\t\treturn Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.resolve(v, vars)]))\n\t\t\t}\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tconst object = this.objectData || {}\n\t\t\tif (value === '@value') {\n\t\t\t\treturn vars.value\n\t\t\t}\n\t\t\tif (value === '@confirmed') {\n\t\t\t\treturn vars.confirmed\n\t\t\t}\n\t\t\tconst whole = value.match(/^@object\\.([\\w.@]+)$/)\n\t\t\tif (whole) {\n\t\t\t\treturn readPath(object, whole[1])\n\t\t\t}\n\t\t\treturn value\n\t\t\t\t.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))\n\t\t\t\t.replace(/@object\\.([\\w.@]+)/g, (m, path) => encodeURIComponent(String(readPath(object, path) ?? '')))\n\t\t\t\t.replace(/@value/g, () => encodeURIComponent(String(vars.value)))\n\t\t},\n\n\t\t/** Read the cards of `source`. */\n\t\tasync loadSource() {\n\t\t\tif (!this.spec.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst { data } = await axios.get(prefixUrl(String(this.resolve(this.spec.url, { value: '', confirmed: false }))))\n\t\t\t\tconst list = this.spec.path ? readPath(data, this.spec.path) : data\n\t\t\t\tthis.sourced = Array.isArray(list) ? list : []\n\t\t\t} catch (e) {\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Choose a card (nothing is written until Save).\n\t\t *\n\t\t * @param {object} option The card.\n\t\t */\n\t\tchoose(option) {\n\t\t\tthis.chosen = option.key\n\t\t\tthis.notice = ''\n\t\t},\n\n\t\t/**\n\t\t * Save the chosen card: the configured request, else a PATCH of the field.\n\t\t *\n\t\t * @param {boolean} confirmed Whether the confirm action was pressed.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-choice-picker/specs/choice-picker/spec.md#requirement-a-risky-choice-is-saved-only-on-purpose\n\t\t */\n\t\tasync save(confirmed) {\n\t\t\tif (!this.selected) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst request = this.content.save\n\t\t\tif (!request && !this.objectUrl) {\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = this.tr('This choice cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.notice = ''\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst vars = { value: this.selected.key, confirmed }\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[method](prefixUrl(String(this.resolve(request.url, vars))), this.resolve(request.payload || {}, vars))\n\t\t\t\t} else {\n\t\t\t\t\tawait axios.patch(prefixUrl(this.objectUrl), { [this.content.field]: this.selected.key })\n\t\t\t\t}\n\t\t\t\tthis.saved = this.selected.key\n\t\t\t\tthis.noticeType = 'success'\n\t\t\t\tthis.notice = this.tr(this.content.savedText || 'Saved.')\n\t\t\t\t/**\n\t\t\t\t * @event saved The choice was written.\n\t\t\t\t * @type {{field: string, value: string, confirmed: boolean}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field: this.content.field, value: this.saved, confirmed })\n\t\t\t} catch (e) {\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-choice-picker {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmin-width: 0;\n}\n\n.cn-choice-picker__cards {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 10px;\n\tmargin: 0;\n\tpadding: 0;\n\tborder: 0;\n}\n\n.cn-choice-picker__legend {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n}\n\n.cn-choice-picker__card {\n\tposition: relative;\n\tdisplay: flex;\n\tflex: 1 1 220px;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 10px 12px;\n\tborder: 1px solid var(--cn-board-hairline, var(--color-border));\n\tborder-radius: 10px;\n\tbackground: var(--color-main-background);\n\tcursor: pointer;\n}\n\n.cn-choice-picker__card--selected {\n\tpadding: 9px 11px;\n\tborder: 2px solid var(--color-primary-element);\n}\n\n.cn-choice-picker__card--refused {\n\tcursor: not-allowed;\n\topacity: 0.7;\n}\n\n.cn-choice-picker__card:focus-within {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 2px;\n}\n\n.cn-choice-picker__input {\n\tflex: 0 0 auto;\n\twidth: 18px;\n\theight: 18px;\n\tmargin: 0;\n\taccent-color: var(--color-primary-element);\n}\n\n.cn-choice-picker__swatches {\n\tdisplay: flex;\n\tgap: 4px;\n}\n\n.cn-choice-picker__swatch {\n\twidth: 18px;\n\theight: 18px;\n\tbox-sizing: border-box;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 4px;\n}\n\n.cn-choice-picker__text {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-choice-picker__title {\n\tfont-size: 15px;\n}\n\n.cn-choice-picker__refusal,\n.cn-choice-picker__hint,\n.cn-choice-picker__note {\n\tmargin: 0;\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-choice-picker__warning-intro {\n\tmargin: 0 0 4px;\n}\n\n.cn-choice-picker__warning-list {\n\tmargin: 0;\n\tpadding-inline-start: 18px;\n}\n\n.cn-choice-picker__actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n}\n</style>\n"],"names":["_createElementBlock","_toDisplayString","_createElementVNode","_Fragment","_renderList","_openBlock","_createBlock"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import __sfc_main from './CnChoicePickerWidget.vue.js';
|
|
2
|
+
import { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
6
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
7
|
+
*
|
|
8
|
+
* CnChoicePickerWidget — self-registers the `choice-picker` widget type (choice
|
|
9
|
+
* cards with colour swatches and a state pill, and a confirm-with-warning save)
|
|
10
|
+
* into the shared dashboardWidgetRegistry at module load.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
registerDashboardWidget('choice-picker', {
|
|
15
|
+
renderer: __sfc_main,
|
|
16
|
+
form: null,
|
|
17
|
+
defaultContent: {
|
|
18
|
+
field: '',
|
|
19
|
+
items: [],
|
|
20
|
+
},
|
|
21
|
+
displayName: 'Choice picker',
|
|
22
|
+
icon: 'Palette',
|
|
23
|
+
surfaces: ['detail-page'],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export { __sfc_main as CnChoicePickerWidget, __sfc_main as default };
|
|
27
|
+
//# sourceMappingURL=index.js.map
|