@conduction/nextcloud-vue 2.98.0 → 2.99.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js +12 -0
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js +11 -2
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue.js +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue2.js.map +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js +1 -1
- package/dist/esm/components/CnBreadcrumbs/CnBreadcrumbs.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +2 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +26 -7
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +78 -17
- package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +9 -0
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js.map +1 -0
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js +265 -0
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -0
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +191 -0
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -0
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue.js +9 -0
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue.js.map +1 -0
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue2.js +508 -0
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue2.js.map +1 -0
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue3.js +99 -0
- package/dist/esm/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue3.js.map +1 -0
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue.js +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js +18 -70
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js +6 -44
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue.js +9 -0
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue.js.map +1 -0
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue2.js +472 -0
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue3.js +231 -0
- package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnWorkingCalendarWidget/index.js +27 -0
- package/dist/esm/components/CnWorkingCalendarWidget/index.js.map +1 -0
- package/dist/esm/composables/useFlowStore.js +2 -1
- package/dist/esm/composables/useFlowStore.js.map +1 -1
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +95 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +109 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +660 -81
- package/dist/esm/utils/libraryWidgetKeys.js +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/workingCalendarMonth.js +85 -0
- package/dist/esm/utils/workingCalendarMonth.js.map +1 -0
- package/dist/nextcloud-vue.cjs.js +9355 -7303
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +660 -81
- package/l10n/en.json +95 -1
- package/l10n/nl.json +109 -1
- package/package.json +1 -1
- package/src/components/CnActionsMenu/CnActionsMenu.vue +14 -1
- package/src/components/CnBreadcrumbs/CnBreadcrumbs.vue +1 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +1 -0
- package/src/components/CnOrderedListField/CnOrderedListField.vue +81 -9
- package/src/components/CnSettingsField/CnSettingsField.vue +449 -0
- package/src/components/CnSettingsField/index.js +4 -0
- package/src/components/CnSettingsFieldsSection/CnSettingsFieldsSection.vue +613 -0
- package/src/components/CnSettingsFieldsSection/index.js +4 -0
- package/src/components/CnSettingsPage/CnSettingsPage.vue +6 -86
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
- package/src/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue +725 -0
- package/src/components/CnWorkingCalendarWidget/index.js +26 -0
- package/src/components/index.js +3 -0
- package/src/composables/useFlowStore.js +2 -1
- package/src/css/badge.css +32 -16
- package/src/css/look-board-detail.css +80 -8
- package/src/css/look-board-index.css +52 -8
- package/src/css/look-board.css +219 -1
- package/src/index.js +3 -0
- package/src/utils/libraryWidgetKeys.js +1 -0
- package/src/utils/workingCalendarMonth.js +82 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import axios__default from '@nextcloud/axios';
|
|
2
|
+
import { translate } from '@nextcloud/l10n';
|
|
3
|
+
import { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue';
|
|
4
|
+
import { prefixUrl, buildHeaders } from '../../utils/headers.js';
|
|
5
|
+
import { readPath } from '../../utils/readPath.js';
|
|
6
|
+
import { serverErrorMessage } from '../../utils/serverErrorMessage.js';
|
|
7
|
+
|
|
8
|
+
let fieldUid = 0;
|
|
9
|
+
|
|
10
|
+
/** Field types and the names CnSettingsPage's manifest uses for them. */
|
|
11
|
+
const KIND_ALIASES = { enum: 'select', string: 'text' };
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* CnSettingsField - one settings field: the control for its type with its
|
|
15
|
+
* label, and under it an error or a hint. Shared by CnSettingsPage and
|
|
16
|
+
* CnSettingsFieldsSection.
|
|
17
|
+
*
|
|
18
|
+
* Types: `text` (default), `textarea`, `number`, `switch`, `boolean` (a checkbox),
|
|
19
|
+
* `select` (`enum`) with static `options` or options read from `optionsUrl`,
|
|
20
|
+
* `password` (a masked input that shows its value back) and `secret`
|
|
21
|
+
* (replace-only: the input stays empty, and with `secretSet` says a value is
|
|
22
|
+
* stored; the host sends it only when something is typed), and `image` (a
|
|
23
|
+
* preview tile, the initials without an image, and an upload button that
|
|
24
|
+
* posts the file to `uploadUrl` at once and emits `uploaded`).
|
|
25
|
+
*
|
|
26
|
+
* ```vue
|
|
27
|
+
* <CnSettingsField
|
|
28
|
+
* :field="{ key: 'apiKey', label: 'API key', type: 'secret', secretSet: true }"
|
|
29
|
+
* v-model="form.apiKey" />
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
var script = {
|
|
33
|
+
name: 'CnSettingsField',
|
|
34
|
+
|
|
35
|
+
components: { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField },
|
|
36
|
+
|
|
37
|
+
props: {
|
|
38
|
+
/**
|
|
39
|
+
* The field: `{ key, label, type?, options?, optionsUrl?, optionsPath?,
|
|
40
|
+
* optionLabel?, optionValue?, placeholder?, rows?, min?, max?, required?,
|
|
41
|
+
* readOnly?, secretSet? }`. `label` arrives translated.
|
|
42
|
+
*
|
|
43
|
+
* @type {object}
|
|
44
|
+
*/
|
|
45
|
+
field: {
|
|
46
|
+
type: Object,
|
|
47
|
+
required: true,
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The value: text, a number, a boolean or a select value. Any type,
|
|
52
|
+
* because a Boolean in a type list would read an empty string as true.
|
|
53
|
+
*/
|
|
54
|
+
modelValue: {
|
|
55
|
+
type: null,
|
|
56
|
+
default: null,
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
/** A validation message, drawn under the control and tied to it. */
|
|
60
|
+
error: {
|
|
61
|
+
type: String,
|
|
62
|
+
default: '',
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
/** A hint under the control (not drawn while there is an error). */
|
|
66
|
+
hint: {
|
|
67
|
+
type: String,
|
|
68
|
+
default: '',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
emits: ['update:modelValue', 'uploaded'],
|
|
73
|
+
|
|
74
|
+
data() {
|
|
75
|
+
fieldUid += 1;
|
|
76
|
+
return {
|
|
77
|
+
uid: fieldUid,
|
|
78
|
+
fetchedOptions: null,
|
|
79
|
+
optionsLoading: false,
|
|
80
|
+
uploading: false,
|
|
81
|
+
uploadError: '',
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
computed: {
|
|
86
|
+
/** @return {string} The control kind. */
|
|
87
|
+
kind() {
|
|
88
|
+
const type = String(this.field.type || 'text');
|
|
89
|
+
return KIND_ALIASES[type] || type
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
/** @return {string} The label. */
|
|
93
|
+
label() {
|
|
94
|
+
return String(this.field.label || this.field.key || '')
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/** @return {string} The control's id. */
|
|
98
|
+
inputId() {
|
|
99
|
+
return `cn-settings-field-${this.uid}-${String(this.field.key).replace(/[^A-Za-z0-9_-]/g, '-')}`
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/** @return {string} The message shown under the control: an upload failure, else `error`. */
|
|
103
|
+
shownError() {
|
|
104
|
+
return this.uploadError || this.error
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/** @return {string|null} The id of the error or hint the control is described by. */
|
|
108
|
+
describedBy() {
|
|
109
|
+
if (this.shownError) {
|
|
110
|
+
return `${this.inputId}-error`
|
|
111
|
+
}
|
|
112
|
+
return this.hint ? `${this.inputId}-hint` : null
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
/** @return {string} The value as text for a text control. */
|
|
116
|
+
stringValue() {
|
|
117
|
+
return this.modelValue === null || this.modelValue === undefined ? '' : String(this.modelValue)
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/** @return {string} The placeholder of a secret that is stored. */
|
|
121
|
+
secretSetPlaceholder() {
|
|
122
|
+
return translate('nextcloud-vue', 'Stored. Type a new value to replace it.')
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The select options as `{ label, value }`: the static `options` (strings,
|
|
127
|
+
* numbers or objects), or those read from `optionsUrl`.
|
|
128
|
+
*
|
|
129
|
+
* @return {Array<{label: string, value: (string|number|boolean)}>}
|
|
130
|
+
*/
|
|
131
|
+
normalizedOptions() {
|
|
132
|
+
const raw = Array.isArray(this.field.options) ? this.field.options : (this.fetchedOptions || []);
|
|
133
|
+
return raw.map((option) => (option && typeof option === 'object'
|
|
134
|
+
? { ...option, label: String(option.label ?? option.value ?? ''), value: option.value }
|
|
135
|
+
: { label: String(option), value: option }))
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/** @return {object|null} The option the value selects, for NcSelect. */
|
|
139
|
+
selectedOption() {
|
|
140
|
+
if (this.modelValue === null || this.modelValue === undefined || this.modelValue === '') {
|
|
141
|
+
return null
|
|
142
|
+
}
|
|
143
|
+
return this.normalizedOptions.find((option) => option.value === this.modelValue)
|
|
144
|
+
|| { label: String(this.modelValue), value: this.modelValue }
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
watch: {
|
|
149
|
+
'field.optionsUrl': {
|
|
150
|
+
handler() {
|
|
151
|
+
this.loadOptions();
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
immediate: true,
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
methods: {
|
|
159
|
+
t: translate,
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Upload a chosen image to `uploadUrl` as multipart form data (the
|
|
163
|
+
* file under `uploadField`, default `image`, plus `uploadParams`), then
|
|
164
|
+
* take the new image url from the answer at `uploadValuePath` (or a
|
|
165
|
+
* cache-busted `previewUrl`).
|
|
166
|
+
*
|
|
167
|
+
* @param {File|undefined} file The chosen file.
|
|
168
|
+
* @return {Promise<void>}
|
|
169
|
+
* @spec openspec/changes/settings-fields-section/specs/settings-fields-section/spec.md#requirement-an-image-field-uploads-at-once
|
|
170
|
+
*/
|
|
171
|
+
async upload(file) {
|
|
172
|
+
if (!file || !this.field.uploadUrl) {
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
const form = new FormData();
|
|
176
|
+
for (const [name, value] of Object.entries(this.field.uploadParams || {})) {
|
|
177
|
+
form.append(name, value);
|
|
178
|
+
}
|
|
179
|
+
form.append(this.field.uploadField || 'image', file);
|
|
180
|
+
this.uploading = true;
|
|
181
|
+
this.uploadError = '';
|
|
182
|
+
try {
|
|
183
|
+
const response = await axios__default.post(prefixUrl(this.field.uploadUrl), form);
|
|
184
|
+
const fromAnswer = this.field.uploadValuePath ? readPath(response?.data, this.field.uploadValuePath) : '';
|
|
185
|
+
const next = fromAnswer || (this.field.previewUrl ? `${prefixUrl(this.field.previewUrl)}${this.field.previewUrl.includes('?') ? '&' : '?'}v=${Date.now()}` : '');
|
|
186
|
+
/**
|
|
187
|
+
* @event uploaded An image was uploaded. Payload: its new url.
|
|
188
|
+
*/
|
|
189
|
+
this.$emit('uploaded', next);
|
|
190
|
+
} catch (error) {
|
|
191
|
+
this.uploadError = translate('nextcloud-vue', 'The image could not be uploaded: {reason}', { reason: serverErrorMessage(error) });
|
|
192
|
+
} finally {
|
|
193
|
+
this.uploading = false;
|
|
194
|
+
if (this.$refs.file) {
|
|
195
|
+
this.$refs.file.value = '';
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Report a new value.
|
|
202
|
+
*
|
|
203
|
+
* @param {unknown} value The value.
|
|
204
|
+
* @return {void}
|
|
205
|
+
*/
|
|
206
|
+
emitValue(value) {
|
|
207
|
+
/**
|
|
208
|
+
* @event update:modelValue The value changed. Payload: the new value.
|
|
209
|
+
*/
|
|
210
|
+
this.$emit('update:modelValue', value);
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The storable value of what NcSelect emits.
|
|
215
|
+
*
|
|
216
|
+
* @param {object|string|number|null} emitted An option, or null on clear.
|
|
217
|
+
* @return {string|number|boolean|null}
|
|
218
|
+
*/
|
|
219
|
+
optionValue(emitted) {
|
|
220
|
+
if (emitted === null || emitted === undefined) {
|
|
221
|
+
return null
|
|
222
|
+
}
|
|
223
|
+
return typeof emitted === 'object' && 'value' in emitted ? emitted.value : emitted
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Read a sourced select's options: a list (or the list at
|
|
228
|
+
* `optionsPath`, or under `results`) mapped through `optionLabel` and
|
|
229
|
+
* `optionValue` (dotted paths; default `label`/`title`/`name` and `value`/`id`).
|
|
230
|
+
*
|
|
231
|
+
* @return {Promise<void>}
|
|
232
|
+
*/
|
|
233
|
+
async loadOptions() {
|
|
234
|
+
const url = this.kind === 'select' && !Array.isArray(this.field.options) ? this.field.optionsUrl : '';
|
|
235
|
+
if (!url) {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
this.optionsLoading = true;
|
|
239
|
+
try {
|
|
240
|
+
const response = await fetch(prefixUrl(url), { headers: buildHeaders() });
|
|
241
|
+
if (!response.ok) {
|
|
242
|
+
this.fetchedOptions = [];
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
const data = await response.json();
|
|
246
|
+
const list = this.field.optionsPath ? readPath(data, this.field.optionsPath) : (Array.isArray(data) ? data : data?.results);
|
|
247
|
+
this.fetchedOptions = (Array.isArray(list) ? list : []).map((item) => {
|
|
248
|
+
if (!item || typeof item !== 'object') {
|
|
249
|
+
return { label: String(item), value: item }
|
|
250
|
+
}
|
|
251
|
+
const value = this.field.optionValue ? readPath(item, this.field.optionValue) : (item.value ?? item.id);
|
|
252
|
+
const label = this.field.optionLabel ? readPath(item, this.field.optionLabel) : (item.label ?? item.title ?? item.name ?? value);
|
|
253
|
+
return { label: String(label ?? ''), value }
|
|
254
|
+
});
|
|
255
|
+
} catch {
|
|
256
|
+
this.fetchedOptions = [];
|
|
257
|
+
} finally {
|
|
258
|
+
this.optionsLoading = false;
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export { script as default };
|
|
265
|
+
//# sourceMappingURL=CnSettingsField.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnSettingsField.vue2.js","sources":["../../../../src/components/CnSettingsField/CnSettingsField.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-settings-field\" :data-testid=\"`cn-settings-field-${field.key}`\">\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-if=\"kind === 'switch' || kind === 'boolean'\"\n\t\t\t:type=\"kind === 'switch' ? 'switch' : 'checkbox'\"\n\t\t\t:modelValue=\"!!modelValue\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\">\n\t\t\t{{ label }}\n\t\t</NcCheckboxRadioSwitch>\n\t\t<div v-else-if=\"kind === 'image'\"\n\t\t\tclass=\"cn-settings-field__image\"\n\t\t\trole=\"group\"\n\t\t\t:aria-labelledby=\"`${inputId}-label`\">\n\t\t\t<span :id=\"`${inputId}-label`\" class=\"cn-settings-field__image-label\">{{ label }}</span>\n\t\t\t<div class=\"cn-settings-field__image-row\">\n\t\t\t\t<span class=\"cn-settings-field__image-tile\" :data-testid=\"`cn-settings-field-image-${field.key}`\">\n\t\t\t\t\t<img v-if=\"stringValue\" :src=\"stringValue\" :alt=\"t('nextcloud-vue', 'Current {name}', { name: label })\">\n\t\t\t\t\t<span v-else class=\"cn-settings-field__image-initials\" aria-hidden=\"true\">{{ field.initials || '' }}</span>\n\t\t\t\t</span>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tref=\"file\"\n\t\t\t\t\tclass=\"hidden-visually\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t:accept=\"field.accept || 'image/*'\"\n\t\t\t\t\ttabindex=\"-1\"\n\t\t\t\t\t:aria-labelledby=\"`${inputId}-label`\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t@change=\"upload($event.target.files && $event.target.files[0])\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"!field.readOnly && field.uploadUrl\"\n\t\t\t\t\t:disabled=\"uploading\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t:data-testid=\"`cn-settings-field-upload-${field.key}`\"\n\t\t\t\t\t@click=\"$refs.file && $refs.file.click()\">\n\t\t\t\t\t<template v-if=\"uploading\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ field.uploadLabel || t('nextcloud-vue', 'Upload {name}', { name: label }) }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<NcSelect\n\t\t\tv-else-if=\"kind === 'select'\"\n\t\t\t:inputId=\"inputId\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"normalizedOptions\"\n\t\t\t:inputLabel=\"label\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:loading=\"optionsLoading\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:clearable=\"!field.required\"\n\t\t\tlabel=\"label\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue(optionValue($event))\" />\n\t\t<NcTextArea\n\t\t\tv-else-if=\"kind === 'textarea'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:rows=\"field.rows || 4\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'secret'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"password\"\n\t\t\tautocomplete=\"new-password\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.secretSet ? secretSetPlaceholder : (field.placeholder || '')\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'number'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"number\"\n\t\t\t:min=\"field.min\"\n\t\t\t:max=\"field.max\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event === '' ? null : Number($event))\" />\n\t\t<NcTextField\n\t\t\tv-else\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:type=\"kind === 'password' ? 'password' : 'text'\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<p v-if=\"shownError\"\n\t\t\t:id=\"`${inputId}-error`\"\n\t\t\tclass=\"cn-settings-field__error\"\n\t\t\t:data-testid=\"`cn-settings-field-error-${field.key}`\">\n\t\t\t{{ shownError }}\n\t\t</p>\n\t\t<p v-else-if=\"hint\" :id=\"`${inputId}-hint`\" class=\"cn-settings-field__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport { buildHeaders, prefixUrl } from '../../utils/headers.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\nlet fieldUid = 0\n\n/** Field types and the names CnSettingsPage's manifest uses for them. */\nconst KIND_ALIASES = { enum: 'select', string: 'text' }\n\n/**\n * CnSettingsField - one settings field: the control for its type with its\n * label, and under it an error or a hint. Shared by CnSettingsPage and\n * CnSettingsFieldsSection.\n *\n * Types: `text` (default), `textarea`, `number`, `switch`, `boolean` (a checkbox),\n * `select` (`enum`) with static `options` or options read from `optionsUrl`,\n * `password` (a masked input that shows its value back) and `secret`\n * (replace-only: the input stays empty, and with `secretSet` says a value is\n * stored; the host sends it only when something is typed), and `image` (a\n * preview tile, the initials without an image, and an upload button that\n * posts the file to `uploadUrl` at once and emits `uploaded`).\n *\n * ```vue\n * <CnSettingsField\n * :field=\"{ key: 'apiKey', label: 'API key', type: 'secret', secretSet: true }\"\n * v-model=\"form.apiKey\" />\n * ```\n */\nexport default {\n\tname: 'CnSettingsField',\n\n\tcomponents: { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField },\n\n\tprops: {\n\t\t/**\n\t\t * The field: `{ key, label, type?, options?, optionsUrl?, optionsPath?,\n\t\t * optionLabel?, optionValue?, placeholder?, rows?, min?, max?, required?,\n\t\t * readOnly?, secretSet? }`. `label` arrives translated.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tfield: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * The value: text, a number, a boolean or a select value. Any type,\n\t\t * because a Boolean in a type list would read an empty string as true.\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: null,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** A validation message, drawn under the control and tied to it. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A hint under the control (not drawn while there is an error). */\n\t\thint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['update:modelValue', 'uploaded'],\n\n\tdata() {\n\t\tfieldUid += 1\n\t\treturn {\n\t\t\tuid: fieldUid,\n\t\t\tfetchedOptions: null,\n\t\t\toptionsLoading: false,\n\t\t\tuploading: false,\n\t\t\tuploadError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The control kind. */\n\t\tkind() {\n\t\t\tconst type = String(this.field.type || 'text')\n\t\t\treturn KIND_ALIASES[type] || type\n\t\t},\n\n\t\t/** @return {string} The label. */\n\t\tlabel() {\n\t\t\treturn String(this.field.label || this.field.key || '')\n\t\t},\n\n\t\t/** @return {string} The control's id. */\n\t\tinputId() {\n\t\t\treturn `cn-settings-field-${this.uid}-${String(this.field.key).replace(/[^A-Za-z0-9_-]/g, '-')}`\n\t\t},\n\n\t\t/** @return {string} The message shown under the control: an upload failure, else `error`. */\n\t\tshownError() {\n\t\t\treturn this.uploadError || this.error\n\t\t},\n\n\t\t/** @return {string|null} The id of the error or hint the control is described by. */\n\t\tdescribedBy() {\n\t\t\tif (this.shownError) {\n\t\t\t\treturn `${this.inputId}-error`\n\t\t\t}\n\t\t\treturn this.hint ? `${this.inputId}-hint` : null\n\t\t},\n\n\t\t/** @return {string} The value as text for a text control. */\n\t\tstringValue() {\n\t\t\treturn this.modelValue === null || this.modelValue === undefined ? '' : String(this.modelValue)\n\t\t},\n\n\t\t/** @return {string} The placeholder of a secret that is stored. */\n\t\tsecretSetPlaceholder() {\n\t\t\treturn t('nextcloud-vue', 'Stored. Type a new value to replace it.')\n\t\t},\n\n\t\t/**\n\t\t * The select options as `{ label, value }`: the static `options` (strings,\n\t\t * numbers or objects), or those read from `optionsUrl`.\n\t\t *\n\t\t * @return {Array<{label: string, value: (string|number|boolean)}>}\n\t\t */\n\t\tnormalizedOptions() {\n\t\t\tconst raw = Array.isArray(this.field.options) ? this.field.options : (this.fetchedOptions || [])\n\t\t\treturn raw.map((option) => (option && typeof option === 'object'\n\t\t\t\t? { ...option, label: String(option.label ?? option.value ?? ''), value: option.value }\n\t\t\t\t: { label: String(option), value: option }))\n\t\t},\n\n\t\t/** @return {object|null} The option the value selects, for NcSelect. */\n\t\tselectedOption() {\n\t\t\tif (this.modelValue === null || this.modelValue === undefined || this.modelValue === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.normalizedOptions.find((option) => option.value === this.modelValue)\n\t\t\t\t|| { label: String(this.modelValue), value: this.modelValue }\n\t\t},\n\t},\n\n\twatch: {\n\t\t'field.optionsUrl': {\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\n\t\t\timmediate: true,\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Upload a chosen image to `uploadUrl` as multipart form data (the\n\t\t * file under `uploadField`, default `image`, plus `uploadParams`), then\n\t\t * take the new image url from the answer at `uploadValuePath` (or a\n\t\t * cache-busted `previewUrl`).\n\t\t *\n\t\t * @param {File|undefined} file The chosen file.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/settings-fields-section/specs/settings-fields-section/spec.md#requirement-an-image-field-uploads-at-once\n\t\t */\n\t\tasync upload(file) {\n\t\t\tif (!file || !this.field.uploadUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = new FormData()\n\t\t\tfor (const [name, value] of Object.entries(this.field.uploadParams || {})) {\n\t\t\t\tform.append(name, value)\n\t\t\t}\n\t\t\tform.append(this.field.uploadField || 'image', file)\n\t\t\tthis.uploading = true\n\t\t\tthis.uploadError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.field.uploadUrl), form)\n\t\t\t\tconst fromAnswer = this.field.uploadValuePath ? readPath(response?.data, this.field.uploadValuePath) : ''\n\t\t\t\tconst next = fromAnswer || (this.field.previewUrl ? `${prefixUrl(this.field.previewUrl)}${this.field.previewUrl.includes('?') ? '&' : '?'}v=${Date.now()}` : '')\n\t\t\t\t/**\n\t\t\t\t * @event uploaded An image was uploaded. Payload: its new url.\n\t\t\t\t */\n\t\t\t\tthis.$emit('uploaded', next)\n\t\t\t} catch (error) {\n\t\t\t\tthis.uploadError = t('nextcloud-vue', 'The image could not be uploaded: {reason}', { reason: serverErrorMessage(error) })\n\t\t\t} finally {\n\t\t\t\tthis.uploading = false\n\t\t\t\tif (this.$refs.file) {\n\t\t\t\t\tthis.$refs.file.value = ''\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Report a new value.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @return {void}\n\t\t */\n\t\temitValue(value) {\n\t\t\t/**\n\t\t\t * @event update:modelValue The value changed. Payload: the new value.\n\t\t\t */\n\t\t\tthis.$emit('update:modelValue', value)\n\t\t},\n\n\t\t/**\n\t\t * The storable value of what NcSelect emits.\n\t\t *\n\t\t * @param {object|string|number|null} emitted An option, or null on clear.\n\t\t * @return {string|number|boolean|null}\n\t\t */\n\t\toptionValue(emitted) {\n\t\t\tif (emitted === null || emitted === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn typeof emitted === 'object' && 'value' in emitted ? emitted.value : emitted\n\t\t},\n\n\t\t/**\n\t\t * Read a sourced select's options: a list (or the list at\n\t\t * `optionsPath`, or under `results`) mapped through `optionLabel` and\n\t\t * `optionValue` (dotted paths; default `label`/`title`/`name` and `value`/`id`).\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tconst url = this.kind === 'select' && !Array.isArray(this.field.options) ? this.field.optionsUrl : ''\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.optionsLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthis.fetchedOptions = []\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = this.field.optionsPath ? readPath(data, this.field.optionsPath) : (Array.isArray(data) ? data : data?.results)\n\t\t\t\tthis.fetchedOptions = (Array.isArray(list) ? list : []).map((item) => {\n\t\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\t\treturn { label: String(item), value: item }\n\t\t\t\t\t}\n\t\t\t\t\tconst value = this.field.optionValue ? readPath(item, this.field.optionValue) : (item.value ?? item.id)\n\t\t\t\t\tconst label = this.field.optionLabel ? readPath(item, this.field.optionLabel) : (item.label ?? item.title ?? item.name ?? value)\n\t\t\t\t\treturn { label: String(label ?? ''), value }\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.optionsLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-settings-field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-settings-field__hint,\n.cn-settings-field__error {\n\tmargin: 0;\n\tfont-size: 13px;\n\tline-height: 1.4;\n}\n\n.cn-settings-field__image {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-settings-field__image-label {\n\tfont-weight: 600;\n}\n\n.cn-settings-field__image-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px;\n}\n\n.cn-settings-field__image-tile {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 64px;\n\theight: 64px;\n\toverflow: hidden;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-settings-field__image-tile img {\n\tmax-width: 100%;\n\tmax-height: 100%;\n\tobject-fit: contain;\n}\n\n.cn-settings-field__image-initials {\n\tfont-size: 20px;\n\tfont-weight: 700;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n}\n\n.cn-settings-field__hint {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-field__error {\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["t","axios"],"mappings":";;;;;;;AAgIA,IAAI,QAAO,GAAI,EAAA;;AAEf;AACA,MAAM,YAAW,GAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAO,GAAA;;AAEtD;;;;AAIC;AACA;AACA;;AAEA;;;;AAIA;AACA;AACA;AACA;;AAEA;;AAED,aAAe;CACd,IAAI,EAAE,iBAAiB;;AAEvB,CAAA,UAAU,EAAE,EAAE,QAAQ,EAAE,qBAAqB,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa;;AAEjG,CAAA,KAAK,EAAE;AACN;;AAEC;;AAEA;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,QAAQ,EAAE,IAAI;GACd;;AAED;;;;EAIA,UAAU,EAAE;AACX,GAAA,IAAI,EAAE,IAAI;GACV,OAAO,EAAE,IAAI;GACb;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;EAGD,IAAI,EAAE;GACL,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;EACD;;AAED,CAAA,KAAK,EAAE,CAAC,mBAAmB,EAAE,UAAU,CAAC;;AAExC,CAAA,IAAI,GAAG;EACN,QAAO,IAAK,EAAA;AACZ,EAAA,OAAO;GACN,GAAG,EAAE,QAAQ;AACb,GAAA,cAAc,EAAE,IAAI;AACpB,GAAA,cAAc,EAAE,KAAK;AACrB,GAAA,SAAS,EAAE,KAAK;AAChB,GAAA,WAAW,EAAE,EAAE;AAChB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,IAAI,GAAG;AACN,GAAA,MAAM,IAAG,GAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAG,IAAK,MAAM,EAAA;GAC7C,OAAO,YAAY,CAAC,IAAI,CAAA,IAAK,IAAG;GAChC;;;AAGD,EAAA,KAAK,GAAG;GACP,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAM,IAAG,IAAI,CAAC,KAAK,CAAC,GAAI,IAAG,EAAE,CAAA;GACtD;;AAED;AACA,EAAA,OAAO,GAAG;AACT,GAAA,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAA;GAC/F;;AAED;EACA,UAAU,GAAG;AACZ,GAAA,OAAO,IAAI,CAAC,WAAU,IAAK,IAAI,CAAC,KAAI;GACpC;;AAED;EACA,WAAW,GAAG;AACb,GAAA,IAAI,IAAI,CAAC,UAAU,EAAE;IACpB,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;AAC9B,IAAA;AACA,GAAA,OAAO,IAAI,CAAC,IAAG,GAAI,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,IAAG;GAC/C;;;EAGD,WAAW,GAAG;AACb,GAAA,OAAO,IAAI,CAAC,UAAW,KAAI,QAAQ,IAAI,CAAC,UAAW,KAAI,YAAY,KAAK,MAAM,CAAC,IAAI,CAAC,UAAU,CAAA;GAC9F;;;EAGD,oBAAoB,GAAG;GACtB,OAAOA,SAAC,CAAC,eAAe,EAAE,yCAAyC,CAAA;GACnE;;AAED;;;AAGC;;;AAGD,EAAA,iBAAiB,GAAG;AACnB,GAAA,MAAM,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAE,GAAE,IAAI,CAAC,KAAK,CAAC,OAAQ,IAAG,IAAI,CAAC,kBAAkB,EAAE,EAAA;GAC/F,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,MAAM,MAAO,IAAG,OAAO,MAAO,KAAI,QAAO;AAC9D,MAAE,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAI,IAAK,MAAM,CAAC,KAAI,IAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAM,EAAA;AACtF,MAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAK,EAAG,CAAC,CAAA;GAC5C;;;AAGD,EAAA,cAAc,GAAG;AAChB,GAAA,IAAI,IAAI,CAAC,UAAS,KAAM,IAAG,IAAK,IAAI,CAAC,UAAW,KAAI,SAAU,IAAG,IAAI,CAAC,eAAe,EAAE,EAAE;AACxF,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,KAAI,KAAM,IAAI,CAAC,UAAU,CAAA;OAC3E,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,UAAW,EAAA;GAC7D;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,kBAAkB,EAAE;AACnB,GAAA,OAAO,GAAG;AACT,IAAA,IAAI,CAAC,WAAW,GAAC;IACjB;;AAED,GAAA,SAAS,EAAE,IAAI;GACf;EACD;;AAED,CAAA,OAAO,EAAE;KACRA,SAAC;;AAED;;AAEC;;;AAGA;AACA;;AAEA;;AAED,EAAA,MAAM,MAAM,CAAC,IAAI,EAAE;AAClB,GAAA,IAAI,CAAC,IAAK,IAAG,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;IACnC,MAAK;AACN,IAAA;GACA,MAAM,OAAO,IAAI,QAAQ,GAAC;AAC1B,GAAA,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAE,IAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,YAAW,IAAK,EAAE,CAAC,EAAE;IAC1E,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAA;AACxB,IAAA;GACA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,OAAO,EAAE,IAAI,EAAA;AACnD,GAAA,IAAI,CAAC,SAAQ,GAAI,KAAG;AACpB,GAAA,IAAI,CAAC,WAAU,GAAI,GAAC;AACpB,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAMC,cAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAA;IACvE,MAAM,aAAa,IAAI,CAAC,KAAK,CAAC,kBAAkB,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAE,GAAE,GAAC;AACxG,IAAA,MAAM,IAAK,GAAE,UAAW,KAAI,IAAI,CAAC,KAAK,CAAC,UAAW,GAAE,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAE,GAAE,GAAI,GAAE,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAE,GAAE,EAAE,EAAA;AAC/J;;;IAGA,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAA;IAC1B,CAAA,OAAO,KAAK,EAAE;IACf,IAAI,CAAC,WAAY,GAAED,SAAC,CAAC,eAAe,EAAE,2CAA2C,EAAE,EAAE,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAA,EAAG,EAAA;AACzH,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,SAAQ,GAAI,MAAI;AACrB,IAAA,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;KACpB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAM,GAAE,GAAC;AAC1B,KAAA;AACD,IAAA;GACA;;AAED;AACC;AACA;;;;AAID,EAAA,SAAS,CAAC,KAAK,EAAE;AAChB;;;AAGA,GAAA,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,EAAA;GACrC;;AAED;AACC;AACA;AACA;AACA;;AAED,EAAA,WAAW,CAAC,OAAO,EAAE;AACpB,GAAA,IAAI,OAAQ,KAAI,QAAQ,OAAM,KAAM,SAAS,EAAE;AAC9C,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,OAAO,OAAO,OAAQ,KAAI,QAAS,IAAG,OAAQ,IAAG,OAAQ,GAAE,OAAO,CAAC,KAAM,GAAE,OAAM;GACjF;;AAED;AACC;;AAEA;AACA;;;AAGD,EAAA,MAAM,WAAW,GAAG;AACnB,GAAA,MAAM,MAAM,IAAI,CAAC,IAAG,KAAM,QAAO,IAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,UAAS,GAAI,GAAC;AACpG,GAAA,IAAI,CAAC,GAAG,EAAE;IACT,MAAK;AACN,IAAA;GACA,IAAI,CAAC,cAAe,GAAE,KAAG;AACzB,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AACxE,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AACjB,KAAA,IAAI,CAAC,cAAa,GAAI,GAAC;KACvB,MAAK;AACN,KAAA;IACA,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;IACjC,MAAM,IAAG,GAAI,IAAI,CAAC,KAAK,CAAC,WAAU,GAAI,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,OAAO,CAAC,IAAI,IAAI,IAAK,GAAE,IAAI,EAAE,OAAO,EAAA;AAC1H,IAAA,IAAI,CAAC,cAAa,GAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAE,GAAE,IAAG,GAAI,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK;AACrE,KAAA,IAAI,CAAC,IAAK,IAAG,OAAO,IAAG,KAAM,QAAQ,EAAE;AACtC,MAAA,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAK,EAAA;AAC3C,MAAA;AACA,KAAA,MAAM,KAAI,GAAI,IAAI,CAAC,KAAK,CAAC,WAAY,GAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAE,IAAG,IAAI,CAAC,KAAM,IAAG,IAAI,CAAC,EAAE,EAAA;KACtG,MAAM,KAAM,GAAE,IAAI,CAAC,KAAK,CAAC,WAAY,GAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,KAAI,IAAK,IAAI,CAAC,KAAI,IAAK,IAAI,CAAC,IAAG,IAAK,KAAK,EAAA;AAC/H,KAAA,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,KAAM,EAAA;KAC3C,EAAA;AACF,IAAA,CAAE,MAAM;AACP,IAAA,IAAI,CAAC,cAAa,GAAI,GAAC;AACxB,IAAA,SAAU;IACT,IAAI,CAAC,iBAAiB,MAAI;AAC3B,IAAA;GACA;EACD;AACF;;;;"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { resolveComponent, openBlock, createElementBlock, createBlock, withCtx, createTextVNode, toDisplayString, createElementVNode, createSlots, createVNode, createCommentVNode } from 'vue';
|
|
2
|
+
|
|
3
|
+
const _hoisted_1 = ["data-testid"];
|
|
4
|
+
const _hoisted_2 = ["aria-labelledby"];
|
|
5
|
+
const _hoisted_3 = ["id"];
|
|
6
|
+
const _hoisted_4 = { class: "cn-settings-field__image-row" };
|
|
7
|
+
const _hoisted_5 = ["data-testid"];
|
|
8
|
+
const _hoisted_6 = ["src", "alt"];
|
|
9
|
+
const _hoisted_7 = {
|
|
10
|
+
key: 1,
|
|
11
|
+
class: "cn-settings-field__image-initials",
|
|
12
|
+
"aria-hidden": "true"
|
|
13
|
+
};
|
|
14
|
+
const _hoisted_8 = ["id", "accept", "aria-labelledby", "aria-describedby"];
|
|
15
|
+
const _hoisted_9 = ["id", "data-testid"];
|
|
16
|
+
const _hoisted_10 = ["id"];
|
|
17
|
+
|
|
18
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
19
|
+
const _component_NcCheckboxRadioSwitch = resolveComponent("NcCheckboxRadioSwitch");
|
|
20
|
+
const _component_NcLoadingIcon = resolveComponent("NcLoadingIcon");
|
|
21
|
+
const _component_NcButton = resolveComponent("NcButton");
|
|
22
|
+
const _component_NcSelect = resolveComponent("NcSelect");
|
|
23
|
+
const _component_NcTextArea = resolveComponent("NcTextArea");
|
|
24
|
+
const _component_NcTextField = resolveComponent("NcTextField");
|
|
25
|
+
|
|
26
|
+
return (openBlock(), createElementBlock("div", {
|
|
27
|
+
class: "cn-settings-field",
|
|
28
|
+
"data-testid": `cn-settings-field-${$props.field.key}`
|
|
29
|
+
}, [
|
|
30
|
+
($options.kind === 'switch' || $options.kind === 'boolean')
|
|
31
|
+
? (openBlock(), createBlock(_component_NcCheckboxRadioSwitch, {
|
|
32
|
+
key: 0,
|
|
33
|
+
type: $options.kind === 'switch' ? 'switch' : 'checkbox',
|
|
34
|
+
modelValue: !!$props.modelValue,
|
|
35
|
+
disabled: $props.field.readOnly,
|
|
36
|
+
"aria-describedby": $options.describedBy,
|
|
37
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = $event => ($options.emitValue($event)))
|
|
38
|
+
}, {
|
|
39
|
+
default: withCtx(() => [
|
|
40
|
+
createTextVNode(toDisplayString($options.label), 1 /* TEXT */)
|
|
41
|
+
]),
|
|
42
|
+
_: 1 /* STABLE */
|
|
43
|
+
}, 8 /* PROPS */, ["type", "modelValue", "disabled", "aria-describedby"]))
|
|
44
|
+
: ($options.kind === 'image')
|
|
45
|
+
? (openBlock(), createElementBlock("div", {
|
|
46
|
+
key: 1,
|
|
47
|
+
class: "cn-settings-field__image",
|
|
48
|
+
role: "group",
|
|
49
|
+
"aria-labelledby": `${$options.inputId}-label`
|
|
50
|
+
}, [
|
|
51
|
+
createElementVNode("span", {
|
|
52
|
+
id: `${$options.inputId}-label`,
|
|
53
|
+
class: "cn-settings-field__image-label"
|
|
54
|
+
}, toDisplayString($options.label), 9 /* TEXT, PROPS */, _hoisted_3),
|
|
55
|
+
createElementVNode("div", _hoisted_4, [
|
|
56
|
+
createElementVNode("span", {
|
|
57
|
+
class: "cn-settings-field__image-tile",
|
|
58
|
+
"data-testid": `cn-settings-field-image-${$props.field.key}`
|
|
59
|
+
}, [
|
|
60
|
+
($options.stringValue)
|
|
61
|
+
? (openBlock(), createElementBlock("img", {
|
|
62
|
+
key: 0,
|
|
63
|
+
src: $options.stringValue,
|
|
64
|
+
alt: $options.t('nextcloud-vue', 'Current {name}', { name: $options.label })
|
|
65
|
+
}, null, 8 /* PROPS */, _hoisted_6))
|
|
66
|
+
: (openBlock(), createElementBlock("span", _hoisted_7, toDisplayString($props.field.initials || ''), 1 /* TEXT */))
|
|
67
|
+
], 8 /* PROPS */, _hoisted_5),
|
|
68
|
+
createElementVNode("input", {
|
|
69
|
+
id: $options.inputId,
|
|
70
|
+
ref: "file",
|
|
71
|
+
class: "hidden-visually",
|
|
72
|
+
type: "file",
|
|
73
|
+
accept: $props.field.accept || 'image/*',
|
|
74
|
+
tabindex: "-1",
|
|
75
|
+
"aria-labelledby": `${$options.inputId}-label`,
|
|
76
|
+
"aria-describedby": $options.describedBy,
|
|
77
|
+
onChange: _cache[1] || (_cache[1] = $event => ($options.upload($event.target.files && $event.target.files[0])))
|
|
78
|
+
}, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_8),
|
|
79
|
+
(!$props.field.readOnly && $props.field.uploadUrl)
|
|
80
|
+
? (openBlock(), createBlock(_component_NcButton, {
|
|
81
|
+
key: 0,
|
|
82
|
+
disabled: $data.uploading,
|
|
83
|
+
"aria-describedby": $options.describedBy,
|
|
84
|
+
"data-testid": `cn-settings-field-upload-${$props.field.key}`,
|
|
85
|
+
onClick: _cache[2] || (_cache[2] = $event => (_ctx.$refs.file && _ctx.$refs.file.click()))
|
|
86
|
+
}, createSlots({
|
|
87
|
+
default: withCtx(() => [
|
|
88
|
+
createTextVNode(" " + toDisplayString($props.field.uploadLabel || $options.t('nextcloud-vue', 'Upload {name}', { name: $options.label })), 1 /* TEXT */)
|
|
89
|
+
]),
|
|
90
|
+
_: 2 /* DYNAMIC */
|
|
91
|
+
}, [
|
|
92
|
+
($data.uploading)
|
|
93
|
+
? {
|
|
94
|
+
name: "icon",
|
|
95
|
+
fn: withCtx(() => [
|
|
96
|
+
createVNode(_component_NcLoadingIcon, { size: 20 })
|
|
97
|
+
]),
|
|
98
|
+
key: "0"
|
|
99
|
+
}
|
|
100
|
+
: undefined
|
|
101
|
+
]), 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "aria-describedby", "data-testid"]))
|
|
102
|
+
: createCommentVNode("v-if", true)
|
|
103
|
+
])
|
|
104
|
+
], 8 /* PROPS */, _hoisted_2))
|
|
105
|
+
: ($options.kind === 'select')
|
|
106
|
+
? (openBlock(), createBlock(_component_NcSelect, {
|
|
107
|
+
key: 2,
|
|
108
|
+
inputId: $options.inputId,
|
|
109
|
+
modelValue: $options.selectedOption,
|
|
110
|
+
options: $options.normalizedOptions,
|
|
111
|
+
inputLabel: $options.label,
|
|
112
|
+
placeholder: $props.field.placeholder || '',
|
|
113
|
+
loading: $data.optionsLoading,
|
|
114
|
+
disabled: $props.field.readOnly,
|
|
115
|
+
clearable: !$props.field.required,
|
|
116
|
+
label: "label",
|
|
117
|
+
"aria-describedby": $options.describedBy,
|
|
118
|
+
"onUpdate:modelValue": _cache[3] || (_cache[3] = $event => ($options.emitValue($options.optionValue($event))))
|
|
119
|
+
}, null, 8 /* PROPS */, ["inputId", "modelValue", "options", "inputLabel", "placeholder", "loading", "disabled", "clearable", "aria-describedby"]))
|
|
120
|
+
: ($options.kind === 'textarea')
|
|
121
|
+
? (openBlock(), createBlock(_component_NcTextArea, {
|
|
122
|
+
key: 3,
|
|
123
|
+
id: $options.inputId,
|
|
124
|
+
label: $options.label,
|
|
125
|
+
modelValue: $options.stringValue,
|
|
126
|
+
rows: $props.field.rows || 4,
|
|
127
|
+
placeholder: $props.field.placeholder || '',
|
|
128
|
+
readonly: $props.field.readOnly,
|
|
129
|
+
error: !!$props.error,
|
|
130
|
+
"aria-describedby": $options.describedBy,
|
|
131
|
+
"onUpdate:modelValue": _cache[4] || (_cache[4] = $event => ($options.emitValue($event)))
|
|
132
|
+
}, null, 8 /* PROPS */, ["id", "label", "modelValue", "rows", "placeholder", "readonly", "error", "aria-describedby"]))
|
|
133
|
+
: ($options.kind === 'secret')
|
|
134
|
+
? (openBlock(), createBlock(_component_NcTextField, {
|
|
135
|
+
key: 4,
|
|
136
|
+
id: $options.inputId,
|
|
137
|
+
label: $options.label,
|
|
138
|
+
type: "password",
|
|
139
|
+
autocomplete: "new-password",
|
|
140
|
+
modelValue: $options.stringValue,
|
|
141
|
+
placeholder: $props.field.secretSet ? $options.secretSetPlaceholder : ($props.field.placeholder || ''),
|
|
142
|
+
readonly: $props.field.readOnly,
|
|
143
|
+
error: !!$props.error,
|
|
144
|
+
"aria-describedby": $options.describedBy,
|
|
145
|
+
"onUpdate:modelValue": _cache[5] || (_cache[5] = $event => ($options.emitValue($event)))
|
|
146
|
+
}, null, 8 /* PROPS */, ["id", "label", "modelValue", "placeholder", "readonly", "error", "aria-describedby"]))
|
|
147
|
+
: ($options.kind === 'number')
|
|
148
|
+
? (openBlock(), createBlock(_component_NcTextField, {
|
|
149
|
+
key: 5,
|
|
150
|
+
id: $options.inputId,
|
|
151
|
+
label: $options.label,
|
|
152
|
+
type: "number",
|
|
153
|
+
min: $props.field.min,
|
|
154
|
+
max: $props.field.max,
|
|
155
|
+
modelValue: $options.stringValue,
|
|
156
|
+
readonly: $props.field.readOnly,
|
|
157
|
+
error: !!$props.error,
|
|
158
|
+
"aria-describedby": $options.describedBy,
|
|
159
|
+
"onUpdate:modelValue": _cache[6] || (_cache[6] = $event => ($options.emitValue($event === '' ? null : Number($event))))
|
|
160
|
+
}, null, 8 /* PROPS */, ["id", "label", "min", "max", "modelValue", "readonly", "error", "aria-describedby"]))
|
|
161
|
+
: (openBlock(), createBlock(_component_NcTextField, {
|
|
162
|
+
key: 6,
|
|
163
|
+
id: $options.inputId,
|
|
164
|
+
label: $options.label,
|
|
165
|
+
type: $options.kind === 'password' ? 'password' : 'text',
|
|
166
|
+
modelValue: $options.stringValue,
|
|
167
|
+
placeholder: $props.field.placeholder || '',
|
|
168
|
+
readonly: $props.field.readOnly,
|
|
169
|
+
error: !!$props.error,
|
|
170
|
+
"aria-describedby": $options.describedBy,
|
|
171
|
+
"onUpdate:modelValue": _cache[7] || (_cache[7] = $event => ($options.emitValue($event)))
|
|
172
|
+
}, null, 8 /* PROPS */, ["id", "label", "type", "modelValue", "placeholder", "readonly", "error", "aria-describedby"])),
|
|
173
|
+
($options.shownError)
|
|
174
|
+
? (openBlock(), createElementBlock("p", {
|
|
175
|
+
key: 7,
|
|
176
|
+
id: `${$options.inputId}-error`,
|
|
177
|
+
class: "cn-settings-field__error",
|
|
178
|
+
"data-testid": `cn-settings-field-error-${$props.field.key}`
|
|
179
|
+
}, toDisplayString($options.shownError), 9 /* TEXT, PROPS */, _hoisted_9))
|
|
180
|
+
: ($props.hint)
|
|
181
|
+
? (openBlock(), createElementBlock("p", {
|
|
182
|
+
key: 8,
|
|
183
|
+
id: `${$options.inputId}-hint`,
|
|
184
|
+
class: "cn-settings-field__hint"
|
|
185
|
+
}, toDisplayString($props.hint), 9 /* TEXT, PROPS */, _hoisted_10))
|
|
186
|
+
: createCommentVNode("v-if", true)
|
|
187
|
+
], 8 /* PROPS */, _hoisted_1))
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export { render };
|
|
191
|
+
//# sourceMappingURL=CnSettingsField.vue3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnSettingsField.vue3.js","sources":["../../../../src/components/CnSettingsField/CnSettingsField.vue?vue&type=template&id=d2218996&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-settings-field\" :data-testid=\"`cn-settings-field-${field.key}`\">\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-if=\"kind === 'switch' || kind === 'boolean'\"\n\t\t\t:type=\"kind === 'switch' ? 'switch' : 'checkbox'\"\n\t\t\t:modelValue=\"!!modelValue\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\">\n\t\t\t{{ label }}\n\t\t</NcCheckboxRadioSwitch>\n\t\t<div v-else-if=\"kind === 'image'\"\n\t\t\tclass=\"cn-settings-field__image\"\n\t\t\trole=\"group\"\n\t\t\t:aria-labelledby=\"`${inputId}-label`\">\n\t\t\t<span :id=\"`${inputId}-label`\" class=\"cn-settings-field__image-label\">{{ label }}</span>\n\t\t\t<div class=\"cn-settings-field__image-row\">\n\t\t\t\t<span class=\"cn-settings-field__image-tile\" :data-testid=\"`cn-settings-field-image-${field.key}`\">\n\t\t\t\t\t<img v-if=\"stringValue\" :src=\"stringValue\" :alt=\"t('nextcloud-vue', 'Current {name}', { name: label })\">\n\t\t\t\t\t<span v-else class=\"cn-settings-field__image-initials\" aria-hidden=\"true\">{{ field.initials || '' }}</span>\n\t\t\t\t</span>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tref=\"file\"\n\t\t\t\t\tclass=\"hidden-visually\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t:accept=\"field.accept || 'image/*'\"\n\t\t\t\t\ttabindex=\"-1\"\n\t\t\t\t\t:aria-labelledby=\"`${inputId}-label`\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t@change=\"upload($event.target.files && $event.target.files[0])\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"!field.readOnly && field.uploadUrl\"\n\t\t\t\t\t:disabled=\"uploading\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t:data-testid=\"`cn-settings-field-upload-${field.key}`\"\n\t\t\t\t\t@click=\"$refs.file && $refs.file.click()\">\n\t\t\t\t\t<template v-if=\"uploading\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ field.uploadLabel || t('nextcloud-vue', 'Upload {name}', { name: label }) }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<NcSelect\n\t\t\tv-else-if=\"kind === 'select'\"\n\t\t\t:inputId=\"inputId\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"normalizedOptions\"\n\t\t\t:inputLabel=\"label\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:loading=\"optionsLoading\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:clearable=\"!field.required\"\n\t\t\tlabel=\"label\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue(optionValue($event))\" />\n\t\t<NcTextArea\n\t\t\tv-else-if=\"kind === 'textarea'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:rows=\"field.rows || 4\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'secret'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"password\"\n\t\t\tautocomplete=\"new-password\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.secretSet ? secretSetPlaceholder : (field.placeholder || '')\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'number'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"number\"\n\t\t\t:min=\"field.min\"\n\t\t\t:max=\"field.max\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event === '' ? null : Number($event))\" />\n\t\t<NcTextField\n\t\t\tv-else\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:type=\"kind === 'password' ? 'password' : 'text'\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<p v-if=\"shownError\"\n\t\t\t:id=\"`${inputId}-error`\"\n\t\t\tclass=\"cn-settings-field__error\"\n\t\t\t:data-testid=\"`cn-settings-field-error-${field.key}`\">\n\t\t\t{{ shownError }}\n\t\t</p>\n\t\t<p v-else-if=\"hint\" :id=\"`${inputId}-hint`\" class=\"cn-settings-field__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport { buildHeaders, prefixUrl } from '../../utils/headers.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\nlet fieldUid = 0\n\n/** Field types and the names CnSettingsPage's manifest uses for them. */\nconst KIND_ALIASES = { enum: 'select', string: 'text' }\n\n/**\n * CnSettingsField - one settings field: the control for its type with its\n * label, and under it an error or a hint. Shared by CnSettingsPage and\n * CnSettingsFieldsSection.\n *\n * Types: `text` (default), `textarea`, `number`, `switch`, `boolean` (a checkbox),\n * `select` (`enum`) with static `options` or options read from `optionsUrl`,\n * `password` (a masked input that shows its value back) and `secret`\n * (replace-only: the input stays empty, and with `secretSet` says a value is\n * stored; the host sends it only when something is typed), and `image` (a\n * preview tile, the initials without an image, and an upload button that\n * posts the file to `uploadUrl` at once and emits `uploaded`).\n *\n * ```vue\n * <CnSettingsField\n * :field=\"{ key: 'apiKey', label: 'API key', type: 'secret', secretSet: true }\"\n * v-model=\"form.apiKey\" />\n * ```\n */\nexport default {\n\tname: 'CnSettingsField',\n\n\tcomponents: { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField },\n\n\tprops: {\n\t\t/**\n\t\t * The field: `{ key, label, type?, options?, optionsUrl?, optionsPath?,\n\t\t * optionLabel?, optionValue?, placeholder?, rows?, min?, max?, required?,\n\t\t * readOnly?, secretSet? }`. `label` arrives translated.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tfield: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * The value: text, a number, a boolean or a select value. Any type,\n\t\t * because a Boolean in a type list would read an empty string as true.\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: null,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** A validation message, drawn under the control and tied to it. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A hint under the control (not drawn while there is an error). */\n\t\thint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['update:modelValue', 'uploaded'],\n\n\tdata() {\n\t\tfieldUid += 1\n\t\treturn {\n\t\t\tuid: fieldUid,\n\t\t\tfetchedOptions: null,\n\t\t\toptionsLoading: false,\n\t\t\tuploading: false,\n\t\t\tuploadError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The control kind. */\n\t\tkind() {\n\t\t\tconst type = String(this.field.type || 'text')\n\t\t\treturn KIND_ALIASES[type] || type\n\t\t},\n\n\t\t/** @return {string} The label. */\n\t\tlabel() {\n\t\t\treturn String(this.field.label || this.field.key || '')\n\t\t},\n\n\t\t/** @return {string} The control's id. */\n\t\tinputId() {\n\t\t\treturn `cn-settings-field-${this.uid}-${String(this.field.key).replace(/[^A-Za-z0-9_-]/g, '-')}`\n\t\t},\n\n\t\t/** @return {string} The message shown under the control: an upload failure, else `error`. */\n\t\tshownError() {\n\t\t\treturn this.uploadError || this.error\n\t\t},\n\n\t\t/** @return {string|null} The id of the error or hint the control is described by. */\n\t\tdescribedBy() {\n\t\t\tif (this.shownError) {\n\t\t\t\treturn `${this.inputId}-error`\n\t\t\t}\n\t\t\treturn this.hint ? `${this.inputId}-hint` : null\n\t\t},\n\n\t\t/** @return {string} The value as text for a text control. */\n\t\tstringValue() {\n\t\t\treturn this.modelValue === null || this.modelValue === undefined ? '' : String(this.modelValue)\n\t\t},\n\n\t\t/** @return {string} The placeholder of a secret that is stored. */\n\t\tsecretSetPlaceholder() {\n\t\t\treturn t('nextcloud-vue', 'Stored. Type a new value to replace it.')\n\t\t},\n\n\t\t/**\n\t\t * The select options as `{ label, value }`: the static `options` (strings,\n\t\t * numbers or objects), or those read from `optionsUrl`.\n\t\t *\n\t\t * @return {Array<{label: string, value: (string|number|boolean)}>}\n\t\t */\n\t\tnormalizedOptions() {\n\t\t\tconst raw = Array.isArray(this.field.options) ? this.field.options : (this.fetchedOptions || [])\n\t\t\treturn raw.map((option) => (option && typeof option === 'object'\n\t\t\t\t? { ...option, label: String(option.label ?? option.value ?? ''), value: option.value }\n\t\t\t\t: { label: String(option), value: option }))\n\t\t},\n\n\t\t/** @return {object|null} The option the value selects, for NcSelect. */\n\t\tselectedOption() {\n\t\t\tif (this.modelValue === null || this.modelValue === undefined || this.modelValue === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.normalizedOptions.find((option) => option.value === this.modelValue)\n\t\t\t\t|| { label: String(this.modelValue), value: this.modelValue }\n\t\t},\n\t},\n\n\twatch: {\n\t\t'field.optionsUrl': {\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\n\t\t\timmediate: true,\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Upload a chosen image to `uploadUrl` as multipart form data (the\n\t\t * file under `uploadField`, default `image`, plus `uploadParams`), then\n\t\t * take the new image url from the answer at `uploadValuePath` (or a\n\t\t * cache-busted `previewUrl`).\n\t\t *\n\t\t * @param {File|undefined} file The chosen file.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/settings-fields-section/specs/settings-fields-section/spec.md#requirement-an-image-field-uploads-at-once\n\t\t */\n\t\tasync upload(file) {\n\t\t\tif (!file || !this.field.uploadUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = new FormData()\n\t\t\tfor (const [name, value] of Object.entries(this.field.uploadParams || {})) {\n\t\t\t\tform.append(name, value)\n\t\t\t}\n\t\t\tform.append(this.field.uploadField || 'image', file)\n\t\t\tthis.uploading = true\n\t\t\tthis.uploadError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.field.uploadUrl), form)\n\t\t\t\tconst fromAnswer = this.field.uploadValuePath ? readPath(response?.data, this.field.uploadValuePath) : ''\n\t\t\t\tconst next = fromAnswer || (this.field.previewUrl ? `${prefixUrl(this.field.previewUrl)}${this.field.previewUrl.includes('?') ? '&' : '?'}v=${Date.now()}` : '')\n\t\t\t\t/**\n\t\t\t\t * @event uploaded An image was uploaded. Payload: its new url.\n\t\t\t\t */\n\t\t\t\tthis.$emit('uploaded', next)\n\t\t\t} catch (error) {\n\t\t\t\tthis.uploadError = t('nextcloud-vue', 'The image could not be uploaded: {reason}', { reason: serverErrorMessage(error) })\n\t\t\t} finally {\n\t\t\t\tthis.uploading = false\n\t\t\t\tif (this.$refs.file) {\n\t\t\t\t\tthis.$refs.file.value = ''\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Report a new value.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @return {void}\n\t\t */\n\t\temitValue(value) {\n\t\t\t/**\n\t\t\t * @event update:modelValue The value changed. Payload: the new value.\n\t\t\t */\n\t\t\tthis.$emit('update:modelValue', value)\n\t\t},\n\n\t\t/**\n\t\t * The storable value of what NcSelect emits.\n\t\t *\n\t\t * @param {object|string|number|null} emitted An option, or null on clear.\n\t\t * @return {string|number|boolean|null}\n\t\t */\n\t\toptionValue(emitted) {\n\t\t\tif (emitted === null || emitted === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn typeof emitted === 'object' && 'value' in emitted ? emitted.value : emitted\n\t\t},\n\n\t\t/**\n\t\t * Read a sourced select's options: a list (or the list at\n\t\t * `optionsPath`, or under `results`) mapped through `optionLabel` and\n\t\t * `optionValue` (dotted paths; default `label`/`title`/`name` and `value`/`id`).\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tconst url = this.kind === 'select' && !Array.isArray(this.field.options) ? this.field.optionsUrl : ''\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.optionsLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthis.fetchedOptions = []\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = this.field.optionsPath ? readPath(data, this.field.optionsPath) : (Array.isArray(data) ? data : data?.results)\n\t\t\t\tthis.fetchedOptions = (Array.isArray(list) ? list : []).map((item) => {\n\t\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\t\treturn { label: String(item), value: item }\n\t\t\t\t\t}\n\t\t\t\t\tconst value = this.field.optionValue ? readPath(item, this.field.optionValue) : (item.value ?? item.id)\n\t\t\t\t\tconst label = this.field.optionLabel ? readPath(item, this.field.optionLabel) : (item.label ?? item.title ?? item.name ?? value)\n\t\t\t\t\treturn { label: String(label ?? ''), value }\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.optionsLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-settings-field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-settings-field__hint,\n.cn-settings-field__error {\n\tmargin: 0;\n\tfont-size: 13px;\n\tline-height: 1.4;\n}\n\n.cn-settings-field__image {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-settings-field__image-label {\n\tfont-weight: 600;\n}\n\n.cn-settings-field__image-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px;\n}\n\n.cn-settings-field__image-tile {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 64px;\n\theight: 64px;\n\toverflow: hidden;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-settings-field__image-tile img {\n\tmax-width: 100%;\n\tmax-height: 100%;\n\tobject-fit: contain;\n}\n\n.cn-settings-field__image-initials {\n\tfont-size: 20px;\n\tfont-weight: 700;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n}\n\n.cn-settings-field__hint {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-field__error {\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_createElementVNode","_openBlock","_toDisplayString","_createTextVNode","_createVNode"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import script from './CnSettingsFieldsSection.vue2.js';
|
|
2
|
+
import { render } from './CnSettingsFieldsSection.vue3.js';
|
|
3
|
+
|
|
4
|
+
script.render = render;
|
|
5
|
+
script.__scopeId = "data-v-65c151a8";
|
|
6
|
+
const __sfc_main = script;
|
|
7
|
+
|
|
8
|
+
export { __sfc_main as default };
|
|
9
|
+
//# sourceMappingURL=CnSettingsFieldsSection.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnSettingsFieldsSection.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
|