@conduction/nextcloud-vue 2.82.0 → 2.83.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.
Files changed (78) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +2 -2
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
  4. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +24 -0
  5. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  6. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +9 -4
  7. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  8. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  9. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +9 -0
  10. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  11. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  12. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +96 -12
  13. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  14. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +95 -50
  15. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  16. package/dist/esm/components/CnMassActionBar/CnMassActionBar.vue2.js +2 -2
  17. package/dist/esm/components/CnMassActionBar/CnMassActionBar.vue2.js.map +1 -1
  18. package/dist/esm/components/CnMassImportDialog/CnMassImportDialog.vue2.js +2 -2
  19. package/dist/esm/components/CnMassImportDialog/CnMassImportDialog.vue2.js.map +1 -1
  20. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +1 -1
  21. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +16 -2
  22. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -1
  23. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +3 -3
  24. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js.map +1 -1
  25. package/dist/esm/components/CnReportsPage/CnReportsPage.vue.js +1 -1
  26. package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js +43 -0
  27. package/dist/esm/components/CnReportsPage/CnReportsPage.vue2.js.map +1 -1
  28. package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js +130 -53
  29. package/dist/esm/components/CnReportsPage/CnReportsPage.vue3.js.map +1 -1
  30. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +1 -1
  31. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +70 -5
  32. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -1
  33. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +61 -35
  34. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js.map +1 -1
  35. package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
  36. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +3 -1
  37. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  38. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  39. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue.js +1 -1
  40. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +55 -3
  41. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
  42. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +88 -71
  43. package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
  44. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +1 -1
  45. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +18 -4
  46. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -1
  47. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js.map +1 -1
  48. package/dist/esm/l10n/nl.json.js +3 -3
  49. package/dist/esm/library-style.js +1 -1
  50. package/dist/esm/nextcloud-vue.css +549 -338
  51. package/dist/esm/utils/fetchAggregate.js +25 -2
  52. package/dist/esm/utils/fetchAggregate.js.map +1 -1
  53. package/dist/esm/utils/switchValues.js +62 -0
  54. package/dist/esm/utils/switchValues.js.map +1 -0
  55. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  56. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  57. package/dist/nextcloud-vue.cjs.js +36086 -35536
  58. package/dist/nextcloud-vue.cjs.js.map +2 -2
  59. package/dist/nextcloud-vue.css +549 -338
  60. package/l10n/nl.json +3 -3
  61. package/package.json +1 -1
  62. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +31 -2
  63. package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -0
  64. package/src/components/CnIndexPage/CnIndexPage.vue +125 -15
  65. package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +54 -3
  66. package/src/components/CnReportsPage/CnReportsPage.vue +84 -4
  67. package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +110 -18
  68. package/src/components/CnStatWidget/CnStatWidget.vue +3 -1
  69. package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +92 -5
  70. package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +18 -4
  71. package/src/css/index-page.css +11 -0
  72. package/src/css/index.css +1 -0
  73. package/src/css/look-board-reports.css +117 -0
  74. package/src/css/look-board.css +32 -1
  75. package/src/schemas/app-manifest-v2.schema.json +2 -2
  76. package/src/utils/fetchAggregate.js +24 -1
  77. package/src/utils/switchValues.js +59 -0
  78. package/src/utils/validateManifestV2.compiled.js +3 -3
@@ -7,7 +7,9 @@ import { fillTemplate } from '../../utils/fillTemplate.js';
7
7
  import { prefixUrl } from '../../utils/headers.js';
8
8
  import { objectUrlOf, changedFields, writeFields } from '../../utils/objectWrite.js';
9
9
  import { readPath } from '../../utils/readPath.js';
10
+ import { resolveFilterTokens, hasUnresolvedTokens } from '../../utils/resolveFilterTokens.js';
10
11
  import { serverErrorMessage } from '../../utils/serverErrorMessage.js';
12
+ import { switchIsOn, switchStoredValue } from '../../utils/switchValues.js';
11
13
 
12
14
  const TYPES = ['text', 'textarea', 'select', 'switch', 'number', 'file', 'chips', 'reference'];
13
15
 
