@conduction/nextcloud-vue 2.133.0 → 2.134.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 (39) hide show
  1. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
  2. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +85 -10
  3. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
  4. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +60 -36
  5. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
  6. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidget.vue.js +1 -1
  7. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidget.vue2.js +10 -0
  8. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidget.vue2.js.map +1 -1
  9. package/dist/esm/components/CnIntegrationWidget/CnIntegrationWidget.vue3.js.map +1 -1
  10. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue.js +1 -1
  11. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js +202 -6
  12. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue2.js.map +1 -1
  13. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js +137 -55
  14. package/dist/esm/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue3.js.map +1 -1
  15. package/dist/esm/dialogs/CnPartyAddDialog.vue.js +9 -0
  16. package/dist/esm/dialogs/CnPartyAddDialog.vue.js.map +1 -0
  17. package/dist/esm/dialogs/CnPartyAddDialog.vue2.js +184 -0
  18. package/dist/esm/dialogs/CnPartyAddDialog.vue2.js.map +1 -0
  19. package/dist/esm/dialogs/CnPartyAddDialog.vue3.js +168 -0
  20. package/dist/esm/dialogs/CnPartyAddDialog.vue3.js.map +1 -0
  21. package/dist/esm/l10n/en.json.js +11 -1
  22. package/dist/esm/l10n/en.json.js.map +1 -1
  23. package/dist/esm/l10n/nl.json.js +11 -1
  24. package/dist/esm/l10n/nl.json.js.map +1 -1
  25. package/dist/esm/library-style.js +1 -1
  26. package/dist/esm/nextcloud-vue.css +95 -70
  27. package/dist/esm/utils/objectParties.js +79 -1
  28. package/dist/esm/utils/objectParties.js.map +1 -1
  29. package/dist/nextcloud-vue.cjs.js +5683 -4860
  30. package/dist/nextcloud-vue.cjs.js.map +2 -2
  31. package/dist/nextcloud-vue.css +95 -70
  32. package/l10n/en.json +11 -1
  33. package/l10n/nl.json +11 -1
  34. package/package.json +1 -1
  35. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +105 -12
  36. package/src/components/CnIntegrationWidget/CnIntegrationWidget.vue +10 -0
  37. package/src/components/CnObjectPartiesWidget/CnObjectPartiesWidget.vue +264 -3
  38. package/src/dialogs/CnPartyAddDialog.vue +309 -0
  39. package/src/utils/objectParties.js +78 -0
@@ -2,7 +2,7 @@ import script from './CnFieldListWidget.vue2.js';
2
2
  import { render } from './CnFieldListWidget.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-6df666da";
5
+ script.__scopeId = "data-v-91c65ff8";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -74,12 +74,12 @@ var script = {
74
74
  * - `field` (required) — the object field holding the array.
75
75
  * - `key` — the item field that identifies an entry (default: the item itself for strings).
76
76
  * - `row` — `{ title, titleFallback?, avatar?, meta?: [paths|{ path, map?, format? }], pill?: { path, map?, variantMap? }, aside?: { path, format?, prefix?, fallback? }, detail?: { template, when?, copy?: [{ path, label }] } }`. `detail.copy` puts a copy button beside the detail line for each named value of the row (an empty value gets none), such as a DNS record's name and value.
77
- * - `add` — `{ label?, fields: [{ key, label, type?: 'text'|'select', options?, required?, pattern?, patternMessage? }], unique?, defaults? }`.
77
+ * - `add` — `{ label?, fields: [{ key, label, type?: 'text'|'select'|'multiselect'|'checkbox', options?, optionsSource?, required?, pattern?, patternMessage? }], unique?, defaults? }`. A `multiselect` field holds a list of values. `optionsSource` — `{ url, path?, valuePath?, labelPath? }` (default `id` and `name`) — adds options read from an endpoint after the static ones, each value once (tokens `@objectId`, `@object.<field>`), for choices that live in other records such as a case type's statuses.
78
78
  * - `remove` — `{ label? }`; omitted = no remove.
79
79
  * - `rowActions` — `[{ id, label, ariaLabel?, when?, placement?: 'band'|'inline', request: { method?, url, payload? } }]`, or `{ id, label, dialog, props }` to open a modal registered in the app registry with filled props (shown in `readOnly` too, since it writes nothing, and only when every token in `props` fills); tokens `@object.<field>`, `@objectId`, `@row.<field>`, `@index`. In the table variant `placement: 'inline'` draws the action as a button in the row instead of in the "..." menu; `ariaLabel` is a template filled from the row.
80
80
  * - `when` (row actions, `detail`) — `{ field: value }`, every field equal; or per field `{ eq?, neq?, set? }`, where a value `@row.<field>` (or `@<field>`) is another field of the same row: `{ deliveredRef: { set: true, neq: '@originalRef' } }`.
81
81
  * - `rowSource` — `{ url, path?, key }`: live per-row state merged by key.
82
- * - `variant: 'table'` + `columns` — `[{ header, path, map?, format?, strong?, pill?, variantMap? }]`: rows as a table; a per-row "..." menu holds the row actions and remove; `detail` lines become a warning band under the table, with the row actions that have `placement: 'band'`.
82
+ * - `variant: 'table'` + `columns` — `[{ header, path, map?, format?, strong?, pill?, variantMap?, labelsFrom? }]` (a list value reads as its items joined; `labelsFrom` names an add field whose option labels word the values): rows as a table; a per-row "..." menu holds the row actions and remove; `detail` lines become a warning band under the table, with the row actions that have `placement: 'band'`.
83
83
  * - `add.trigger: 'button'`, `add.placement: 'header' | 'title' | 'footer'` — the add form opens from a button; `title` reports the button for the card's title row on the `header` event.
84
84
  * - `readOnly`, `hint`, `emptyText`.
85
85
  * - `row.href` — the path of a link for the row title; only http(s) and root-relative links, an absolute one opens in a new tab.
@@ -140,6 +140,8 @@ var script = {
140
140
  noticeType: 'error',
141
141
  // What the last copy button put on the clipboard, said to a screen reader.
142
142
  copied: '',
143
+ /** Options read through each add field's `optionsSource`, by field key. */
144
+ sourcedOptions: {},
143
145
  }
144
146
  },