@@ -37,7 +39,7 @@ var script = {
37
39
  /**
38
40
  * The widget configuration.
39
41
  *
40
- * - `fields` (required) — `[{ key, label, type?: 'text'|'textarea'|'select'|'switch'|'number'|'file'|'chips'|'reference', register?, schema?, labelField?, valueTemplate?, filter?, limit?, emptyLabel?, default?, minItems?, required?, minItemsMessage?, lowercase?, addLabel?, confirmLabel?, removeLabel?, picker?: { title?, mimeTypes?, startAt?, valueTemplate? }, chooseLabel?, clearLabel?, hint?, placeholder?, options?: [{ value, label }], required?, pattern?, patternMessage?, min?, max?, rows?, wide?, readOnly? }]`; `key` is a field of the object, a top-level name or a dot-path.
42
+ * - `fields` (required) — `[{ key, label, type?: 'text'|'textarea'|'select'|'switch'|'number'|'file'|'chips'|'reference', register?, schema?, labelField?, valueTemplate?, filter?, limit?, emptyLabel?, free?, freeLabel?, freePlaceholder?, freePattern?, freePatternMessage?, default?, minItems?, required?, minItemsMessage?, values?: { on, off }, lowercase?, addLabel?, confirmLabel?, removeLabel?, picker?: { title?, mimeTypes?, startAt?, valueTemplate? }, chooseLabel?, clearLabel?, hint?, placeholder?, options?: [{ value, label }], required?, pattern?, patternMessage?, min?, max?, rows?, wide?, readOnly? }]`; `key` is a field of the object, a top-level name or a dot-path. A `reference` field's `filter` values may be `@objectId` and `@object.<field>` (the record being edited). A `switch` field's `values: { on, off }` reads and writes those values instead of true/false.
41
43
  * - `save` — `{ url, method?, payload? }`, write through an app endpoint (tokens `{value}`, `{field}`, `{changes}`, `{object.<path>}`).
42
44
  * - `columns` — 1 or 2 (default 2).
43
45
  * - `saveLabel`, `savedText`, `readOnly`.
@@ -86,6 +88,9 @@ var script = {
86
88
  // `reference` fields: the objects to choose from and the read's state (`loading`, `ready`, `error`), by field key.
87
89
  referenceOptions: {},
88
90
  referenceState: {},
91
+ // The query each `reference` field was last read with, by field key, so a
92
+ // new object re-reads only the fields whose filter changes with it.
93
+ referenceQuery: {},
89
94
  errors: {},
90
95
  saving: false,
91
96
  notice: '',
@@ -110,6 +115,9 @@ var script = {
110
115
  hint: this.tr(field.hint || ''),
111
116
  placeholder: this.tr(field.placeholder || ''),
112
117
  chooseLabel: this.tr(field.chooseLabel || 'Choose a file'),
118
+ free: field.type === 'reference' && field.free === true,
119
+ freeLabel: this.tr(field.freeLabel || 'Or type a value'),
120
+ freePlaceholder: this.tr(field.freePlaceholder || ''),
113
121
  clearLabel: this.tr(field.clearLabel || 'Remove'),
114
122
  rows: field.rows || 3,
115
123
  wide: field.wide === true || field.type === 'textarea',
@@ -143,6 +151,7 @@ var script = {
143
151
  watch: {
144
152
  objectData() {
145
153
  this.adopt();
154
+ this.loadReferences();
146
155
  },
147
156
  },
148
157
 
@@ -158,7 +167,14 @@ var script = {
158
167
  * parameters, at most `limit`, 100 by default). A failed read leaves the
159
168
  * field with its stored value only, and says so in the hint's place.
160
169
  *
170
+ * `filter` values may be `@objectId` and `@object.<field>`: the record
171
+ * the form edits, so a list can be narrowed to it (the logos of this
172
+ * portal). Until the record has that value the field is not read; it is
173
+ * read again when the record changes the resolved query, never twice
174
+ * for the same query.
175
+ *
161
176
  * @spec openspec/changes/screens-settings-form-reference/specs/settings-form/spec.md#requirement-a-settings-form-field-can-pick-an-object
177
+ * @spec openspec/changes/screens-settings-form-reference-object-filter/specs/settings-form/spec.md#requirement-a-reference-fields-filter-can-name-the-record-being-edited
162
178
  * @return {Promise<void>}
163
179
  */
164
180
  async loadReferences() {
@@ -166,13 +182,35 @@ var script = {
166
182
  if (fields.length === 0) {
167
183
  return
168
184
  }
185
+ const ctx = { objectId: this.objectId || (this.objectData && this.objectData.id) || undefined, object: this.objectData || undefined };
186
+ const pending = [];
187
+ for (const field of fields) {
188
+ const filter = resolveFilterTokens(field.filter && typeof field.filter === 'object' ? field.filter : {}, ctx);
189
+ if (hasUnresolvedTokens(filter)) {
190
+ // The record has no value for the token yet: nothing to read.
191
+ continue
192
+ }
193
+ const params = { ...filter, _limit: Number(field.limit) > 0 ? Number(field.limit) : 100 };
194
+ const query = JSON.stringify(params);
195
+ if (this.referenceQuery[field.key] === query) {
196
+ continue
197
+ }
198
+ this.referenceQuery = { ...this.referenceQuery, [field.key]: query };
199
+ pending.push({ field, params, query });
200
+ }
201
+ if (pending.length === 0) {
202
+ return
203
+ }
169
204
  const { default: axios } = await import('@nextcloud/axios');
170
- await Promise.all(fields.map(async (field) => {
205
+ await Promise.all(pending.map(async ({ field, params, query }) => {
171
206
  this.referenceState = { ...this.referenceState, [field.key]: 'loading' };
172
207
  try {
173
208
  const url = `/apps/openregister/api/objects/${encodeURIComponent(field.register)}/${encodeURIComponent(field.schema)}`;
174
- const params = { ...(field.filter && typeof field.filter === 'object' ? field.filter : {}), _limit: Number(field.limit) > 0 ? Number(field.limit) : 100 };
175
209
  const { data } = await axios.get(prefixUrl(url), { params });
210
+ if (this.referenceQuery[field.key] !== query) {
211
+ // A newer record asked for another list meanwhile.
212
+ return
213
+ }
176
214
  const rows = Array.isArray(data) ? data : (Array.isArray(data?.results) ? data.results : []);
177
215
  const options = [];
178
216
  for (const row of rows) {
@@ -214,6 +252,24 @@ var script = {
214
252
  return [...choices, ...options]
215
253
  },
216
254
 
255
+ /**
256
+ * The typed value of a `reference` field with `free`: the value the form
257
+ * holds when it is not one of the objects to pick, else empty (picking
258
+ * an object clears the typed value).
259
+ *
260
+ * @spec openspec/changes/screens-settings-form-reference-free-value/specs/settings-form/spec.md#requirement-a-reference-field-can-also-take-a-typed-value
261
+ * @param {object} field The field.
262
+ * @return {string}
263
+ */
264
+ freeValue(field) {
265
+ const current = this.form[field.key];
266
+ if (typeof current !== 'string' || current === '') {
267
+ return ''
268
+ }
269
+ const options = this.referenceOptions[field.key] || [];
270
+ return options.some((option) => option.value === current) ? '' : current
271
+ },
272
+
217
273
  tr(text) {
218
274
  if (typeof text !== 'string' || text === '') {
219
275
  return ''
@@ -284,7 +340,7 @@ var script = {
284
340
  stored(field) {
285
341
  const value = readPath(this.objectData || {}, field.key);
286
342
  if (field.type === 'switch') {
287
- return value === true
343
+ return switchIsOn(value, field.values)
288
344
  }
289
345
  if (field.type === 'chips') {
290
346
  return Array.isArray(value) ? value.map((item) => String(item)) : []
@@ -408,6 +464,9 @@ var script = {
408
464
  if (Number.isNaN(value) || (field.min !== undefined && value < field.min) || (field.max !== undefined && value > field.max)) {
409
465
  errors[field.key] = this.tr('This number is not valid.');
410
466
  }
467
+ } else if (field.free && field.freePattern && this.freeValue(field) !== '' && !new RegExp(field.freePattern).test(String(value))) {
468
+ // A typed value (not one of the objects) answers to `freePattern`.
469
+ errors[field.key] = this.tr(field.freePatternMessage || 'This value is not valid.');
411
470
  } else if (field.pattern && !new RegExp(field.pattern).test(String(value))) {
412
471
  errors[field.key] = this.tr(field.patternMessage || 'This value is not valid.');
413
472
  }
@@ -441,6 +500,12 @@ var script = {
441
500
  }
442
501
  }
443
502
  const patch = changedFields(compare, next);
503
+ // A switch with a value map (`values: { on, off }`) writes those values.
504
+ for (const field of this.fields) {
505
+ if (field.type === 'switch' && Object.hasOwn(patch, field.key)) {
506
+ patch[field.key] = switchStoredValue(patch[field.key], field.values);
507
+ }
508
+ }
444
509
  this.saving = true;
445
510
  try {
446
511
  if (Object.keys(patch).length > 0) {
@@ -452,7 +517,7 @@ var script = {
452
517
  const field = this.fields.find((candidate) => candidate.key === key);
453
518
  const answered = readPath(data, key);
454
519
  const written = answered !== undefined ? answered : patch[key];
455
- baseline[key] = field.type === 'switch' ? written === true : (written === null ? (field.type === 'chips' ? [] : '') : written);
520
+ baseline[key] = field.type === 'switch' ? switchIsOn(written, field.values) : (written === null ? (field.type === 'chips' ? [] : '') : written);
456
521
  form[key] = baseline[key];
457
522
  loaded[key] = baseline[key];
458
523
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CnSettingsFormWidget.vue2.js","sources":["../../../../src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<form class=\"cn-settings-form\"\n\t\tdata-testid=\"cn-settings-form\"\n\t\tnovalidate\n\t\t@submit.prevent=\"save\">\n\t\t<div class=\"cn-settings-form__grid\" :class=\"`cn-settings-form__grid--${columns}`\">\n\t\t\t<div\n\t\t\t\tv-for=\"field in fields\"\n\t\t\t\t:key=\"field.key\"\n\t\t\t\tclass=\"cn-settings-form__field\"\n\t\t\t\t:class=\"{ 'cn-settings-form__field--wide': field.wide }\"\n\t\t\t\t:data-testid=\"`cn-settings-form-field-${field.key}`\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\tv-if=\"field.type === 'switch'\"\n\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t:disabled=\"field.readOnly\">\n\t\t\t\t\t{{ field.label }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<CnChipsFieldWidget\n\t\t\t\t\tv-else-if=\"field.type === 'chips'\"\n\t\t\t\t\t:modelValue=\"form[field.key]\"\n\t\t\t\t\t:content=\"chipsContent(field)\"\n\t\t\t\t\t@update:modelValue=\"form[field.key] = $event\" />\n\t\t\t\t<template v-else>\n\t\t\t\t\t<label class=\"cn-settings-form__label\" :for=\"inputId(field)\">{{ field.label }}</label>\n\t\t\t\t\t<div v-if=\"field.type === 'file'\" class=\"cn-settings-form__file\" :data-testid=\"`cn-settings-form-file-${field.key}`\">\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\t\tclass=\"cn-settings-form__control cn-settings-form__control--file\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-settings-form__control--placeholder': !form[field.key] }\">\n\t\t\t\t\t\t\t{{ form[field.key] ? fileName(form[field.key]) : field.placeholder }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"!field.readOnly\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t:aria-describedby=\"inputId(field)\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-settings-form-choose-${field.key}`\"\n\t\t\t\t\t\t\t@click=\"chooseFile(field)\">\n\t\t\t\t\t\t\t{{ field.chooseLabel }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"!field.readOnly && form[field.key]\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-settings-form-clear-${field.key}`\"\n\t\t\t\t\t\t\t@click=\"form[field.key] = ''\">\n\t\t\t\t\t\t\t{{ field.clearLabel }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t\t<select\n\t\t\t\t\t\tv-else-if=\"field.type === 'reference'\"\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\t\tclass=\"cn-settings-form__control\"\n\t\t\t\t\t\t:disabled=\"field.readOnly\"\n\t\t\t\t\t\t:aria-busy=\"referenceState[field.key] === 'loading' ? 'true' : null\"\n\t\t\t\t\t\t:data-testid=\"`cn-settings-form-reference-${field.key}`\">\n\t\t\t\t\t\t<option v-for=\"option in referenceChoices(field)\" :key=\"option.value\" :value=\"option.value\">\n\t\t\t\t\t\t\t{{ option.label }}\n\t\t\t\t\t\t</option>\n\t\t\t\t\t</select>\n\t\t\t\t\t<select\n\t\t\t\t\t\tv-else-if=\"field.type === 'select'\"\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\t\tclass=\"cn-settings-form__control\"\n\t\t\t\t\t\t:disabled=\"field.readOnly\">\n\t\t\t\t\t\t<option v-for=\"option in field.options\" :key=\"String(option.value)\" :value=\"option.value\">\n\t\t\t\t\t\t\t{{ option.label }}\n\t\t\t\t\t\t</option>\n\t\t\t\t\t</select>\n\t\t\t\t\t<textarea\n\t\t\t\t\t\tv-else-if=\"field.type === 'textarea'\"\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\t\tclass=\"cn-settings-form__control cn-settings-form__control--area\"\n\t\t\t\t\t\t:rows=\"field.rows\"\n\t\t\t\t\t\t:placeholder=\"field.placeholder\"\n\t\t\t\t\t\t:readonly=\"field.readOnly\" />\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-else\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\t\tclass=\"cn-settings-form__control\"\n\t\t\t\t\t\t:type=\"field.type === 'number' ? 'number' : 'text'\"\n\t\t\t\t\t\t:min=\"field.min\"\n\t\t\t\t\t\t:max=\"field.max\"\n\t\t\t\t\t\t:placeholder=\"field.placeholder\"\n\t\t\t\t\t\t:readonly=\"field.readOnly\"\n\t\t\t\t\t\t:aria-invalid=\"errors[field.key] ? 'true' : null\">\n\t\t\t\t</template>\n\t\t\t\t<p v-if=\"errors[field.key]\" class=\"cn-settings-form__error\" role=\"alert\">\n\t\t\t\t\t{{ errors[field.key] }}\n\t\t\t\t</p>\n\t\t\t\t<p v-else-if=\"field.hint\" class=\"cn-settings-form__hint\">\n\t\t\t\t\t{{ field.hint }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-if=\"notice\" :type=\"noticeType\" data-testid=\"cn-settings-form-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\n\t\t<div v-if=\"!readOnly\" class=\"cn-settings-form__actions\">\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\ttype=\"submit\"\n\t\t\t\t:disabled=\"saving\"\n\t\t\t\tdata-testid=\"cn-settings-form-save\">\n\t\t\t\t{{ saveLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t</form>\n</template>\n\n<script>\nimport { FilePickerClosed, getFilePickerBuilder } from '@nextcloud/dialogs'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport CnChipsFieldWidget from '../CnChipsFieldWidget/CnChipsFieldWidget.vue'\nimport { pickRefLabel } from '../../composables/useRefLabels.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { changedFields, objectUrlOf, writeFields } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n// The native file-picker modal ships its chrome styles here; without this the\n// spawned picker renders unstyled. Rules are scoped to the picker/dialog classes.\nimport '@nextcloud/dialogs/style.css'\n\nconst TYPES = ['text', 'textarea', 'select', 'switch', 'number', 'file', 'chips', 'reference']\n\nlet uid = 0\n\n/**\n * CnSettingsFormWidget — the `settings-form` widget: fields of the CURRENT\n * object as a one- or two-column grid of framed inputs with light labels and\n * hints, saved by ONE PATCH of the fields that changed since the last save.\n *\n * \"Last save\" is the baseline this widget keeps: a save moves it forward, so\n * editing a field back to the value the page loaded with, after a save, still\n * counts as a change (comparing against the loaded object skipped that PATCH).\n *\n * @spec openspec/changes/abstract-settings-form/specs/settings-form/spec.md\n */\nexport default {\n\tname: 'CnSettingsFormWidget',\n\n\tcomponents: { CnChipsFieldWidget, NcButton, NcCheckboxRadioSwitch, 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 * - `fields` (required) — `[{ key, label, type?: 'text'|'textarea'|'select'|'switch'|'number'|'file'|'chips'|'reference', register?, schema?, labelField?, valueTemplate?, filter?, limit?, emptyLabel?, default?, minItems?, required?, minItemsMessage?, lowercase?, addLabel?, confirmLabel?, removeLabel?, picker?: { title?, mimeTypes?, startAt?, valueTemplate? }, chooseLabel?, clearLabel?, hint?, placeholder?, options?: [{ value, label }], required?, pattern?, patternMessage?, min?, max?, rows?, wide?, readOnly? }]`; `key` is a field of the object, a top-level name or a dot-path.\n\t\t * - `save` — `{ url, method?, payload? }`, write through an app endpoint (tokens `{value}`, `{field}`, `{changes}`, `{object.<path>}`).\n\t\t * - `columns` — 1 or 2 (default 2).\n\t\t * - `saveLabel`, `savedText`, `readOnly`.\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\tuid,\n\t\t\tform: {},\n\t\t\tbaseline: {},\n\t\t\tloaded: {},\n\t\t\t// `reference` fields: the objects to choose from and the read's state (`loading`, `ready`, `error`), by field key.\n\t\t\treferenceOptions: {},\n\t\t\treferenceState: {},\n\t\t\terrors: {},\n\t\t\tsaving: false,\n\t\t\tnotice: '',\n\t\t\tnoticeType: 'success',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The configured fields, normalised and translated.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tfields() {\n\t\t\tconst list = Array.isArray(this.content.fields) ? this.content.fields : []\n\t\t\treturn list\n\t\t\t\t.filter((field) => field && field.key)\n\t\t\t\t.map((field) => ({\n\t\t\t\t\t...field,\n\t\t\t\t\ttype: TYPES.includes(field.type) ? field.type : 'text',\n\t\t\t\t\tlabel: this.tr(field.label || field.key),\n\t\t\t\t\thint: this.tr(field.hint || ''),\n\t\t\t\t\tplaceholder: this.tr(field.placeholder || ''),\n\t\t\t\t\tchooseLabel: this.tr(field.chooseLabel || 'Choose a file'),\n\t\t\t\t\tclearLabel: this.tr(field.clearLabel || 'Remove'),\n\t\t\t\t\trows: field.rows || 3,\n\t\t\t\t\twide: field.wide === true || field.type === 'textarea',\n\t\t\t\t\treadOnly: this.readOnly || field.readOnly === true,\n\t\t\t\t\toptions: (Array.isArray(field.options) ? field.options : []).map((option) => (\n\t\t\t\t\t\ttypeof option === 'object' && option !== null\n\t\t\t\t\t\t\t? { value: option.value, label: this.tr(String(option.label ?? option.value)) }\n\t\t\t\t\t\t\t: { value: option, label: this.tr(String(option)) }\n\t\t\t\t\t)),\n\t\t\t\t}))\n\t\t},\n\n\t\tcolumns() {\n\t\t\treturn this.content.columns === 1 ? 1 : 2\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tsaveLabel() {\n\t\t\treturn this.tr(this.content.saveLabel || 'Save')\n\t\t},\n\n\t\t/** The object URL the form is saved to, or '' when it is not known. */\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},\n\t},\n\n\tcreated() {\n\t\tthis.adopt(true)\n\t\tthis.loadReferences()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the objects each `reference` field chooses from: one list read\n\t\t * per field of its `register` and `schema` (`filter` as query\n\t\t * parameters, at most `limit`, 100 by default). A failed read leaves the\n\t\t * field with its stored value only, and says so in the hint's place.\n\t\t *\n\t\t * @spec openspec/changes/screens-settings-form-reference/specs/settings-form/spec.md#requirement-a-settings-form-field-can-pick-an-object\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadReferences() {\n\t\t\tconst fields = this.fields.filter((field) => field.type === 'reference' && typeof field.register === 'string' && field.register !== '' && typeof field.schema === 'string' && field.schema !== '')\n\t\t\tif (fields.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\tawait Promise.all(fields.map(async (field) => {\n\t\t\t\tthis.referenceState = { ...this.referenceState, [field.key]: 'loading' }\n\t\t\t\ttry {\n\t\t\t\t\tconst url = `/apps/openregister/api/objects/${encodeURIComponent(field.register)}/${encodeURIComponent(field.schema)}`\n\t\t\t\t\tconst params = { ...(field.filter && typeof field.filter === 'object' ? field.filter : {}), _limit: Number(field.limit) > 0 ? Number(field.limit) : 100 }\n\t\t\t\t\tconst { data } = await axios.get(prefixUrl(url), { params })\n\t\t\t\t\tconst rows = Array.isArray(data) ? data : (Array.isArray(data?.results) ? data.results : [])\n\t\t\t\t\tconst options = []\n\t\t\t\t\tfor (const row of rows) {\n\t\t\t\t\t\tconst id = row && (row.id ?? row.uuid ?? (row['@self'] && row['@self'].id))\n\t\t\t\t\t\tif (id === undefined || id === null || id === '') {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst scope = { ...row, id, register: field.register, schema: field.schema }\n\t\t\t\t\t\tconst value = fillTemplate(typeof field.valueTemplate === 'string' && field.valueTemplate !== '' ? field.valueTemplate : '{id}', scope)\n\t\t\t\t\t\tif (value !== '') {\n\t\t\t\t\t\t\toptions.push({ value, label: pickRefLabel(row, field.labelField) || String(id) })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.referenceOptions = { ...this.referenceOptions, [field.key]: options }\n\t\t\t\t\tthis.referenceState = { ...this.referenceState, [field.key]: 'ready' }\n\t\t\t\t} catch {\n\t\t\t\t\tthis.referenceOptions = { ...this.referenceOptions, [field.key]: [] }\n\t\t\t\t\tthis.referenceState = { ...this.referenceState, [field.key]: 'error' }\n\t\t\t\t\tthis.errors = { ...this.errors, [field.key]: this.tr('The list to choose from could not be loaded.') }\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The choices of a `reference` field: \"none\" (unless required), the\n\t\t * objects read, and the value the form holds when it is not one of\n\t\t * them (a free string such as a URL stays selectable, as it is stored).\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\treferenceChoices(field) {\n\t\t\tconst options = this.referenceOptions[field.key] || []\n\t\t\tconst current = this.form[field.key]\n\t\t\tconst choices = field.required ? [] : [{ value: '', label: this.tr(field.emptyLabel || 'None') }]\n\t\t\tif (typeof current === 'string' && current !== '' && !options.some((option) => option.value === current)) {\n\t\t\t\tchoices.push({ value: current, label: current })\n\t\t\t}\n\t\t\treturn [...choices, ...options]\n\t\t},\n\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\tinputId(field) {\n\t\t\treturn `cn-settings-form-${this.uid}-${field.key}`\n\t\t},\n\n\t\t/**\n\t\t * The name shown for a stored file value: its last path segment.\n\t\t *\n\t\t * @param {string} value The stored value.\n\t\t * @return {string}\n\t\t */\n\t\tfileName(value) {\n\t\t\tconst text = String(value)\n\t\t\treturn text.split('/').filter(Boolean).pop() || text\n\t\t},\n\n\t\t/**\n\t\t * Open the Nextcloud file picker and take the chosen file as the value.\n\t\t * `field.picker` = `{ title?, mimeTypes?, startAt?, valueTemplate? }`; the\n\t\t * template's `{path}`, `{fileid}` and `{name}` are filled from the chosen\n\t\t * node (default `{path}`).\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-settings-form-file/specs/settings-form/spec.md#requirement-a-file-field-takes-a-file-from-the-nextcloud-picker\n\t\t */\n\t\tasync chooseFile(field) {\n\t\t\tconst picker = field.picker || {}\n\t\t\tlet builder = getFilePickerBuilder(this.tr(picker.title || field.label))\n\t\t\t\t.setMultiSelect(false)\n\t\t\t\t.allowDirectories(false)\n\t\t\t\t.startAt(picker.startAt || '/')\n\t\t\t\t.addButton({ label: t('nextcloud-vue', 'Choose'), type: 'primary', callback: () => {} })\n\t\t\tif (Array.isArray(picker.mimeTypes) && picker.mimeTypes.length > 0) {\n\t\t\t\tbuilder = builder.setMimeTypeFilter(picker.mimeTypes)\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst nodes = await builder.build().pickNodes()\n\t\t\t\tconst node = Array.isArray(nodes) ? nodes[0] : nodes\n\t\t\t\tif (!node) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.form[field.key] = String(picker.valueTemplate || '{path}').replace(/\\{(path|fileid|name)\\}/g, (match, part) => {\n\t\t\t\t\tconst value = part === 'name' ? (node.basename || this.fileName(node.path)) : node[part]\n\t\t\t\t\treturn value === undefined || value === null ? '' : String(value)\n\t\t\t\t})\n\t\t\t} catch (e) {\n\t\t\t\tif (e instanceof FilePickerClosed) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = this.tr('The file picker could not be opened.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The stored value of a field as the input holds it.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\tstored(field) {\n\t\t\tconst value = readPath(this.objectData || {}, field.key)\n\t\t\tif (field.type === 'switch') {\n\t\t\t\treturn value === true\n\t\t\t}\n\t\t\tif (field.type === 'chips') {\n\t\t\t\treturn Array.isArray(value) ? value.map((item) => String(item)) : []\n\t\t\t}\n\t\t\treturn value === undefined || value === null ? '' : value\n\t\t},\n\n\t\t/**\n\t\t * The value the input shows for a field: the stored one, else the field's\n\t\t * `default` when nothing is stored. The baseline stays the stored value, so\n\t\t * a default that was never saved counts as a change and the next Save writes it.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\tshown(field) {\n\t\t\tconst value = this.stored(field)\n\t\t\tconst absent = readPath(this.objectData || {}, field.key) === undefined || readPath(this.objectData || {}, field.key) === null || value === '' || (field.type === 'chips' && value.length === 0)\n\t\t\tif (absent && field.default !== undefined) {\n\t\t\t\treturn field.type === 'chips' && Array.isArray(field.default) ? [...field.default] : field.default\n\t\t\t}\n\t\t\treturn value\n\t\t},\n\n\t\t/**\n\t\t * Take the object's values as the new baseline; a field the person has\n\t\t * not touched follows it, a touched one keeps the typed value.\n\t\t *\n\t\t * @param {boolean} [first] Whether this is the first read.\n\t\t */\n\t\tadopt(first = false) {\n\t\t\tconst baseline = {}\n\t\t\tconst loaded = {}\n\t\t\tconst form = {}\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tbaseline[field.key] = this.stored(field)\n\t\t\t\tloaded[field.key] = this.shown(field)\n\t\t\t\tconst untouched = first || JSON.stringify(this.form[field.key]) === JSON.stringify(this.loaded[field.key])\n\t\t\t\tform[field.key] = untouched ? loaded[field.key] : this.form[field.key]\n\t\t\t}\n\t\t\tthis.baseline = baseline\n\t\t\tthis.loaded = loaded\n\t\t\tthis.form = form\n\t\t},\n\n\t\t/**\n\t\t * The configuration of the embedded chips widget for a `chips` field.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {object}\n\t\t */\n\t\tchipsContent(field) {\n\t\t\treturn {\n\t\t\t\tlabel: field.label,\n\t\t\t\thint: field.hint,\n\t\t\t\tplaceholder: field.placeholder,\n\t\t\t\taddLabel: field.addLabel,\n\t\t\t\tconfirmLabel: field.confirmLabel,\n\t\t\t\tremoveLabel: field.removeLabel,\n\t\t\t\tpattern: field.pattern,\n\t\t\t\tpatternMessage: field.patternMessage,\n\t\t\t\tlowercase: field.lowercase,\n\t\t\t\toptions: field.options,\n\t\t\t\tminItems: field.minItems,\n\t\t\t\trequired: field.required,\n\t\t\t\tminItemsMessage: field.minItemsMessage,\n\t\t\t\treadOnly: field.readOnly,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The value to send for a field: numbers as numbers, an empty value as null.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\toutgoing(field) {\n\t\t\tconst value = this.form[field.key]\n\t\t\tif (field.type === 'number') {\n\t\t\t\treturn value === '' || value === null || value === undefined ? null : Number(value)\n\t\t\t}\n\t\t\tif (field.type === 'switch') {\n\t\t\t\treturn value === true\n\t\t\t}\n\t\t\tif (field.type === 'chips') {\n\t\t\t\treturn Array.isArray(value) ? [...value] : []\n\t\t\t}\n\t\t\tif (typeof value === 'string') {\n\t\t\t\treturn value.trim() === '' ? null : value.trim()\n\t\t\t}\n\t\t\treturn value\n\t\t},\n\n\t\t/**\n\t\t * Check required, number range and pattern before any write.\n\t\t *\n\t\t * @return {object} Error text by field key.\n\t\t */\n\t\tvalidate() {\n\t\t\tconst errors = {}\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (field.type === 'switch' || field.readOnly) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst value = this.outgoing(field)\n\t\t\t\tif (field.type === 'chips') {\n\t\t\t\t\tconst least = Number(field.minItems) > 0 ? Number(field.minItems) : (field.required ? 1 : 0)\n\t\t\t\t\tif (value.length < least) {\n\t\t\t\t\t\terrors[field.key] = this.tr(field.minItemsMessage || 'Keep at least {count}.').replace('{count}', String(least))\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst empty = value === null || value === undefined || value === ''\n\t\t\t\tif (empty) {\n\t\t\t\t\tif (field.required) {\n\t\t\t\t\t\terrors[field.key] = this.tr('Fill this in.')\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (field.type === 'number') {\n\t\t\t\t\tif (Number.isNaN(value) || (field.min !== undefined && value < field.min) || (field.max !== undefined && value > field.max)) {\n\t\t\t\t\t\terrors[field.key] = this.tr('This number is not valid.')\n\t\t\t\t\t}\n\t\t\t\t} else if (field.pattern && !new RegExp(field.pattern).test(String(value))) {\n\t\t\t\t\terrors[field.key] = this.tr(field.patternMessage || 'This value is not valid.')\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn errors\n\t\t},\n\n\t\t/**\n\t\t * Save: PATCH the fields that differ from the last saved values.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-settings-form/specs/settings-form/spec.md#requirement-a-settings-form-saves-only-what-changed\n\t\t */\n\t\tasync save() {\n\t\t\tthis.errors = this.validate()\n\t\t\tthis.notice = ''\n\t\t\tif (Object.keys(this.errors).length > 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.objectUrl && !(this.content.save && this.content.save.url)) {\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = this.tr('This form cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = {}\n\t\t\tconst compare = {}\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (!field.readOnly) {\n\t\t\t\t\tnext[field.key] = this.outgoing(field)\n\t\t\t\t\tcompare[field.key] = this.baseline[field.key] === '' ? null : this.baseline[field.key]\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst patch = changedFields(compare, next)\n\t\t\tthis.saving = true\n\t\t\ttry {\n\t\t\t\tif (Object.keys(patch).length > 0) {\n\t\t\t\t\tconst data = await writeFields(this.objectUrl, patch, { save: this.content.save, object: this.objectData })\n\t\t\t\t\tconst baseline = { ...this.baseline }\n\t\t\t\t\tconst loaded = { ...this.loaded }\n\t\t\t\t\tconst form = { ...this.form }\n\t\t\t\t\tfor (const key of Object.keys(patch)) {\n\t\t\t\t\t\tconst field = this.fields.find((candidate) => candidate.key === key)\n\t\t\t\t\t\tconst answered = readPath(data, key)\n\t\t\t\t\t\tconst written = answered !== undefined ? answered : patch[key]\n\t\t\t\t\t\tbaseline[key] = field.type === 'switch' ? written === true : (written === null ? (field.type === 'chips' ? [] : '') : written)\n\t\t\t\t\t\tform[key] = baseline[key]\n\t\t\t\t\t\tloaded[key] = baseline[key]\n\t\t\t\t\t}\n\t\t\t\t\tthis.baseline = baseline\n\t\t\t\t\tthis.loaded = loaded\n\t\t\t\t\tthis.form = form\n\t\t\t\t}\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 changed fields were written.\n\t\t\t\t * @type {{patch: object}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { patch })\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-settings-form {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 14px;\n\tmin-width: 0;\n}\n\n.cn-settings-form__grid {\n\tdisplay: grid;\n\tgap: 14px 16px;\n\tgrid-template-columns: minmax(0, 1fr);\n}\n\n.cn-settings-form__grid--2 {\n\tgrid-template-columns: repeat(2, minmax(0, 1fr));\n}\n\n.cn-settings-form__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-settings-form__field--wide {\n\tgrid-column: 1 / -1;\n}\n\n.cn-settings-form__label {\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-settings-form__control {\n\twidth: 100%;\n\tbox-sizing: border-box;\n\theight: var(--cn-board-control-height, 40px);\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-maxcontrast);\n\tborder-radius: var(--cn-board-control-radius, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont: inherit;\n}\n\n.cn-settings-form__file {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-settings-form__control--file {\n\tdisplay: inline-flex;\n\talign-items: center;\n\twidth: auto;\n\tmin-width: 120px;\n\tflex: 0 1 auto;\n\toverflow-wrap: anywhere;\n}\n\n.cn-settings-form__control--placeholder {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-form__control--area {\n\theight: auto;\n\tpadding: 10px 12px;\n\tresize: vertical;\n}\n\n.cn-settings-form__control:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 1px;\n}\n\n.cn-settings-form__hint,\n.cn-settings-form__error {\n\tmargin: 0;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-form__error {\n\tcolor: var(--color-error-text);\n}\n\n.cn-settings-form__actions {\n\tdisplay: flex;\n\tjustify-content: flex-start;\n}\n\n@media (max-width: 640px) {\n\t.cn-settings-form__grid--2 {\n\t\tgrid-template-columns: minmax(0, 1fr);\n\t}\n}\n</style>\n"],"names":["CnChipsFieldWidget","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnSettingsFormWidget.vue2.js","sources":["../../../../src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<form class=\"cn-settings-form\"\n\t\tdata-testid=\"cn-settings-form\"\n\t\tnovalidate\n\t\t@submit.prevent=\"save\">\n\t\t<div class=\"cn-settings-form__grid\" :class=\"`cn-settings-form__grid--${columns}`\">\n\t\t\t<div\n\t\t\t\tv-for=\"field in fields\"\n\t\t\t\t:key=\"field.key\"\n\t\t\t\tclass=\"cn-settings-form__field\"\n\t\t\t\t:class=\"{ 'cn-settings-form__field--wide': field.wide }\"\n\t\t\t\t:data-testid=\"`cn-settings-form-field-${field.key}`\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\tv-if=\"field.type === 'switch'\"\n\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t:disabled=\"field.readOnly\">\n\t\t\t\t\t{{ field.label }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<CnChipsFieldWidget\n\t\t\t\t\tv-else-if=\"field.type === 'chips'\"\n\t\t\t\t\t:modelValue=\"form[field.key]\"\n\t\t\t\t\t:content=\"chipsContent(field)\"\n\t\t\t\t\t@update:modelValue=\"form[field.key] = $event\" />\n\t\t\t\t<template v-else>\n\t\t\t\t\t<label class=\"cn-settings-form__label\" :for=\"inputId(field)\">{{ field.label }}</label>\n\t\t\t\t\t<div v-if=\"field.type === 'file'\" class=\"cn-settings-form__file\" :data-testid=\"`cn-settings-form-file-${field.key}`\">\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\t\tclass=\"cn-settings-form__control cn-settings-form__control--file\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-settings-form__control--placeholder': !form[field.key] }\">\n\t\t\t\t\t\t\t{{ form[field.key] ? fileName(form[field.key]) : field.placeholder }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"!field.readOnly\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t:aria-describedby=\"inputId(field)\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-settings-form-choose-${field.key}`\"\n\t\t\t\t\t\t\t@click=\"chooseFile(field)\">\n\t\t\t\t\t\t\t{{ field.chooseLabel }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"!field.readOnly && form[field.key]\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-settings-form-clear-${field.key}`\"\n\t\t\t\t\t\t\t@click=\"form[field.key] = ''\">\n\t\t\t\t\t\t\t{{ field.clearLabel }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div v-else-if=\"field.type === 'reference'\" class=\"cn-settings-form__reference\">\n\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\t\t\tclass=\"cn-settings-form__control\"\n\t\t\t\t\t\t\t:disabled=\"field.readOnly\"\n\t\t\t\t\t\t\t:aria-busy=\"referenceState[field.key] === 'loading' ? 'true' : null\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-settings-form-reference-${field.key}`\">\n\t\t\t\t\t\t\t<option v-for=\"option in referenceChoices(field)\" :key=\"option.value\" :value=\"option.value\">\n\t\t\t\t\t\t\t\t{{ option.label }}\n\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t</select>\n\t\t\t\t\t\t<!-- `free`: a typed value (a URL) besides picking an object. -->\n\t\t\t\t\t\t<template v-if=\"field.free && !field.readOnly\">\n\t\t\t\t\t\t\t<label class=\"cn-settings-form__sublabel\" :for=\"`${inputId(field)}-free`\">{{ field.freeLabel }}</label>\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t:id=\"`${inputId(field)}-free`\"\n\t\t\t\t\t\t\t\tclass=\"cn-settings-form__control\"\n\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\tinputmode=\"url\"\n\t\t\t\t\t\t\t\t:value=\"freeValue(field)\"\n\t\t\t\t\t\t\t\t:placeholder=\"field.freePlaceholder\"\n\t\t\t\t\t\t\t\t:aria-invalid=\"errors[field.key] ? 'true' : null\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-settings-form-reference-free-${field.key}`\"\n\t\t\t\t\t\t\t\t@input=\"form[field.key] = $event.target.value.trim()\">\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</div>\n\t\t\t\t\t<select\n\t\t\t\t\t\tv-else-if=\"field.type === 'select'\"\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\t\tclass=\"cn-settings-form__control\"\n\t\t\t\t\t\t:disabled=\"field.readOnly\">\n\t\t\t\t\t\t<option v-for=\"option in field.options\" :key=\"String(option.value)\" :value=\"option.value\">\n\t\t\t\t\t\t\t{{ option.label }}\n\t\t\t\t\t\t</option>\n\t\t\t\t\t</select>\n\t\t\t\t\t<textarea\n\t\t\t\t\t\tv-else-if=\"field.type === 'textarea'\"\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\t\tclass=\"cn-settings-form__control cn-settings-form__control--area\"\n\t\t\t\t\t\t:rows=\"field.rows\"\n\t\t\t\t\t\t:placeholder=\"field.placeholder\"\n\t\t\t\t\t\t:readonly=\"field.readOnly\" />\n\t\t\t\t\t<input\n\t\t\t\t\t\tv-else\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\tv-model=\"form[field.key]\"\n\t\t\t\t\t\tclass=\"cn-settings-form__control\"\n\t\t\t\t\t\t:type=\"field.type === 'number' ? 'number' : 'text'\"\n\t\t\t\t\t\t:min=\"field.min\"\n\t\t\t\t\t\t:max=\"field.max\"\n\t\t\t\t\t\t:placeholder=\"field.placeholder\"\n\t\t\t\t\t\t:readonly=\"field.readOnly\"\n\t\t\t\t\t\t:aria-invalid=\"errors[field.key] ? 'true' : null\">\n\t\t\t\t</template>\n\t\t\t\t<p v-if=\"errors[field.key]\" class=\"cn-settings-form__error\" role=\"alert\">\n\t\t\t\t\t{{ errors[field.key] }}\n\t\t\t\t</p>\n\t\t\t\t<!-- A chips field prints its own hint (it gets it in chipsContent). -->\n\t\t\t\t<p v-else-if=\"field.hint && field.type !== 'chips'\" class=\"cn-settings-form__hint\">\n\t\t\t\t\t{{ field.hint }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<NcNoteCard v-if=\"notice\" :type=\"noticeType\" data-testid=\"cn-settings-form-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\n\t\t<div v-if=\"!readOnly\" class=\"cn-settings-form__actions\">\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\ttype=\"submit\"\n\t\t\t\t:disabled=\"saving\"\n\t\t\t\tdata-testid=\"cn-settings-form-save\">\n\t\t\t\t{{ saveLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t</form>\n</template>\n\n<script>\nimport { FilePickerClosed, getFilePickerBuilder } from '@nextcloud/dialogs'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport CnChipsFieldWidget from '../CnChipsFieldWidget/CnChipsFieldWidget.vue'\nimport { pickRefLabel } from '../../composables/useRefLabels.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { changedFields, objectUrlOf, writeFields } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { hasUnresolvedTokens, resolveFilterTokens } from '../../utils/resolveFilterTokens.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\nimport { switchIsOn, switchStoredValue } from '../../utils/switchValues.js'\n\n// The native file-picker modal ships its chrome styles here; without this the\n// spawned picker renders unstyled. Rules are scoped to the picker/dialog classes.\nimport '@nextcloud/dialogs/style.css'\n\nconst TYPES = ['text', 'textarea', 'select', 'switch', 'number', 'file', 'chips', 'reference']\n\nlet uid = 0\n\n/**\n * CnSettingsFormWidget — the `settings-form` widget: fields of the CURRENT\n * object as a one- or two-column grid of framed inputs with light labels and\n * hints, saved by ONE PATCH of the fields that changed since the last save.\n *\n * \"Last save\" is the baseline this widget keeps: a save moves it forward, so\n * editing a field back to the value the page loaded with, after a save, still\n * counts as a change (comparing against the loaded object skipped that PATCH).\n *\n * @spec openspec/changes/abstract-settings-form/specs/settings-form/spec.md\n */\nexport default {\n\tname: 'CnSettingsFormWidget',\n\n\tcomponents: { CnChipsFieldWidget, NcButton, NcCheckboxRadioSwitch, 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 * - `fields` (required) — `[{ key, label, type?: 'text'|'textarea'|'select'|'switch'|'number'|'file'|'chips'|'reference', register?, schema?, labelField?, valueTemplate?, filter?, limit?, emptyLabel?, free?, freeLabel?, freePlaceholder?, freePattern?, freePatternMessage?, default?, minItems?, required?, minItemsMessage?, values?: { on, off }, lowercase?, addLabel?, confirmLabel?, removeLabel?, picker?: { title?, mimeTypes?, startAt?, valueTemplate? }, chooseLabel?, clearLabel?, hint?, placeholder?, options?: [{ value, label }], required?, pattern?, patternMessage?, min?, max?, rows?, wide?, readOnly? }]`; `key` is a field of the object, a top-level name or a dot-path. A `reference` field's `filter` values may be `@objectId` and `@object.<field>` (the record being edited). A `switch` field's `values: { on, off }` reads and writes those values instead of true/false.\n\t\t * - `save` — `{ url, method?, payload? }`, write through an app endpoint (tokens `{value}`, `{field}`, `{changes}`, `{object.<path>}`).\n\t\t * - `columns` — 1 or 2 (default 2).\n\t\t * - `saveLabel`, `savedText`, `readOnly`.\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\tuid,\n\t\t\tform: {},\n\t\t\tbaseline: {},\n\t\t\tloaded: {},\n\t\t\t// `reference` fields: the objects to choose from and the read's state (`loading`, `ready`, `error`), by field key.\n\t\t\treferenceOptions: {},\n\t\t\treferenceState: {},\n\t\t\t// The query each `reference` field was last read with, by field key, so a\n\t\t\t// new object re-reads only the fields whose filter changes with it.\n\t\t\treferenceQuery: {},\n\t\t\terrors: {},\n\t\t\tsaving: false,\n\t\t\tnotice: '',\n\t\t\tnoticeType: 'success',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The configured fields, normalised and translated.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tfields() {\n\t\t\tconst list = Array.isArray(this.content.fields) ? this.content.fields : []\n\t\t\treturn list\n\t\t\t\t.filter((field) => field && field.key)\n\t\t\t\t.map((field) => ({\n\t\t\t\t\t...field,\n\t\t\t\t\ttype: TYPES.includes(field.type) ? field.type : 'text',\n\t\t\t\t\tlabel: this.tr(field.label || field.key),\n\t\t\t\t\thint: this.tr(field.hint || ''),\n\t\t\t\t\tplaceholder: this.tr(field.placeholder || ''),\n\t\t\t\t\tchooseLabel: this.tr(field.chooseLabel || 'Choose a file'),\n\t\t\t\t\tfree: field.type === 'reference' && field.free === true,\n\t\t\t\t\tfreeLabel: this.tr(field.freeLabel || 'Or type a value'),\n\t\t\t\t\tfreePlaceholder: this.tr(field.freePlaceholder || ''),\n\t\t\t\t\tclearLabel: this.tr(field.clearLabel || 'Remove'),\n\t\t\t\t\trows: field.rows || 3,\n\t\t\t\t\twide: field.wide === true || field.type === 'textarea',\n\t\t\t\t\treadOnly: this.readOnly || field.readOnly === true,\n\t\t\t\t\toptions: (Array.isArray(field.options) ? field.options : []).map((option) => (\n\t\t\t\t\t\ttypeof option === 'object' && option !== null\n\t\t\t\t\t\t\t? { value: option.value, label: this.tr(String(option.label ?? option.value)) }\n\t\t\t\t\t\t\t: { value: option, label: this.tr(String(option)) }\n\t\t\t\t\t)),\n\t\t\t\t}))\n\t\t},\n\n\t\tcolumns() {\n\t\t\treturn this.content.columns === 1 ? 1 : 2\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tsaveLabel() {\n\t\t\treturn this.tr(this.content.saveLabel || 'Save')\n\t\t},\n\n\t\t/** The object URL the form is saved to, or '' when it is not known. */\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.loadReferences()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.adopt(true)\n\t\tthis.loadReferences()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the objects each `reference` field chooses from: one list read\n\t\t * per field of its `register` and `schema` (`filter` as query\n\t\t * parameters, at most `limit`, 100 by default). A failed read leaves the\n\t\t * field with its stored value only, and says so in the hint's place.\n\t\t *\n\t\t * `filter` values may be `@objectId` and `@object.<field>`: the record\n\t\t * the form edits, so a list can be narrowed to it (the logos of this\n\t\t * portal). Until the record has that value the field is not read; it is\n\t\t * read again when the record changes the resolved query, never twice\n\t\t * for the same query.\n\t\t *\n\t\t * @spec openspec/changes/screens-settings-form-reference/specs/settings-form/spec.md#requirement-a-settings-form-field-can-pick-an-object\n\t\t * @spec openspec/changes/screens-settings-form-reference-object-filter/specs/settings-form/spec.md#requirement-a-reference-fields-filter-can-name-the-record-being-edited\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadReferences() {\n\t\t\tconst fields = this.fields.filter((field) => field.type === 'reference' && typeof field.register === 'string' && field.register !== '' && typeof field.schema === 'string' && field.schema !== '')\n\t\t\tif (fields.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst ctx = { objectId: this.objectId || (this.objectData && this.objectData.id) || undefined, object: this.objectData || undefined }\n\t\t\tconst pending = []\n\t\t\tfor (const field of fields) {\n\t\t\t\tconst filter = resolveFilterTokens(field.filter && typeof field.filter === 'object' ? field.filter : {}, ctx)\n\t\t\t\tif (hasUnresolvedTokens(filter)) {\n\t\t\t\t\t// The record has no value for the token yet: nothing to read.\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst params = { ...filter, _limit: Number(field.limit) > 0 ? Number(field.limit) : 100 }\n\t\t\t\tconst query = JSON.stringify(params)\n\t\t\t\tif (this.referenceQuery[field.key] === query) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tthis.referenceQuery = { ...this.referenceQuery, [field.key]: query }\n\t\t\t\tpending.push({ field, params, query })\n\t\t\t}\n\t\t\tif (pending.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\tawait Promise.all(pending.map(async ({ field, params, query }) => {\n\t\t\t\tthis.referenceState = { ...this.referenceState, [field.key]: 'loading' }\n\t\t\t\ttry {\n\t\t\t\t\tconst url = `/apps/openregister/api/objects/${encodeURIComponent(field.register)}/${encodeURIComponent(field.schema)}`\n\t\t\t\t\tconst { data } = await axios.get(prefixUrl(url), { params })\n\t\t\t\t\tif (this.referenceQuery[field.key] !== query) {\n\t\t\t\t\t\t// A newer record asked for another list meanwhile.\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tconst rows = Array.isArray(data) ? data : (Array.isArray(data?.results) ? data.results : [])\n\t\t\t\t\tconst options = []\n\t\t\t\t\tfor (const row of rows) {\n\t\t\t\t\t\tconst id = row && (row.id ?? row.uuid ?? (row['@self'] && row['@self'].id))\n\t\t\t\t\t\tif (id === undefined || id === null || id === '') {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst scope = { ...row, id, register: field.register, schema: field.schema }\n\t\t\t\t\t\tconst value = fillTemplate(typeof field.valueTemplate === 'string' && field.valueTemplate !== '' ? field.valueTemplate : '{id}', scope)\n\t\t\t\t\t\tif (value !== '') {\n\t\t\t\t\t\t\toptions.push({ value, label: pickRefLabel(row, field.labelField) || String(id) })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.referenceOptions = { ...this.referenceOptions, [field.key]: options }\n\t\t\t\t\tthis.referenceState = { ...this.referenceState, [field.key]: 'ready' }\n\t\t\t\t} catch {\n\t\t\t\t\tthis.referenceOptions = { ...this.referenceOptions, [field.key]: [] }\n\t\t\t\t\tthis.referenceState = { ...this.referenceState, [field.key]: 'error' }\n\t\t\t\t\tthis.errors = { ...this.errors, [field.key]: this.tr('The list to choose from could not be loaded.') }\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The choices of a `reference` field: \"none\" (unless required), the\n\t\t * objects read, and the value the form holds when it is not one of\n\t\t * them (a free string such as a URL stays selectable, as it is stored).\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {Array<{value: string, label: string}>}\n\t\t */\n\t\treferenceChoices(field) {\n\t\t\tconst options = this.referenceOptions[field.key] || []\n\t\t\tconst current = this.form[field.key]\n\t\t\tconst choices = field.required ? [] : [{ value: '', label: this.tr(field.emptyLabel || 'None') }]\n\t\t\tif (typeof current === 'string' && current !== '' && !options.some((option) => option.value === current)) {\n\t\t\t\tchoices.push({ value: current, label: current })\n\t\t\t}\n\t\t\treturn [...choices, ...options]\n\t\t},\n\n\t\t/**\n\t\t * The typed value of a `reference` field with `free`: the value the form\n\t\t * holds when it is not one of the objects to pick, else empty (picking\n\t\t * an object clears the typed value).\n\t\t *\n\t\t * @spec openspec/changes/screens-settings-form-reference-free-value/specs/settings-form/spec.md#requirement-a-reference-field-can-also-take-a-typed-value\n\t\t * @param {object} field The field.\n\t\t * @return {string}\n\t\t */\n\t\tfreeValue(field) {\n\t\t\tconst current = this.form[field.key]\n\t\t\tif (typeof current !== 'string' || current === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst options = this.referenceOptions[field.key] || []\n\t\t\treturn options.some((option) => option.value === current) ? '' : current\n\t\t},\n\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\tinputId(field) {\n\t\t\treturn `cn-settings-form-${this.uid}-${field.key}`\n\t\t},\n\n\t\t/**\n\t\t * The name shown for a stored file value: its last path segment.\n\t\t *\n\t\t * @param {string} value The stored value.\n\t\t * @return {string}\n\t\t */\n\t\tfileName(value) {\n\t\t\tconst text = String(value)\n\t\t\treturn text.split('/').filter(Boolean).pop() || text\n\t\t},\n\n\t\t/**\n\t\t * Open the Nextcloud file picker and take the chosen file as the value.\n\t\t * `field.picker` = `{ title?, mimeTypes?, startAt?, valueTemplate? }`; the\n\t\t * template's `{path}`, `{fileid}` and `{name}` are filled from the chosen\n\t\t * node (default `{path}`).\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-settings-form-file/specs/settings-form/spec.md#requirement-a-file-field-takes-a-file-from-the-nextcloud-picker\n\t\t */\n\t\tasync chooseFile(field) {\n\t\t\tconst picker = field.picker || {}\n\t\t\tlet builder = getFilePickerBuilder(this.tr(picker.title || field.label))\n\t\t\t\t.setMultiSelect(false)\n\t\t\t\t.allowDirectories(false)\n\t\t\t\t.startAt(picker.startAt || '/')\n\t\t\t\t.addButton({ label: t('nextcloud-vue', 'Choose'), type: 'primary', callback: () => {} })\n\t\t\tif (Array.isArray(picker.mimeTypes) && picker.mimeTypes.length > 0) {\n\t\t\t\tbuilder = builder.setMimeTypeFilter(picker.mimeTypes)\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst nodes = await builder.build().pickNodes()\n\t\t\t\tconst node = Array.isArray(nodes) ? nodes[0] : nodes\n\t\t\t\tif (!node) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.form[field.key] = String(picker.valueTemplate || '{path}').replace(/\\{(path|fileid|name)\\}/g, (match, part) => {\n\t\t\t\t\tconst value = part === 'name' ? (node.basename || this.fileName(node.path)) : node[part]\n\t\t\t\t\treturn value === undefined || value === null ? '' : String(value)\n\t\t\t\t})\n\t\t\t} catch (e) {\n\t\t\t\tif (e instanceof FilePickerClosed) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = this.tr('The file picker could not be opened.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The stored value of a field as the input holds it.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\tstored(field) {\n\t\t\tconst value = readPath(this.objectData || {}, field.key)\n\t\t\tif (field.type === 'switch') {\n\t\t\t\treturn switchIsOn(value, field.values)\n\t\t\t}\n\t\t\tif (field.type === 'chips') {\n\t\t\t\treturn Array.isArray(value) ? value.map((item) => String(item)) : []\n\t\t\t}\n\t\t\treturn value === undefined || value === null ? '' : value\n\t\t},\n\n\t\t/**\n\t\t * The value the input shows for a field: the stored one, else the field's\n\t\t * `default` when nothing is stored. The baseline stays the stored value, so\n\t\t * a default that was never saved counts as a change and the next Save writes it.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\tshown(field) {\n\t\t\tconst value = this.stored(field)\n\t\t\tconst absent = readPath(this.objectData || {}, field.key) === undefined || readPath(this.objectData || {}, field.key) === null || value === '' || (field.type === 'chips' && value.length === 0)\n\t\t\tif (absent && field.default !== undefined) {\n\t\t\t\treturn field.type === 'chips' && Array.isArray(field.default) ? [...field.default] : field.default\n\t\t\t}\n\t\t\treturn value\n\t\t},\n\n\t\t/**\n\t\t * Take the object's values as the new baseline; a field the person has\n\t\t * not touched follows it, a touched one keeps the typed value.\n\t\t *\n\t\t * @param {boolean} [first] Whether this is the first read.\n\t\t */\n\t\tadopt(first = false) {\n\t\t\tconst baseline = {}\n\t\t\tconst loaded = {}\n\t\t\tconst form = {}\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tbaseline[field.key] = this.stored(field)\n\t\t\t\tloaded[field.key] = this.shown(field)\n\t\t\t\tconst untouched = first || JSON.stringify(this.form[field.key]) === JSON.stringify(this.loaded[field.key])\n\t\t\t\tform[field.key] = untouched ? loaded[field.key] : this.form[field.key]\n\t\t\t}\n\t\t\tthis.baseline = baseline\n\t\t\tthis.loaded = loaded\n\t\t\tthis.form = form\n\t\t},\n\n\t\t/**\n\t\t * The configuration of the embedded chips widget for a `chips` field.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {object}\n\t\t */\n\t\tchipsContent(field) {\n\t\t\treturn {\n\t\t\t\tlabel: field.label,\n\t\t\t\thint: field.hint,\n\t\t\t\tplaceholder: field.placeholder,\n\t\t\t\taddLabel: field.addLabel,\n\t\t\t\tconfirmLabel: field.confirmLabel,\n\t\t\t\tremoveLabel: field.removeLabel,\n\t\t\t\tpattern: field.pattern,\n\t\t\t\tpatternMessage: field.patternMessage,\n\t\t\t\tlowercase: field.lowercase,\n\t\t\t\toptions: field.options,\n\t\t\t\tminItems: field.minItems,\n\t\t\t\trequired: field.required,\n\t\t\t\tminItemsMessage: field.minItemsMessage,\n\t\t\t\treadOnly: field.readOnly,\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The value to send for a field: numbers as numbers, an empty value as null.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {unknown}\n\t\t */\n\t\toutgoing(field) {\n\t\t\tconst value = this.form[field.key]\n\t\t\tif (field.type === 'number') {\n\t\t\t\treturn value === '' || value === null || value === undefined ? null : Number(value)\n\t\t\t}\n\t\t\tif (field.type === 'switch') {\n\t\t\t\treturn value === true\n\t\t\t}\n\t\t\tif (field.type === 'chips') {\n\t\t\t\treturn Array.isArray(value) ? [...value] : []\n\t\t\t}\n\t\t\tif (typeof value === 'string') {\n\t\t\t\treturn value.trim() === '' ? null : value.trim()\n\t\t\t}\n\t\t\treturn value\n\t\t},\n\n\t\t/**\n\t\t * Check required, number range and pattern before any write.\n\t\t *\n\t\t * @return {object} Error text by field key.\n\t\t */\n\t\tvalidate() {\n\t\t\tconst errors = {}\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (field.type === 'switch' || field.readOnly) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst value = this.outgoing(field)\n\t\t\t\tif (field.type === 'chips') {\n\t\t\t\t\tconst least = Number(field.minItems) > 0 ? Number(field.minItems) : (field.required ? 1 : 0)\n\t\t\t\t\tif (value.length < least) {\n\t\t\t\t\t\terrors[field.key] = this.tr(field.minItemsMessage || 'Keep at least {count}.').replace('{count}', String(least))\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst empty = value === null || value === undefined || value === ''\n\t\t\t\tif (empty) {\n\t\t\t\t\tif (field.required) {\n\t\t\t\t\t\terrors[field.key] = this.tr('Fill this in.')\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (field.type === 'number') {\n\t\t\t\t\tif (Number.isNaN(value) || (field.min !== undefined && value < field.min) || (field.max !== undefined && value > field.max)) {\n\t\t\t\t\t\terrors[field.key] = this.tr('This number is not valid.')\n\t\t\t\t\t}\n\t\t\t\t} else if (field.free && field.freePattern && this.freeValue(field) !== '' && !new RegExp(field.freePattern).test(String(value))) {\n\t\t\t\t\t// A typed value (not one of the objects) answers to `freePattern`.\n\t\t\t\t\terrors[field.key] = this.tr(field.freePatternMessage || 'This value is not valid.')\n\t\t\t\t} else if (field.pattern && !new RegExp(field.pattern).test(String(value))) {\n\t\t\t\t\terrors[field.key] = this.tr(field.patternMessage || 'This value is not valid.')\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn errors\n\t\t},\n\n\t\t/**\n\t\t * Save: PATCH the fields that differ from the last saved values.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-settings-form/specs/settings-form/spec.md#requirement-a-settings-form-saves-only-what-changed\n\t\t */\n\t\tasync save() {\n\t\t\tthis.errors = this.validate()\n\t\t\tthis.notice = ''\n\t\t\tif (Object.keys(this.errors).length > 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (!this.objectUrl && !(this.content.save && this.content.save.url)) {\n\t\t\t\tthis.noticeType = 'error'\n\t\t\t\tthis.notice = this.tr('This form cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = {}\n\t\t\tconst compare = {}\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (!field.readOnly) {\n\t\t\t\t\tnext[field.key] = this.outgoing(field)\n\t\t\t\t\tcompare[field.key] = this.baseline[field.key] === '' ? null : this.baseline[field.key]\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst patch = changedFields(compare, next)\n\t\t\t// A switch with a value map (`values: { on, off }`) writes those values.\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (field.type === 'switch' && Object.hasOwn(patch, field.key)) {\n\t\t\t\t\tpatch[field.key] = switchStoredValue(patch[field.key], field.values)\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\ttry {\n\t\t\t\tif (Object.keys(patch).length > 0) {\n\t\t\t\t\tconst data = await writeFields(this.objectUrl, patch, { save: this.content.save, object: this.objectData })\n\t\t\t\t\tconst baseline = { ...this.baseline }\n\t\t\t\t\tconst loaded = { ...this.loaded }\n\t\t\t\t\tconst form = { ...this.form }\n\t\t\t\t\tfor (const key of Object.keys(patch)) {\n\t\t\t\t\t\tconst field = this.fields.find((candidate) => candidate.key === key)\n\t\t\t\t\t\tconst answered = readPath(data, key)\n\t\t\t\t\t\tconst written = answered !== undefined ? answered : patch[key]\n\t\t\t\t\t\tbaseline[key] = field.type === 'switch' ? switchIsOn(written, field.values) : (written === null ? (field.type === 'chips' ? [] : '') : written)\n\t\t\t\t\t\tform[key] = baseline[key]\n\t\t\t\t\t\tloaded[key] = baseline[key]\n\t\t\t\t\t}\n\t\t\t\t\tthis.baseline = baseline\n\t\t\t\t\tthis.loaded = loaded\n\t\t\t\t\tthis.form = form\n\t\t\t\t}\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 changed fields were written.\n\t\t\t\t * @type {{patch: object}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { patch })\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-settings-form {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 14px;\n\tmin-width: 0;\n}\n\n.cn-settings-form__grid {\n\tdisplay: grid;\n\tgap: 14px 16px;\n\tgrid-template-columns: minmax(0, 1fr);\n}\n\n.cn-settings-form__grid--2 {\n\tgrid-template-columns: repeat(2, minmax(0, 1fr));\n}\n\n.cn-settings-form__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-settings-form__field--wide {\n\tgrid-column: 1 / -1;\n}\n\n.cn-settings-form__label {\n\tfont-size: 13px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-settings-form__reference {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-settings-form__sublabel {\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-form__control {\n\twidth: 100%;\n\tbox-sizing: border-box;\n\theight: var(--cn-board-control-height, 40px);\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-maxcontrast);\n\tborder-radius: var(--cn-board-control-radius, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont: inherit;\n}\n\n.cn-settings-form__file {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-settings-form__control--file {\n\tdisplay: inline-flex;\n\talign-items: center;\n\twidth: auto;\n\tmin-width: 120px;\n\tflex: 0 1 auto;\n\toverflow-wrap: anywhere;\n}\n\n.cn-settings-form__control--placeholder {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-form__control--area {\n\theight: auto;\n\tpadding: 10px 12px;\n\tresize: vertical;\n}\n\n.cn-settings-form__control:focus-visible {\n\toutline: 2px solid var(--color-primary-element);\n\toutline-offset: 1px;\n}\n\n.cn-settings-form__hint,\n.cn-settings-form__error {\n\tmargin: 0;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-form__error {\n\tcolor: var(--color-error-text);\n}\n\n.cn-settings-form__actions {\n\tdisplay: flex;\n\tjustify-content: flex-start;\n}\n\n@media (max-width: 640px) {\n\t.cn-settings-form__grid--2 {\n\t\tgrid-template-columns: minmax(0, 1fr);\n\t}\n}\n</style>\n"],"names":["CnChipsFieldWidget","t"],"mappings":"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"}
@@ -4,22 +4,28 @@ const _hoisted_1 = ["data-testid"];
4
4
  const _hoisted_2 = ["for"];
5
5
  const _hoisted_3 = ["data-testid"];
6
6
  const _hoisted_4 = ["id"];
7
- const _hoisted_5 = ["id", "onUpdate:modelValue", "disabled", "aria-busy", "data-testid"];
8
- const _hoisted_6 = ["value"];
9
- const _hoisted_7 = ["id", "onUpdate:modelValue", "disabled"];
10
- const _hoisted_8 = ["value"];
11
- const _hoisted_9 = ["id", "onUpdate:modelValue", "rows", "placeholder", "readonly"];
12
- const _hoisted_10 = ["id", "onUpdate:modelValue", "type", "min", "max", "placeholder", "readonly", "aria-invalid"];
13
- const _hoisted_11 = {
7
+ const _hoisted_5 = {
8
+ key: 1,
9
+ class: "cn-settings-form__reference"
10
+ };
11
+ const _hoisted_6 = ["id", "onUpdate:modelValue", "disabled", "aria-busy", "data-testid"];
12
+ const _hoisted_7 = ["value"];
13
+ const _hoisted_8 = ["for"];
14
+ const _hoisted_9 = ["id", "value", "placeholder", "aria-invalid", "data-testid", "onInput"];
15
+ const _hoisted_10 = ["id", "onUpdate:modelValue", "disabled"];
16
+ const _hoisted_11 = ["value"];
17
+ const _hoisted_12 = ["id", "onUpdate:modelValue", "rows", "placeholder", "readonly"];
18
+ const _hoisted_13 = ["id", "onUpdate:modelValue", "type", "min", "max", "placeholder", "readonly", "aria-invalid"];
19
+ const _hoisted_14 = {
14
20
  key: 3,
15
21
  class: "cn-settings-form__error",
16
22
  role: "alert"
17
23
  };
18
- const _hoisted_12 = {
24
+ const _hoisted_15 = {
19
25
  key: 4,
20
26
  class: "cn-settings-form__hint"
21
27
  };
22
- const _hoisted_13 = {
28
+ const _hoisted_16 = {
23
29
  key: 1,
24
30
  class: "cn-settings-form__actions"
25
31
  };
@@ -109,24 +115,44 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
109
115
  : createCommentVNode("v-if", true)
110
116
  ], 8 /* PROPS */, _hoisted_3))
111
117
  : (field.type === 'reference')
112
- ? withDirectives((openBlock(), createElementBlock("select", {
113
- key: 1,
114
- id: $options.inputId(field),
115
- "onUpdate:modelValue": $event => (($data.form[field.key]) = $event),
116
- class: "cn-settings-form__control",
117
- disabled: field.readOnly,
118
- "aria-busy": $data.referenceState[field.key] === 'loading' ? 'true' : null,
119
- "data-testid": `cn-settings-form-reference-${field.key}`
120
- }, [
121
- (openBlock(true), createElementBlock(Fragment, null, renderList($options.referenceChoices(field), (option) => {
122
- return (openBlock(), createElementBlock("option", {
123
- key: option.value,
124
- value: option.value
125
- }, toDisplayString(option.label), 9 /* TEXT, PROPS */, _hoisted_6))
126
- }), 128 /* KEYED_FRAGMENT */))
127
- ], 8 /* PROPS */, _hoisted_5)), [
128
- [vModelSelect, $data.form[field.key]]
129
- ])
118
+ ? (openBlock(), createElementBlock("div", _hoisted_5, [
119
+ withDirectives(createElementVNode("select", {
120
+ id: $options.inputId(field),
121
+ "onUpdate:modelValue": $event => (($data.form[field.key]) = $event),
122
+ class: "cn-settings-form__control",
123
+ disabled: field.readOnly,
124
+ "aria-busy": $data.referenceState[field.key] === 'loading' ? 'true' : null,
125
+ "data-testid": `cn-settings-form-reference-${field.key}`
126
+ }, [
127
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.referenceChoices(field), (option) => {
128
+ return (openBlock(), createElementBlock("option", {
129
+ key: option.value,
130
+ value: option.value
131
+ }, toDisplayString(option.label), 9 /* TEXT, PROPS */, _hoisted_7))
132
+ }), 128 /* KEYED_FRAGMENT */))
133
+ ], 8 /* PROPS */, _hoisted_6), [
134
+ [vModelSelect, $data.form[field.key]]
135
+ ]),
136
+ (field.free && !field.readOnly)
137
+ ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
138
+ createElementVNode("label", {
139
+ class: "cn-settings-form__sublabel",
140
+ for: `${$options.inputId(field)}-free`
141
+ }, toDisplayString(field.freeLabel), 9 /* TEXT, PROPS */, _hoisted_8),
142
+ createElementVNode("input", {
143
+ id: `${$options.inputId(field)}-free`,
144
+ class: "cn-settings-form__control",
145
+ type: "text",
146
+ inputmode: "url",
147
+ value: $options.freeValue(field),
148
+ placeholder: field.freePlaceholder,
149
+ "aria-invalid": $data.errors[field.key] ? 'true' : null,
150
+ "data-testid": `cn-settings-form-reference-free-${field.key}`,
151
+ onInput: $event => ($data.form[field.key] = $event.target.value.trim())
152
+ }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_9)
153
+ ], 64 /* STABLE_FRAGMENT */))
154
+ : createCommentVNode("v-if", true)
155
+ ]))
130
156
  : (field.type === 'select')
131
157
  ? withDirectives((openBlock(), createElementBlock("select", {
132
158
  key: 2,
@@ -139,9 +165,9 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
139
165
  return (openBlock(), createElementBlock("option", {
140
166
  key: String(option.value),
141
167
  value: option.value
142
- }, toDisplayString(option.label), 9 /* TEXT, PROPS */, _hoisted_8))
168
+ }, toDisplayString(option.label), 9 /* TEXT, PROPS */, _hoisted_11))
143
169
  }), 128 /* KEYED_FRAGMENT */))
144
- ], 8 /* PROPS */, _hoisted_7)), [
170
+ ], 8 /* PROPS */, _hoisted_10)), [
145
171
  [vModelSelect, $data.form[field.key]]
146
172
  ])
147
173
  : (field.type === 'textarea')
@@ -153,7 +179,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
153
179
  rows: field.rows,
154
180
  placeholder: field.placeholder,
155
181
  readonly: field.readOnly
156
- }, null, 8 /* PROPS */, _hoisted_9)), [
182
+ }, null, 8 /* PROPS */, _hoisted_12)), [
157
183
  [vModelText, $data.form[field.key]]
158
184
  ])
159
185
  : withDirectives((openBlock(), createElementBlock("input", {
@@ -167,14 +193,14 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
167
193
  placeholder: field.placeholder,
168
194
  readonly: field.readOnly,
169
195
  "aria-invalid": $data.errors[field.key] ? 'true' : null
170
- }, null, 8 /* PROPS */, _hoisted_10)), [
196
+ }, null, 8 /* PROPS */, _hoisted_13)), [
171
197
  [vModelDynamic, $data.form[field.key]]
172
198
  ])
173
199
  ], 64 /* STABLE_FRAGMENT */)),
174
200
  ($data.errors[field.key])
175
- ? (openBlock(), createElementBlock("p", _hoisted_11, toDisplayString($data.errors[field.key]), 1 /* TEXT */))
176
- : (field.hint)
177
- ? (openBlock(), createElementBlock("p", _hoisted_12, toDisplayString(field.hint), 1 /* TEXT */))
201
+ ? (openBlock(), createElementBlock("p", _hoisted_14, toDisplayString($data.errors[field.key]), 1 /* TEXT */))
202
+ : (field.hint && field.type !== 'chips')
203
+ ? (openBlock(), createElementBlock("p", _hoisted_15, toDisplayString(field.hint), 1 /* TEXT */))
178
204
  : createCommentVNode("v-if", true)
179
205
  ], 10 /* CLASS, PROPS */, _hoisted_1))
180
206
  }), 128 /* KEYED_FRAGMENT */))
@@ -192,7 +218,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
192
218
  }, 8 /* PROPS */, ["type"]))
193
219
  : createCommentVNode("v-if", true),
194
220
  (!$options.readOnly)
195
- ? (openBlock(), createElementBlock("div", _hoisted_13, [
221
+ ? (openBlock(), createElementBlock("div", _hoisted_16, [
196
222
  createVNode(_component_NcButton, {
197
223
  variant: "primary",
198
224
  type: "submit",