145
147
 
@@ -237,9 +239,12 @@ var script = {
237
239
  .map((field) => ({
238
240
  ...field,
239
241
  label: this.tr(field.label || field.key),
240
- options: (Array.isArray(field.options) ? field.options : []).map((option) => (
241
- typeof option === 'object' ? { value: option.value, label: this.tr(option.label || String(option.value)) } : { value: option, label: this.tr(String(option)) }
242
- )),
242
+ options: [
243
+ ...(Array.isArray(field.options) ? field.options : []).map((option) => (
244
+ typeof option === 'object' ? { value: option.value, label: this.tr(option.label || String(option.value)) } : { value: option, label: this.tr(String(option)) }
245
+ )),
246
+ ...(this.sourcedOptions[field.key] || []),
247
+ ],
243
248
  }))
244
249
  },
245
250
 
@@ -361,12 +366,14 @@ var script = {
361
366
  objectData() {
362
367
  this.saved = null;
363
368
  this.loadLive();
369
+ this.loadOptions();
364
370
  },
365
371
  },
366
372
 
367
373
  created() {
368
374
  this.resetDraft();
369
375
  this.loadLive();
376
+ this.loadOptions();
370
377
  },
371
378
 
372
379
  methods: {
@@ -455,12 +462,77 @@ var script = {
455
462
  }
456
463
  return def.format === 'date-long' ? formatBoardDate(date, new Date(date.getFullYear() + 1, 0, 1)) : formatBoardDate(date)
457
464
  }
465
+ if (Array.isArray(raw)) {
466
+ return raw.map((item) => this.wordOf(item, def)).filter((word) => word !== '').join(', ')
467
+ }
468
+ return this.wordOf(raw, def)
469
+ },
470
+
471
+ /**
472
+ * One value in words: through the column's `map`, then the option labels
473
+ * of the add field it names in `labelsFrom`, else the value itself.
474
+ *
475
+ * @param {string|number|boolean|object} raw The value.
476
+ * @param {object} def The column.
477
+ * @return {string}
478
+ */
479
+ wordOf(raw, def) {
458
480
  if (def.map && Object.hasOwn(def.map, String(raw))) {
459
481
  return this.tr(def.map[String(raw)])
460
482
  }
483
+ if (def.labelsFrom) {
484
+ const field = this.addFields.find((candidate) => candidate.key === def.labelsFrom);
485
+ const option = field && field.options.find((candidate) => String(candidate.value) === String(raw));
486
+ if (option) {
487
+ return option.label
488
+ }
489
+ }
461
490
  return typeof raw === 'object' ? '' : String(raw)
462
491
  },
463
492
 
493
+ /**
494
+ * The empty value of an add field: false for a checkbox, a list for a multiselect.
495
+ *
496
+ * @param {object} field The add field.
497
+ * @return {boolean|Array|string}
498
+ */
499
+ emptyValue(field) {
500
+ if (field.type === 'checkbox') {
501
+ return false
502
+ }
503
+ return field.type === 'multiselect' ? [] : ''
504
+ },
505
+
506
+ /**
507
+ * Read the options of every add field that names an `optionsSource`.
508
+ *
509
+ * A source that cannot be read leaves the static options alone.
510
+ *
511
+ * @return {Promise<void>}
512
+ */
513
+ async loadOptions() {
514
+ const fields = this.content.add && Array.isArray(this.content.add.fields) ? this.content.add.fields : [];
515
+ for (const field of fields) {
516
+ const source = field && field.optionsSource;
517
+ if (!source || !source.url || !field.key) {
518
+ continue
519
+ }
520
+ try {
521
+ const { axios } = await this.http();
522
+ const response = await axios.get(prefixUrl(this.resolve(source.url, {})));
523
+ const list = source.path ? readPath(response && response.data, source.path) : response && response.data;
524
+ const options = (Array.isArray(list) ? list : [])
525
+ .map((item) => ({ value: readPath(item, source.valuePath || 'id'), label: String(readPath(item, source.labelPath || 'name') ?? '') }))
526
+ .filter((option, index, all) => option.value !== undefined && option.value !== null && option.value !== ''
527
+ && all.findIndex((other) => String(other.value) === String(option.value)) === index);
528
+ this.sourcedOptions = { ...this.sourcedOptions, [field.key]: options };
529
+ } catch (e) {
530
+ // eslint-disable-next-line no-console
531
+ console.warn('[CnFieldListWidget] optionsSource could not be read:', e?.message || e);
532
+ }
533
+ }
534
+ },
535
+
464
536
  pillOf(entry, spec) {
465
537
  if (!spec || !spec.path) {
466
538
  return null
@@ -632,7 +704,7 @@ var script = {
632
704
  resetDraft() {
633
705
  const draft = {};
634
706
  for (const field of this.addFields) {
635
- const empty = field.type === 'checkbox' ? false : '';
707
+ const empty = this.emptyValue(field);
636
708
  const first = field.type === 'select' && field.options.length > 0 ? field.options[0].value : empty;
637
709
  draft[field.key] = field.default !== undefined ? field.default : first;
638
710
  }
@@ -787,10 +859,10 @@ var script = {
787
859
  const errors = {};
788
860
  for (const field of this.addFields) {
789
861
  const value = this.draft[field.key];
790
- const empty = value === undefined || value === null || String(value).trim() === '';
862
+ const empty = value === undefined || value === null || (Array.isArray(value) ? value.length === 0 : String(value).trim() === '');
791
863
  if (field.required && empty) {
792
864
  errors[field.key] = this.tr('Fill this in.');
793
- } else if (!empty && field.pattern && !new RegExp(field.pattern).test(String(value).trim())) {
865
+ } else if (!empty && field.pattern && !Array.isArray(value) && !new RegExp(field.pattern).test(String(value).trim())) {
794
866
  errors[field.key] = this.tr(field.patternMessage || 'This value is not valid.');
795
867
  }
796
868
  }
@@ -870,7 +942,7 @@ var script = {
870
942
  for (const [index, field] of this.addFields.entries()) {
871
943
  const scalarValue = this.content.add?.scalar === true && index === 0 ? row.item : undefined;
872
944
  const value = row.item && typeof row.item === 'object' ? readPath(row.item, field.key) : scalarValue;
873
- draft[field.key] = value === undefined || value === null ? (field.type === 'checkbox' ? false : '') : value;
945
+ draft[field.key] = value === undefined || value === null ? this.emptyValue(field) : value;
874
946
  }
875
947
  this.draft = draft;
876
948
  this.errors = {};
@@ -903,7 +975,10 @@ var script = {
903
975
  const entry = { ...(add.defaults || {}) };
904
976
  for (const field of this.addFields) {
905
977
  const value = this.draft[field.key];
906
- if (value !== undefined && value !== null && String(value).trim() !== '') {
978
+ if (Array.isArray(value)) {
979
+ // An emptied list is written as empty, so an edit can clear it.
980
+ entry[field.key] = value;
981
+ } else if (value !== undefined && value !== null && String(value).trim() !== '') {
907
982
  entry[field.key] = trimmed(value);
908
983
  }
909
984
  }