@conduction/nextcloud-vue 2.56.0-beta.31 → 2.56.0-beta.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +55 -4
  2. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
  3. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +51 -15
  4. package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
  5. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +13 -2
  6. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  7. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +63 -52
  8. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  9. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js +10 -0
  10. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js.map +1 -0
  11. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js +252 -0
  12. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js.map +1 -0
  13. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js +140 -0
  14. package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js.map +1 -0
  15. package/dist/esm/components/CnChipsFieldWidget/index.js +26 -0
  16. package/dist/esm/components/CnChipsFieldWidget/index.js.map +1 -0
  17. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js +10 -0
  18. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js.map +1 -0
  19. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js +354 -0
  20. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js.map +1 -0
  21. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js +172 -0
  22. package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js.map +1 -0
  23. package/dist/esm/components/CnChoicePickerWidget/index.js +27 -0
  24. package/dist/esm/components/CnChoicePickerWidget/index.js.map +1 -0
  25. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +25 -2
  26. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -1
  28. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  29. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  30. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +3 -2
  31. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  32. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +29 -0
  33. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  34. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +20 -3
  35. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  36. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +7 -1
  37. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  38. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  39. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +77 -3
  40. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +282 -69
  42. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
  43. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +0 -1
  44. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  45. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  46. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +65 -2
  47. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  48. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +6 -2
  49. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  50. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +10 -0
  51. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js.map +1 -0
  52. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +174 -0
  53. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -0
  54. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +75 -0
  55. package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js.map +1 -0
  56. package/dist/esm/components/CnRadioCardsWidget/index.js +28 -0
  57. package/dist/esm/components/CnRadioCardsWidget/index.js.map +1 -0
  58. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +18 -1
  59. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  60. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +34 -25
  61. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  62. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js +10 -0
  63. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js.map +1 -0
  64. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js +222 -0
  65. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js.map +1 -0
  66. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js +64 -0
  67. package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js.map +1 -0
  68. package/dist/esm/components/CnSavedViewsWidget/index.js +30 -0
  69. package/dist/esm/components/CnSavedViewsWidget/index.js.map +1 -0
  70. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
  71. package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
  72. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +10 -0
  73. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js.map +1 -0
  74. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +347 -0
  75. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -0
  76. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +184 -0
  77. package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js.map +1 -0
  78. package/dist/esm/components/CnSettingsFormWidget/index.js +27 -0
  79. package/dist/esm/components/CnSettingsFormWidget/index.js.map +1 -0
  80. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +87 -6
  81. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  82. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  83. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +10 -0
  84. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js.map +1 -0
  85. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +159 -0
  86. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -0
  87. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js +60 -0
  88. package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js.map +1 -0
  89. package/dist/esm/components/CnSwitchRowsWidget/index.js +26 -0
  90. package/dist/esm/components/CnSwitchRowsWidget/index.js.map +1 -0
  91. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +47 -1
  92. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  93. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +16 -14
  94. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  95. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +80 -1
  96. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
  97. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +75 -32
  98. package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
  99. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +10 -0
  100. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js.map +1 -0
  101. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +269 -0
  102. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -0
  103. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js +106 -0
  104. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -0
  105. package/dist/esm/components/CnToggleTableWidget/index.js +27 -0
  106. package/dist/esm/components/CnToggleTableWidget/index.js.map +1 -0
  107. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +7 -0
  108. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  109. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js.map +1 -1
  110. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js +4 -2
  111. package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js.map +1 -1
  112. package/dist/esm/index.js +7 -0
  113. package/dist/esm/index.js.map +1 -1
  114. package/dist/esm/l10n/en.json.js +1 -0
  115. package/dist/esm/l10n/en.json.js.map +1 -1
  116. package/dist/esm/l10n/nl.json.js +1 -0
  117. package/dist/esm/l10n/nl.json.js.map +1 -1
  118. package/dist/esm/nextcloud-vue.css +843 -4
  119. package/dist/esm/utils/contentHeaderLink.js +51 -0
  120. package/dist/esm/utils/contentHeaderLink.js.map +1 -0
  121. package/dist/esm/utils/fetchFilterCounts.js +40 -5
  122. package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
  123. package/dist/esm/utils/initials.js +32 -0
  124. package/dist/esm/utils/initials.js.map +1 -0
  125. package/dist/esm/utils/libraryWidgetKeys.js +7 -0
  126. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  127. package/dist/esm/utils/objectWrite.js +59 -0
  128. package/dist/esm/utils/objectWrite.js.map +1 -0
  129. package/dist/esm/utils/widgetDispatch.js +1 -1
  130. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  131. package/dist/nextcloud-vue.cjs.js +10510 -6830
  132. package/dist/nextcloud-vue.cjs.js.map +2 -2
  133. package/dist/nextcloud-vue.css +843 -4
  134. package/l10n/en.json +1 -0
  135. package/l10n/nl.json +1 -0
  136. package/package.json +1 -1
  137. package/src/components/CnBannerWidget/CnBannerWidget.vue +93 -13
  138. package/src/components/CnCellRenderer/CnCellRenderer.md +2 -0
  139. package/src/components/CnCellRenderer/CnCellRenderer.vue +43 -3
  140. package/src/components/CnChipsFieldWidget/CnChipsFieldWidget.vue +433 -0
  141. package/src/components/CnChipsFieldWidget/index.js +25 -0
  142. package/src/components/CnChoicePickerWidget/CnChoicePickerWidget.vue +556 -0
  143. package/src/components/CnChoicePickerWidget/index.js +26 -0
  144. package/src/components/CnDashboardPage/CnDashboardPage.vue +38 -2
  145. package/src/components/CnDataTable/CnDataTable.vue +2 -1
  146. package/src/components/CnDetailPage/CnDetailPage.vue +45 -2
  147. package/src/components/CnFactsWidget/CnFactsWidget.vue +18 -3
  148. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +265 -4
  149. package/src/components/CnIndexPage/CnIndexPage.vue +0 -1
  150. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +69 -2
  151. package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +313 -0
  152. package/src/components/CnRadioCardsWidget/index.js +27 -0
  153. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +43 -1
  154. package/src/components/CnSavedViewsWidget/CnSavedViewsWidget.vue +296 -0
  155. package/src/components/CnSavedViewsWidget/index.js +29 -0
  156. package/src/components/CnSegmentedControl/CnSegmentedControl.vue +13 -0
  157. package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +555 -0
  158. package/src/components/CnSettingsFormWidget/index.js +26 -0
  159. package/src/components/CnStatWidget/CnStatWidget.vue +87 -6
  160. package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +226 -0
  161. package/src/components/CnSwitchRowsWidget/index.js +25 -0
  162. package/src/components/CnTabsWidget/CnTabsWidget.vue +82 -3
  163. package/src/components/CnTasksWidget/CnTasksWidget.vue +175 -15
  164. package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +386 -0
  165. package/src/components/CnToggleTableWidget/index.js +26 -0
  166. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +7 -0
  167. package/src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue +28 -1
  168. package/src/components/index.js +7 -0
  169. package/src/css/look-board-detail.css +36 -2
  170. package/src/css/look-board-index.css +23 -0
  171. package/src/css/look-board.css +72 -0
  172. package/src/index.js +7 -0
  173. package/src/utils/contentHeaderLink.js +48 -0
  174. package/src/utils/fetchFilterCounts.js +39 -4
  175. package/src/utils/initials.js +29 -0
  176. package/src/utils/libraryWidgetKeys.js +7 -0
  177. package/src/utils/objectWrite.js +55 -0
  178. package/src/utils/widgetDispatch.js +1 -1
@@ -1,4 +1,4 @@
1
- import { resolveComponent, openBlock, createElementBlock, toDisplayString, Fragment, renderList, createElementVNode, createCommentVNode, createBlock, withCtx, createTextVNode, withModifiers, createVNode } from 'vue';
1
+ import { resolveComponent, openBlock, createElementBlock, createVNode, withCtx, createTextVNode, toDisplayString, createCommentVNode, withModifiers, Fragment, renderList, createBlock, createElementVNode } from 'vue';
2
2
 
3
3
  const _hoisted_1 = {
4
4
  class: "cn-field-list-widget",
@@ -6,84 +6,237 @@ const _hoisted_1 = {
6
6
  };
7
7
  const _hoisted_2 = {
8
8
  key: 0,
9
+ class: "cn-field-list-widget__toolbar"
10
+ };
11
+ const _hoisted_3 = ["data-testid"];
12
+ const _hoisted_4 = {
13
+ key: 2,
9
14
  class: "cn-field-list-widget__empty",
10
15
  "data-testid": "cn-field-list-empty"
11
16
  };
12
- const _hoisted_3 = {
13
- key: 1,
14
- class: "cn-field-list-widget__rows"
17
+ const _hoisted_5 = {
18
+ key: 3,
19
+ class: "cn-field-list-widget__table-wrap"
15
20
  };
16
- const _hoisted_4 = ["data-testid"];
17
- const _hoisted_5 = { class: "cn-field-list-widget__line" };
18
21
  const _hoisted_6 = {
22
+ class: "cn-field-list-widget__table",
23
+ "data-testid": "cn-field-list-table"
24
+ };
25
+ const _hoisted_7 = {
26
+ key: 0,
27
+ scope: "col",
28
+ class: "cn-field-list-widget__th cn-field-list-widget__th--menu"
29
+ };
30
+ const _hoisted_8 = { class: "cn-field-list-widget__sr" };
31
+ const _hoisted_9 = ["data-testid"];
32
+ const _hoisted_10 = { key: 1 };
33
+ const _hoisted_11 = {
34
+ key: 0,
35
+ class: "cn-field-list-widget__td cn-field-list-widget__td--menu"
36
+ };
37
+ const _hoisted_12 = ["data-testid"];
38
+ const _hoisted_13 = { class: "cn-field-list-widget__band-text" };
39
+ const _hoisted_14 = {
40
+ key: 4,
41
+ class: "cn-field-list-widget__rows"
42
+ };
43
+ const _hoisted_15 = ["data-testid"];
44
+ const _hoisted_16 = { class: "cn-field-list-widget__line" };
45
+ const _hoisted_17 = {
19
46
  key: 0,
20
47
  class: "cn-field-list-widget__avatar",
21
48
  "aria-hidden": "true"
22
49
  };
23
- const _hoisted_7 = { class: "cn-field-list-widget__main" };
24
- const _hoisted_8 = { class: "cn-field-list-widget__title" };
25
- const _hoisted_9 = {
50
+ const _hoisted_18 = { class: "cn-field-list-widget__main" };
51
+ const _hoisted_19 = { class: "cn-field-list-widget__title" };
52
+ const _hoisted_20 = {
26
53
  key: 0,
27
54
  class: "cn-field-list-widget__meta"
28
55
  };
29
- const _hoisted_10 = {
56
+ const _hoisted_21 = {
30
57
  key: 2,
31
58
  class: "cn-field-list-widget__aside"
32
59
  };
33
- const _hoisted_11 = {
60
+ const _hoisted_22 = {
34
61
  key: 0,
35
62
  class: "cn-field-list-widget__detail"
36
63
  };
37
- const _hoisted_12 = {
38
- key: 2,
64
+ const _hoisted_23 = {
65
+ key: 5,
39
66
  class: "cn-field-list-widget__hint"
40
67
  };
41
- const _hoisted_13 = ["data-testid"];
68
+ const _hoisted_24 = {
69
+ key: 6,
70
+ class: "cn-field-list-widget__toolbar"
71
+ };
72
+ const _hoisted_25 = ["data-testid"];
42
73
 
43
74
  function render(_ctx, _cache, $props, $setup, $data, $options) {
44
- const _component_CnStatusBadge = resolveComponent("CnStatusBadge");
45
75
  const _component_NcButton = resolveComponent("NcButton");
46
76
  const _component_NcSelect = resolveComponent("NcSelect");
47
77
  const _component_NcTextField = resolveComponent("NcTextField");
78
+ const _component_CnStatusBadge = resolveComponent("CnStatusBadge");
79
+ const _component_NcActionButton = resolveComponent("NcActionButton");
80
+ const _component_NcActions = resolveComponent("NcActions");
48
81
  const _component_NcNoteCard = resolveComponent("NcNoteCard");
49
82
 
50
83
  return (openBlock(), createElementBlock("div", _hoisted_1, [
51
- ($options.rows.length === 0)
52
- ? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString($options.emptyLabel), 1 /* TEXT */))
53
- : (openBlock(), createElementBlock("ul", _hoisted_3, [
54
- (openBlock(true), createElementBlock(Fragment, null, renderList($options.rows, (row) => {
55
- return (openBlock(), createElementBlock("li", {
56
- key: row.key,
57
- class: "cn-field-list-widget__row",
58
- "data-testid": `cn-field-list-row-${row.key}`
84
+ ($options.canAdd && $options.addTrigger && $options.addPlacement === 'header')
85
+ ? (openBlock(), createElementBlock("div", _hoisted_2, [
86
+ createVNode(_component_NcButton, {
87
+ variant: "secondary",
88
+ disabled: $data.busy !== '',
89
+ "data-testid": "cn-field-list-open-add",
90
+ onClick: _cache[0] || (_cache[0] = $event => ($data.adding = !$data.adding))
91
+ }, {
92
+ default: withCtx(() => [
93
+ createTextVNode(" + " + toDisplayString($options.addLabel), 1 /* TEXT */)
94
+ ]),
95
+ _: 1 /* STABLE */
96
+ }, 8 /* PROPS */, ["disabled"])
97
+ ]))
98
+ : createCommentVNode("v-if", true),
99
+ ($options.canAdd && $options.addTrigger && $options.addPlacement === 'header' && $data.adding)
100
+ ? (openBlock(), createElementBlock("form", {
101
+ key: 1,
102
+ class: "cn-field-list-widget__add",
103
+ "data-testid": "cn-field-list-add",
104
+ onSubmit: _cache[1] || (_cache[1] = withModifiers((...args) => ($options.add && $options.add(...args)), ["prevent"]))
105
+ }, [
106
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.addFields, (field) => {
107
+ return (openBlock(), createElementBlock("div", {
108
+ key: field.key,
109
+ class: "cn-field-list-widget__field",
110
+ "data-testid": `cn-field-list-input-${field.key}`
59
111
  }, [
60
- createElementVNode("div", _hoisted_5, [
61
- (row.initials)
62
- ? (openBlock(), createElementBlock("span", _hoisted_6, toDisplayString(row.initials), 1 /* TEXT */))
63
- : createCommentVNode("v-if", true),
64
- createElementVNode("span", _hoisted_7, [
65
- createElementVNode("span", _hoisted_8, toDisplayString(row.title), 1 /* TEXT */),
66
- (row.meta)
67
- ? (openBlock(), createElementBlock("span", _hoisted_9, toDisplayString(row.meta), 1 /* TEXT */))
112
+ (field.type === 'select')
113
+ ? (openBlock(), createBlock(_component_NcSelect, {
114
+ key: 0,
115
+ modelValue: $data.draft[field.key],
116
+ "onUpdate:modelValue": $event => (($data.draft[field.key]) = $event),
117
+ inputLabel: field.label,
118
+ options: field.options,
119
+ reduce: (option) => option.value,
120
+ clearable: false,
121
+ label: "label"
122
+ }, null, 8 /* PROPS */, ["modelValue", "onUpdate:modelValue", "inputLabel", "options", "reduce"]))
123
+ : (openBlock(), createBlock(_component_NcTextField, {
124
+ key: 1,
125
+ modelValue: $data.draft[field.key],
126
+ "onUpdate:modelValue": $event => (($data.draft[field.key]) = $event),
127
+ label: field.label,
128
+ error: Boolean($data.errors[field.key]),
129
+ helperText: $data.errors[field.key] || ''
130
+ }, null, 8 /* PROPS */, ["modelValue", "onUpdate:modelValue", "label", "error", "helperText"]))
131
+ ], 8 /* PROPS */, _hoisted_3))
132
+ }), 128 /* KEYED_FRAGMENT */)),
133
+ createVNode(_component_NcButton, {
134
+ type: "submit",
135
+ variant: "primary",
136
+ disabled: $data.busy !== '',
137
+ "data-testid": "cn-field-list-submit"
138
+ }, {
139
+ default: withCtx(() => [
140
+ createTextVNode(toDisplayString($options.addLabel), 1 /* TEXT */)
141
+ ]),
142
+ _: 1 /* STABLE */
143
+ }, 8 /* PROPS */, ["disabled"])
144
+ ], 32 /* NEED_HYDRATION */))
145
+ : createCommentVNode("v-if", true),
146
+ ($options.rows.length === 0)
147
+ ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString($options.emptyLabel), 1 /* TEXT */))
148
+ : ($options.isTable)
149
+ ? (openBlock(), createElementBlock("div", _hoisted_5, [
150
+ createElementVNode("table", _hoisted_6, [
151
+ createElementVNode("thead", null, [
152
+ createElementVNode("tr", null, [
153
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.tableColumns, (column) => {
154
+ return (openBlock(), createElementBlock("th", {
155
+ key: column.key,
156
+ scope: "col",
157
+ class: "cn-field-list-widget__th"
158
+ }, toDisplayString(column.header), 1 /* TEXT */))
159
+ }), 128 /* KEYED_FRAGMENT */)),
160
+ ($options.hasMenu)
161
+ ? (openBlock(), createElementBlock("th", _hoisted_7, [
162
+ createElementVNode("span", _hoisted_8, toDisplayString($options.tr('Actions')), 1 /* TEXT */)
163
+ ]))
68
164
  : createCommentVNode("v-if", true)
69
- ]),
70
- (row.pill)
71
- ? (openBlock(), createBlock(_component_CnStatusBadge, {
72
- key: 1,
73
- label: row.pill.label,
74
- variant: row.pill.variant,
75
- size: "small"
76
- }, null, 8 /* PROPS */, ["label", "variant"]))
77
- : createCommentVNode("v-if", true),
78
- (row.aside)
79
- ? (openBlock(), createElementBlock("span", _hoisted_10, toDisplayString(row.aside), 1 /* TEXT */))
80
- : createCommentVNode("v-if", true),
81
- (openBlock(true), createElementBlock(Fragment, null, renderList(row.actions, (action) => {
165
+ ])
166
+ ]),
167
+ createElementVNode("tbody", null, [
168
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.rows, (row) => {
169
+ return (openBlock(), createElementBlock("tr", {
170
+ key: row.key,
171
+ class: "cn-field-list-widget__tr",
172
+ "data-testid": `cn-field-list-row-${row.key}`
173
+ }, [
174
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.tableColumns, (column, index) => {
175
+ return (openBlock(), createElementBlock("td", {
176
+ key: column.key,
177
+ class: "cn-field-list-widget__td"
178
+ }, [
179
+ (column.pill && row.cells[index].pill)
180
+ ? (openBlock(), createBlock(_component_CnStatusBadge, {
181
+ key: 0,
182
+ label: row.cells[index].pill.label,
183
+ variant: row.cells[index].pill.variant,
184
+ size: "small"
185
+ }, null, 8 /* PROPS */, ["label", "variant"]))
186
+ : (column.strong)
187
+ ? (openBlock(), createElementBlock("strong", _hoisted_10, toDisplayString(row.cells[index].text), 1 /* TEXT */))
188
+ : (openBlock(), createElementBlock(Fragment, { key: 2 }, [
189
+ createTextVNode(toDisplayString(row.cells[index].text), 1 /* TEXT */)
190
+ ], 64 /* STABLE_FRAGMENT */))
191
+ ]))
192
+ }), 128 /* KEYED_FRAGMENT */)),
193
+ ($options.hasMenu)
194
+ ? (openBlock(), createElementBlock("td", _hoisted_11, [
195
+ ($options.menuItems(row).length > 0)
196
+ ? (openBlock(), createBlock(_component_NcActions, {
197
+ key: 0,
198
+ forceMenu: true,
199
+ disabled: $data.busy !== '',
200
+ ariaLabel: `${$options.tr('More actions')}: ${row.title}`,
201
+ "data-testid": `cn-field-list-menu-${row.key}`
202
+ }, {
203
+ default: withCtx(() => [
204
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.menuItems(row), (item) => {
205
+ return (openBlock(), createBlock(_component_NcActionButton, {
206
+ key: item.id,
207
+ "data-testid": `cn-field-list-menu-${item.id}-${row.key}`,
208
+ onClick: item.run
209
+ }, {
210
+ default: withCtx(() => [
211
+ createTextVNode(toDisplayString(item.label), 1 /* TEXT */)
212
+ ]),
213
+ _: 2 /* DYNAMIC */
214
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["data-testid", "onClick"]))
215
+ }), 128 /* KEYED_FRAGMENT */))
216
+ ]),
217
+ _: 2 /* DYNAMIC */
218
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "ariaLabel", "data-testid"]))
219
+ : createCommentVNode("v-if", true)
220
+ ]))
221
+ : createCommentVNode("v-if", true)
222
+ ], 8 /* PROPS */, _hoisted_9))
223
+ }), 128 /* KEYED_FRAGMENT */))
224
+ ])
225
+ ]),
226
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.bandRows, (row) => {
227
+ return (openBlock(), createElementBlock("div", {
228
+ key: row.key,
229
+ class: "cn-field-list-widget__band",
230
+ role: "note",
231
+ "data-testid": `cn-field-list-band-${row.key}`
232
+ }, [
233
+ createElementVNode("span", _hoisted_13, toDisplayString(row.detail), 1 /* TEXT */),
234
+ (openBlock(true), createElementBlock(Fragment, null, renderList(row.bandActions, (action) => {
82
235
  return (openBlock(), createBlock(_component_NcButton, {
83
236
  key: action.id,
84
- variant: "tertiary",
237
+ variant: "secondary",
85
238
  disabled: $data.busy !== '',
86
- "data-testid": `cn-field-list-action-${action.id}-${row.key}`,
239
+ "data-testid": `cn-field-list-band-action-${action.id}-${row.key}`,
87
240
  onClick: $event => ($options.runAction(action, row))
88
241
  }, {
89
242
  default: withCtx(() => [
@@ -91,38 +244,98 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
91
244
  ]),
92
245
  _: 2 /* DYNAMIC */
93
246
  }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "data-testid", "onClick"]))
94
- }), 128 /* KEYED_FRAGMENT */)),
95
- ($options.canRemove)
96
- ? (openBlock(), createBlock(_component_NcButton, {
97
- key: 3,
247
+ }), 128 /* KEYED_FRAGMENT */))
248
+ ], 8 /* PROPS */, _hoisted_12))
249
+ }), 128 /* KEYED_FRAGMENT */))
250
+ ]))
251
+ : (openBlock(), createElementBlock("ul", _hoisted_14, [
252
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.rows, (row) => {
253
+ return (openBlock(), createElementBlock("li", {
254
+ key: row.key,
255
+ class: "cn-field-list-widget__row",
256
+ "data-testid": `cn-field-list-row-${row.key}`
257
+ }, [
258
+ createElementVNode("div", _hoisted_16, [
259
+ (row.initials)
260
+ ? (openBlock(), createElementBlock("span", _hoisted_17, toDisplayString(row.initials), 1 /* TEXT */))
261
+ : createCommentVNode("v-if", true),
262
+ createElementVNode("span", _hoisted_18, [
263
+ createElementVNode("span", _hoisted_19, toDisplayString(row.title), 1 /* TEXT */),
264
+ (row.meta)
265
+ ? (openBlock(), createElementBlock("span", _hoisted_20, toDisplayString(row.meta), 1 /* TEXT */))
266
+ : createCommentVNode("v-if", true)
267
+ ]),
268
+ (row.pill)
269
+ ? (openBlock(), createBlock(_component_CnStatusBadge, {
270
+ key: 1,
271
+ label: row.pill.label,
272
+ variant: row.pill.variant,
273
+ size: "small"
274
+ }, null, 8 /* PROPS */, ["label", "variant"]))
275
+ : createCommentVNode("v-if", true),
276
+ (row.aside)
277
+ ? (openBlock(), createElementBlock("span", _hoisted_21, toDisplayString(row.aside), 1 /* TEXT */))
278
+ : createCommentVNode("v-if", true),
279
+ (openBlock(true), createElementBlock(Fragment, null, renderList(row.actions, (action) => {
280
+ return (openBlock(), createBlock(_component_NcButton, {
281
+ key: action.id,
98
282
  variant: "tertiary",
99
283
  disabled: $data.busy !== '',
100
- "aria-label": $options.removeAriaLabel(row),
101
- "data-testid": `cn-field-list-remove-${row.key}`,
102
- onClick: $event => ($options.remove(row))
284
+ "data-testid": `cn-field-list-action-${action.id}-${row.key}`,
285
+ onClick: $event => ($options.runAction(action, row))
103
286
  }, {
104
287
  default: withCtx(() => [
105
- createTextVNode(toDisplayString($options.removeLabel), 1 /* TEXT */)
288
+ createTextVNode(toDisplayString(action.label), 1 /* TEXT */)
106
289
  ]),
107
- _: 1 /* STABLE */
108
- }, 8 /* PROPS */, ["disabled", "aria-label", "data-testid", "onClick"]))
290
+ _: 2 /* DYNAMIC */
291
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "data-testid", "onClick"]))
292
+ }), 128 /* KEYED_FRAGMENT */)),
293
+ ($options.canRemove)
294
+ ? (openBlock(), createBlock(_component_NcButton, {
295
+ key: 3,
296
+ variant: "tertiary",
297
+ disabled: $data.busy !== '',
298
+ "aria-label": $options.removeAriaLabel(row),
299
+ "data-testid": `cn-field-list-remove-${row.key}`,
300
+ onClick: $event => ($options.remove(row))
301
+ }, {
302
+ default: withCtx(() => [
303
+ createTextVNode(toDisplayString($options.removeLabel), 1 /* TEXT */)
304
+ ]),
305
+ _: 1 /* STABLE */
306
+ }, 8 /* PROPS */, ["disabled", "aria-label", "data-testid", "onClick"]))
307
+ : createCommentVNode("v-if", true)
308
+ ]),
309
+ (row.detail)
310
+ ? (openBlock(), createElementBlock("p", _hoisted_22, toDisplayString(row.detail), 1 /* TEXT */))
109
311
  : createCommentVNode("v-if", true)
110
- ]),
111
- (row.detail)
112
- ? (openBlock(), createElementBlock("p", _hoisted_11, toDisplayString(row.detail), 1 /* TEXT */))
113
- : createCommentVNode("v-if", true)
114
- ], 8 /* PROPS */, _hoisted_4))
115
- }), 128 /* KEYED_FRAGMENT */))
116
- ])),
312
+ ], 8 /* PROPS */, _hoisted_15))
313
+ }), 128 /* KEYED_FRAGMENT */))
314
+ ])),
117
315
  ($options.hint)
118
- ? (openBlock(), createElementBlock("p", _hoisted_12, toDisplayString($options.hint), 1 /* TEXT */))
316
+ ? (openBlock(), createElementBlock("p", _hoisted_23, toDisplayString($options.hint), 1 /* TEXT */))
317
+ : createCommentVNode("v-if", true),
318
+ ($options.canAdd && $options.addTrigger && $options.addPlacement !== 'header' && !$data.adding)
319
+ ? (openBlock(), createElementBlock("div", _hoisted_24, [
320
+ createVNode(_component_NcButton, {
321
+ variant: "secondary",
322
+ disabled: $data.busy !== '',
323
+ "data-testid": "cn-field-list-open-add",
324
+ onClick: _cache[2] || (_cache[2] = $event => ($data.adding = true))
325
+ }, {
326
+ default: withCtx(() => [
327
+ createTextVNode(" + " + toDisplayString($options.addLabel), 1 /* TEXT */)
328
+ ]),
329
+ _: 1 /* STABLE */
330
+ }, 8 /* PROPS */, ["disabled"])
331
+ ]))
119
332
  : createCommentVNode("v-if", true),
120
- ($options.canAdd)
333
+ ($options.canAdd && !($options.addTrigger && $options.addPlacement === 'header') && (!$options.addTrigger || $data.adding))
121
334
  ? (openBlock(), createElementBlock("form", {
122
- key: 3,
335
+ key: 7,
123
336
  class: "cn-field-list-widget__add",
124
337
  "data-testid": "cn-field-list-add",
125
- onSubmit: _cache[0] || (_cache[0] = withModifiers((...args) => ($options.add && $options.add(...args)), ["prevent"]))
338
+ onSubmit: _cache[3] || (_cache[3] = withModifiers((...args) => ($options.add && $options.add(...args)), ["prevent"]))
126
339
  }, [
127
340
  (openBlock(true), createElementBlock(Fragment, null, renderList($options.addFields, (field) => {
128
341
  return (openBlock(), createElementBlock("div", {
@@ -149,7 +362,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
149
362
  error: Boolean($data.errors[field.key]),
150
363
  helperText: $data.errors[field.key] || ''
151
364
  }, null, 8 /* PROPS */, ["modelValue", "onUpdate:modelValue", "label", "error", "helperText"]))
152
- ], 8 /* PROPS */, _hoisted_13))
365
+ ], 8 /* PROPS */, _hoisted_25))
153
366
  }), 128 /* KEYED_FRAGMENT */)),
154
367
  createVNode(_component_NcButton, {
155
368
  type: "submit",
@@ -166,7 +379,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
166
379
  : createCommentVNode("v-if", true),
167
380
  ($data.notice)
168
381
  ? (openBlock(), createBlock(_component_NcNoteCard, {
169
- key: 4,
382
+ key: 8,
170
383
  type: $data.noticeType,
171
384
  "data-testid": "cn-field-list-notice"
172
385
  }, {
@@ -1 +1 @@
1
- {"version":3,"file":"CnFieldListWidget.vue3.js","sources":["../../../../src/components/CnFieldListWidget/CnFieldListWidget.vue?vue&type=template&id=0f29a833&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-field-list-widget\" data-testid=\"cn-field-list-widget\">\n\t\t<p v-if=\"rows.length === 0\" class=\"cn-field-list-widget__empty\" data-testid=\"cn-field-list-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<ul v-else class=\"cn-field-list-widget__rows\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-field-list-widget__row\"\n\t\t\t\t:data-testid=\"`cn-field-list-row-${row.key}`\">\n\t\t\t\t<div class=\"cn-field-list-widget__line\">\n\t\t\t\t\t<span v-if=\"row.initials\" class=\"cn-field-list-widget__avatar\" aria-hidden=\"true\">{{ row.initials }}</span>\n\t\t\t\t\t<span class=\"cn-field-list-widget__main\">\n\t\t\t\t\t\t<span class=\"cn-field-list-widget__title\">{{ row.title }}</span>\n\t\t\t\t\t\t<span v-if=\"row.meta\" class=\"cn-field-list-widget__meta\">{{ row.meta }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\tv-if=\"row.pill\"\n\t\t\t\t\t\t:label=\"row.pill.label\"\n\t\t\t\t\t\t:variant=\"row.pill.variant\"\n\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t<span v-if=\"row.aside\" class=\"cn-field-list-widget__aside\">{{ row.aside }}</span>\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-for=\"action in row.actions\"\n\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\t\t\t:data-testid=\"`cn-field-list-action-${action.id}-${row.key}`\"\n\t\t\t\t\t\t@click=\"runAction(action, row)\">\n\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"canRemove\"\n\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\t\t\t:aria-label=\"removeAriaLabel(row)\"\n\t\t\t\t\t\t:data-testid=\"`cn-field-list-remove-${row.key}`\"\n\t\t\t\t\t\t@click=\"remove(row)\">\n\t\t\t\t\t\t{{ removeLabel }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"row.detail\" class=\"cn-field-list-widget__detail\">\n\t\t\t\t\t{{ row.detail }}\n\t\t\t\t</p>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<p v-if=\"hint\" class=\"cn-field-list-widget__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\n\t\t<form\n\t\t\tv-if=\"canAdd\"\n\t\t\tclass=\"cn-field-list-widget__add\"\n\t\t\tdata-testid=\"cn-field-list-add\"\n\t\t\t@submit.prevent=\"add\">\n\t\t\t<div\n\t\t\t\tv-for=\"field in addFields\"\n\t\t\t\t:key=\"field.key\"\n\t\t\t\tclass=\"cn-field-list-widget__field\"\n\t\t\t\t:data-testid=\"`cn-field-list-input-${field.key}`\">\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-if=\"field.type === 'select'\"\n\t\t\t\t\tv-model=\"draft[field.key]\"\n\t\t\t\t\t:inputLabel=\"field.label\"\n\t\t\t\t\t:options=\"field.options\"\n\t\t\t\t\t:reduce=\"(option) => option.value\"\n\t\t\t\t\t:clearable=\"false\"\n\t\t\t\t\tlabel=\"label\" />\n\t\t\t\t<NcTextField\n\t\t\t\t\tv-else\n\t\t\t\t\tv-model=\"draft[field.key]\"\n\t\t\t\t\t:label=\"field.label\"\n\t\t\t\t\t:error=\"Boolean(errors[field.key])\"\n\t\t\t\t\t:helperText=\"errors[field.key] || ''\" />\n\t\t\t</div>\n\t\t\t<NcButton type=\"submit\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\tdata-testid=\"cn-field-list-submit\">\n\t\t\t\t{{ addLabel }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<NcNoteCard v-if=\"notice\" :type=\"noticeType\" data-testid=\"cn-field-list-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcButton, NcNoteCard, NcSelect, NcTextField } from '@nextcloud/vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { formatBoardDate } from '../../utils/boardDate.js'\nimport { parseDateValue } from '../../utils/dateVariant.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnFieldListWidget — the `field-list` widget: a list stored INSIDE one field\n * of the current object (a portal's `domains[]`, its `editors[]`), shown as\n * rows and edited in place.\n *\n * Rows are drawn from configuration (title, meta line, pill, aside, a detail\n * line); a small form adds an entry, a button removes one, and each change is\n * saved as ONE PATCH of that field on the object, after re-reading the stored\n * value so a concurrent change to the same list is not overwritten with a\n * stale copy. Optional row actions call a configured endpoint (a \"check\n * again\"), and an optional `rowSource` merges live per-row state read from an\n * endpoint by key without writing it back.\n *\n * The server decides who may write: a refused PATCH shows the server's words\n * and leaves the list as stored.\n *\n * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md\n */\nexport default {\n\tname: 'CnFieldListWidget',\n\n\tcomponents: { CnStatusBadge, NcButton, NcNoteCard, NcSelect, NcTextField },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `field` (required) — the object field holding the array.\n\t\t * - `key` — the item field that identifies an entry (default: the item itself for strings).\n\t\t * - `row` — `{ title, titleFallback?, avatar?, meta?: [paths|{ path, map?, format? }], pill?: { path, map?, variantMap? }, aside?: { path, format?, prefix?, fallback? }, detail?: { template, when? } }`.\n\t\t * - `add` — `{ label?, fields: [{ key, label, type?: 'text'|'select', options?, required?, pattern?, patternMessage? }], unique?, defaults? }`.\n\t\t * - `remove` — `{ label? }`; omitted = no remove.\n\t\t * - `rowActions` — `[{ id, label, when?, request: { method?, url, payload? } }]`; tokens `@object.<field>`, `@objectId`, `@row.<field>`.\n\t\t * - `rowSource` — `{ url, path?, key }`: live per-row state merged by key.\n\t\t * - `readOnly`, `hint`, `emptyText`.\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\treturn {\n\t\t\t/** The list as last saved by this widget; null = read it off objectData. */\n\t\t\tsaved: null,\n\t\t\t/** Live per-row state from `rowSource`, by key. */\n\t\t\tlive: {},\n\t\t\tdraft: {},\n\t\t\terrors: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t\tnoticeType: 'error',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The stored list.\n\t\t *\n\t\t * @return {Array}\n\t\t */\n\t\titems() {\n\t\t\tconst list = this.saved !== null ? this.saved : readPath(this.objectData || {}, this.content.field)\n\t\t\treturn Array.isArray(list) ? list : []\n\t\t},\n\n\t\t/**\n\t\t * The rows to draw.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md#requirement-a-field-list-draws-the-entries-of-one-object-field\n\t\t */\n\t\trows() {\n\t\t\tconst spec = this.content.row || {}\n\t\t\treturn this.items.map((item, index) => {\n\t\t\t\tconst key = this.keyOf(item, index)\n\t\t\t\tconst entry = item && typeof item === 'object'\n\t\t\t\t\t? { ...item, ...(this.live[key] || {}) }\n\t\t\t\t\t: { value: item, ...(this.live[key] || {}) }\n\t\t\t\tconst title = this.text(entry, spec.title) || this.text(entry, spec.titleFallback) || (typeof item === 'string' ? item : key)\n\t\t\t\tconst meta = (Array.isArray(spec.meta) ? spec.meta : [])\n\t\t\t\t\t.map((part) => this.text(entry, part))\n\t\t\t\t\t.filter((part) => part !== '')\n\t\t\t\t\t.join(' · ')\n\t\t\t\treturn {\n\t\t\t\t\tkey,\n\t\t\t\t\titem,\n\t\t\t\t\tentry,\n\t\t\t\t\ttitle,\n\t\t\t\t\tinitials: spec.avatar ? this.initials(title) : '',\n\t\t\t\t\tmeta,\n\t\t\t\t\tpill: this.pillOf(entry, spec.pill),\n\t\t\t\t\taside: spec.aside ? this.asideOf(entry, spec.aside) : '',\n\t\t\t\t\tdetail: spec.detail && this.matches(entry, spec.detail.when) ? this.fill(spec.detail.template, entry) : '',\n\t\t\t\t\tactions: this.actionsFor(entry),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** Whether the list is read-only. */\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\t/** Whether entries can be added. */\n\t\tcanAdd() {\n\t\t\treturn !this.readOnly && this.addFields.length > 0 && Boolean(this.content.field)\n\t\t},\n\n\t\t/** Whether entries can be removed. */\n\t\tcanRemove() {\n\t\t\treturn !this.readOnly && Boolean(this.content.remove) && Boolean(this.content.field)\n\t\t},\n\n\t\t/**\n\t\t * The add form's fields, labels translated, select options translated.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\taddFields() {\n\t\t\tconst fields = this.content.add && Array.isArray(this.content.add.fields) ? this.content.add.fields : []\n\t\t\treturn fields\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\tlabel: this.tr(field.label || field.key),\n\t\t\t\t\toptions: (Array.isArray(field.options) ? field.options : []).map((option) => (\n\t\t\t\t\t\ttypeof option === 'object' ? { value: option.value, label: this.tr(option.label || String(option.value)) } : { value: option, label: this.tr(String(option)) }\n\t\t\t\t\t)),\n\t\t\t\t}))\n\t\t},\n\n\t\taddLabel() {\n\t\t\treturn this.tr((this.content.add && this.content.add.label) || 'Add')\n\t\t},\n\n\t\tremoveLabel() {\n\t\t\treturn this.tr((this.content.remove && this.content.remove.label) || 'Remove')\n\t\t},\n\n\t\thint() {\n\t\t\treturn this.tr(this.content.hint || '')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn this.tr(this.content.emptyText || 'Nothing listed yet')\n\t\t},\n\n\t\t/** The object URL the list is saved to, or '' when it is not known. */\n\t\tobjectUrl() {\n\t\t\tconst id = this.objectId || (this.objectData && this.objectData.id)\n\t\t\tif (!this.register || !this.schema || !id || typeof this.register !== 'string' || typeof this.schema !== 'string') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `/apps/openregister/api/objects/${encodeURIComponent(this.register)}/${encodeURIComponent(this.schema)}/${encodeURIComponent(String(id))}`\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.saved = null\n\t\t\tthis.loadLive()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.resetDraft()\n\t\tthis.loadLive()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The identity of an entry.\n\t\t *\n\t\t * @param {unknown} item The entry.\n\t\t * @param {number} index Its position.\n\t\t * @return {string}\n\t\t */\n\t\tkeyOf(item, index) {\n\t\t\tif (item === null || typeof item !== 'object') {\n\t\t\t\treturn String(item)\n\t\t\t}\n\t\t\tconst key = this.content.key ? readPath(item, this.content.key) : undefined\n\t\t\treturn key === undefined || key === null || key === '' ? `item-${index}` : String(key)\n\t\t},\n\n\t\t/**\n\t\t * A display text off an entry: a path, or `{ path, map?, format? }`.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {string|object} spec The spec.\n\t\t * @return {string}\n\t\t */\n\t\ttext(entry, spec) {\n\t\t\tif (!spec) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst def = typeof spec === 'string' ? { path: spec } : spec\n\t\t\tconst raw = readPath(entry, def.path)\n\t\t\tif (raw === null || raw === undefined || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (def.format === 'date' || def.format === 'date-long') {\n\t\t\t\tconst date = parseDateValue(raw)\n\t\t\t\tif (date === null) {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn def.format === 'date-long' ? formatBoardDate(date, new Date(date.getFullYear() + 1, 0, 1)) : formatBoardDate(date)\n\t\t\t}\n\t\t\tif (def.map && Object.hasOwn(def.map, String(raw))) {\n\t\t\t\treturn this.tr(def.map[String(raw)])\n\t\t\t}\n\t\t\treturn typeof raw === 'object' ? '' : String(raw)\n\t\t},\n\n\t\tpillOf(entry, spec) {\n\t\t\tif (!spec || !spec.path) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = readPath(entry, spec.path)\n\t\t\tif (raw === null || raw === undefined || raw === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst label = this.text(entry, spec)\n\t\t\tconst variant = spec.variantMap && spec.variantMap[String(raw)]\n\t\t\treturn { label, variant: isBadgeVariant(variant) ? variant : 'default' }\n\t\t},\n\n\t\tasideOf(entry, spec) {\n\t\t\tconst value = this.text(entry, spec)\n\t\t\tif (value === '') {\n\t\t\t\t// No value: the optional `fallback` label, translated, instead of an empty aside.\n\t\t\t\treturn this.tr(spec.fallback)\n\t\t\t}\n\t\t\treturn spec.prefix ? `${this.tr(spec.prefix)} ${value}` : value\n\t\t},\n\n\t\t/**\n\t\t * Whether an entry matches a `{ field: value }` condition (every field equal).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {object|undefined} when The condition.\n\t\t * @return {boolean}\n\t\t */\n\t\tmatches(entry, when) {\n\t\t\tif (!when || typeof when !== 'object') {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn Object.entries(when).every(([field, expected]) => {\n\t\t\t\tconst actual = readPath(entry, field)\n\t\t\t\tif (expected === false) {\n\t\t\t\t\treturn actual === false || actual === undefined || actual === null || actual === ''\n\t\t\t\t}\n\t\t\t\treturn String(actual) === String(expected)\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Fill `{path}` placeholders from an entry; '' when one stays empty.\n\t\t *\n\t\t * @param {string} template The template, translated first.\n\t\t * @param {object} entry The entry.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template, entry) {\n\t\t\tif (typeof template !== 'string') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet missing = false\n\t\t\tconst out = this.tr(template).replace(/\\{([\\w.@]+)\\}/g, (match, path) => {\n\t\t\t\tconst value = readPath(entry, path)\n\t\t\t\tif (value === undefined || value === null || value === '') {\n\t\t\t\t\tmissing = true\n\t\t\t\t\treturn match\n\t\t\t\t}\n\t\t\t\treturn String(value)\n\t\t\t})\n\t\t\treturn missing ? '' : out\n\t\t},\n\n\t\tactionsFor(entry) {\n\t\t\tif (this.readOnly) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst actions = Array.isArray(this.content.rowActions) ? this.content.rowActions : []\n\t\t\treturn actions\n\t\t\t\t.filter((action) => action && action.id && action.request && action.request.url && this.matches(entry, action.when))\n\t\t\t\t.map((action) => ({ ...action, label: this.tr(action.label || action.id) }))\n\t\t},\n\n\t\tinitials(name) {\n\t\t\treturn String(name || '').split(/[\\s@._-]+/).filter(Boolean).slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join('')\n\t\t},\n\n\t\tremoveAriaLabel(row) {\n\t\t\treturn `${this.removeLabel}: ${row.title}`\n\t\t},\n\n\t\tresetDraft() {\n\t\t\tconst draft = {}\n\t\t\tfor (const field of this.addFields) {\n\t\t\t\tconst first = field.type === 'select' && field.options.length > 0 ? field.options[0].value : ''\n\t\t\t\tdraft[field.key] = field.default !== undefined ? field.default : first\n\t\t\t}\n\t\t\tthis.draft = draft\n\t\t\tthis.errors = {}\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId`, `@object.<field>` and `@row.<field>` inside a string or a payload.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @param {object} entry The row entry.\n\t\t * @return {unknown}\n\t\t */\n\t\tresolve(value, entry) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.map((v) => this.resolve(v, entry))\n\t\t\t}\n\t\t\tif (value && typeof value === 'object') {\n\t\t\t\treturn Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.resolve(v, entry)]))\n\t\t\t}\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tconst object = this.objectData || {}\n\t\t\tconst read = (source, path) => {\n\t\t\t\tconst v = readPath(source || {}, path)\n\t\t\t\treturn v === undefined || v === null ? '' : v\n\t\t\t}\n\t\t\tconst whole = value.match(/^@(row|object)\\.([\\w.@]+)$/)\n\t\t\tif (whole) {\n\t\t\t\treturn read(whole[1] === 'row' ? entry : object, whole[2])\n\t\t\t}\n\t\t\treturn value\n\t\t\t\t.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))\n\t\t\t\t.replace(/@(row|object)\\.([\\w.@]+)/g, (m, scope, path) => encodeURIComponent(String(read(scope === 'row' ? entry : object, path))))\n\t\t},\n\n\t\tasync http() {\n\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\treturn { axios }\n\t\t},\n\n\t\t/**\n\t\t * Read live per-row state from `rowSource` and keep it by key.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadLive() {\n\t\t\tconst source = this.content.rowSource\n\t\t\tif (!source || !source.url || !source.key || !this.objectData) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { axios } = await this.http()\n\t\t\t\tconst response = await axios.get(prefixUrl(this.resolve(source.url, {})))\n\t\t\t\tconst data = response && response.data\n\t\t\t\tconst list = source.path ? readPath(data, source.path) : data\n\t\t\t\tconst live = {}\n\t\t\t\tfor (const item of Array.isArray(list) ? list : []) {\n\t\t\t\t\tconst key = item && readPath(item, source.key)\n\t\t\t\t\tif (key !== undefined && key !== null) {\n\t\t\t\t\t\tlive[String(key)] = item\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.live = live\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnFieldListWidget] rowSource could not be read:', e?.message || e)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Save a new list: re-read the stored value, apply the change to it, and\n\t\t * PATCH that one field.\n\t\t *\n\t\t * @param {(stored: Array) => Array} change Builds the next list from the stored one, or throws an Error with a `userMessage`.\n\t\t * @param {string} busyKey What is busy.\n\t\t * @return {Promise<boolean>} Whether it saved.\n\t\t * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md#requirement-a-field-list-saves-one-field-with-one-patch\n\t\t */\n\t\tasync save(change, busyKey) {\n\t\t\tif (!this.objectUrl) {\n\t\t\t\tthis.notify(this.tr('This list cannot be saved here.'))\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tthis.busy = busyKey\n\t\t\tthis.notice = ''\n\t\t\ttry {\n\t\t\t\tconst { axios } = await this.http()\n\t\t\t\tconst { data: stored } = await axios.get(prefixUrl(this.objectUrl))\n\t\t\t\tconst current = readPath(stored || {}, this.content.field)\n\t\t\t\tconst next = change(Array.isArray(current) ? current : [])\n\t\t\t\tconst { data } = await axios.patch(prefixUrl(this.objectUrl), { [this.content.field]: next })\n\t\t\t\tconst written = readPath(data || {}, this.content.field)\n\t\t\t\tthis.saved = Array.isArray(written) ? written : next\n\t\t\t\t/**\n\t\t\t\t * @event saved The list was saved: one PATCH of the field succeeded.\n\t\t\t\t * @type {{field: string, value: Array}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field: this.content.field, value: this.saved })\n\t\t\t\treturn true\n\t\t\t} catch (e) {\n\t\t\t\tthis.notify(e && e.userMessage ? e.userMessage : serverErrorMessage(e))\n\t\t\t\treturn false\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\n\t\tnotify(message, type = 'error') {\n\t\t\tthis.notice = message\n\t\t\tthis.noticeType = type\n\t\t},\n\n\t\t/**\n\t\t * Validate the draft and add it.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md#requirement-a-field-list-adds-and-removes-entries\n\t\t */\n\t\tasync add() {\n\t\t\tconst errors = {}\n\t\t\tfor (const field of this.addFields) {\n\t\t\t\tconst value = this.draft[field.key]\n\t\t\t\tconst empty = value === undefined || value === null || String(value).trim() === ''\n\t\t\t\tif (field.required && empty) {\n\t\t\t\t\terrors[field.key] = this.tr('Fill this in.')\n\t\t\t\t} else if (!empty && field.pattern && !new RegExp(field.pattern).test(String(value).trim())) {\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\tthis.errors = errors\n\t\t\tif (Object.keys(errors).length > 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst entry = { ...((this.content.add && this.content.add.defaults) || {}) }\n\t\t\tfor (const field of this.addFields) {\n\t\t\t\tconst value = this.draft[field.key]\n\t\t\t\tif (value !== undefined && value !== null && String(value).trim() !== '') {\n\t\t\t\t\tentry[field.key] = typeof value === 'string' ? value.trim() : value\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst unique = this.content.add && this.content.add.unique\n\t\t\tconst saved = await this.save((stored) => {\n\t\t\t\tif (unique && stored.some((item) => item && String(readPath(item, unique)) === String(entry[unique]))) {\n\t\t\t\t\tconst error = new Error('duplicate')\n\t\t\t\t\terror.userMessage = this.tr('This is already in the list.')\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\treturn [...stored, entry]\n\t\t\t}, '*')\n\t\t\tif (saved) {\n\t\t\t\tthis.resetDraft()\n\t\t\t\tthis.loadLive()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Remove an entry by its key.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync remove(row) {\n\t\t\tawait this.save((stored) => stored.filter((item, index) => this.keyOf(item, index) !== row.key), row.key)\n\t\t},\n\n\t\t/**\n\t\t * Run a row action's request, then re-read the live state.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} row The row.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md#requirement-a-field-list-row-can-run-a-configured-request\n\t\t */\n\t\tasync runAction(action, row) {\n\t\t\tthis.busy = row.key\n\t\t\tthis.notice = ''\n\t\t\ttry {\n\t\t\t\tconst { axios } = await this.http()\n\t\t\t\tconst method = String(action.request.method || 'POST').toLowerCase()\n\t\t\t\tconst payload = this.resolve(action.request.payload || {}, row.entry)\n\t\t\t\tconst response = method === 'get'\n\t\t\t\t\t? await axios.get(prefixUrl(this.resolve(action.request.url, row.entry)))\n\t\t\t\t\t: await axios[method](prefixUrl(this.resolve(action.request.url, row.entry)), payload)\n\t\t\t\tconst message = response && response.data && typeof response.data.message === 'string' ? response.data.message : ''\n\t\t\t\tif (message) {\n\t\t\t\t\tthis.notify(message, 'info')\n\t\t\t\t}\n\t\t\t\tawait this.loadLive()\n\t\t\t} catch (e) {\n\t\t\t\tthis.notify(serverErrorMessage(e))\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-field-list-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmin-width: 0;\n}\n\n.cn-field-list-widget__rows {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-field-list-widget__row {\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-field-list-widget__row:first-child {\n\tborder-top: none;\n\tpadding-top: 0;\n}\n\n.cn-field-list-widget__line {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tmin-width: 0;\n}\n\n.cn-field-list-widget__avatar {\n\tflex: 0 0 auto;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 50%;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text, var(--color-main-text));\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-field-list-widget__main {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-field-list-widget__title {\n\tfont-weight: 600;\n\toverflow-wrap: anywhere;\n}\n\n.cn-field-list-widget__meta,\n.cn-field-list-widget__aside,\n.cn-field-list-widget__detail,\n.cn-field-list-widget__hint,\n.cn-field-list-widget__empty {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-field-list-widget__meta,\n.cn-field-list-widget__aside,\n.cn-field-list-widget__detail {\n\tfont-size: 13px;\n}\n\n.cn-field-list-widget__aside {\n\twhite-space: nowrap;\n}\n\n.cn-field-list-widget__detail,\n.cn-field-list-widget__hint,\n.cn-field-list-widget__empty {\n\tmargin: 4px 0 0;\n\toverflow-wrap: anywhere;\n}\n\n.cn-field-list-widget__add {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-end;\n\tgap: 8px 12px;\n}\n\n.cn-field-list-widget__add > * {\n\tflex: 1 1 180px;\n}\n\n.cn-field-list-widget__add > button {\n\tflex: 0 0 auto;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_toDisplayString","_Fragment","_renderList","_createElementVNode","_createBlock","_createTextVNode","_createVNode"],"mappings":"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"}
1
+ {"version":3,"file":"CnFieldListWidget.vue3.js","sources":["../../../../src/components/CnFieldListWidget/CnFieldListWidget.vue?vue&type=template&id=0f29a833&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-field-list-widget\" data-testid=\"cn-field-list-widget\">\n\t\t<div v-if=\"canAdd && addTrigger && addPlacement === 'header'\" class=\"cn-field-list-widget__toolbar\">\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\tdata-testid=\"cn-field-list-open-add\"\n\t\t\t\t@click=\"adding = !adding\">\n\t\t\t\t+ {{ addLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<form\n\t\t\tv-if=\"canAdd && addTrigger && addPlacement === 'header' && adding\"\n\t\t\tclass=\"cn-field-list-widget__add\"\n\t\t\tdata-testid=\"cn-field-list-add\"\n\t\t\t@submit.prevent=\"add\">\n\t\t\t<div\n\t\t\t\tv-for=\"field in addFields\"\n\t\t\t\t:key=\"field.key\"\n\t\t\t\tclass=\"cn-field-list-widget__field\"\n\t\t\t\t:data-testid=\"`cn-field-list-input-${field.key}`\">\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-if=\"field.type === 'select'\"\n\t\t\t\t\tv-model=\"draft[field.key]\"\n\t\t\t\t\t:inputLabel=\"field.label\"\n\t\t\t\t\t:options=\"field.options\"\n\t\t\t\t\t:reduce=\"(option) => option.value\"\n\t\t\t\t\t:clearable=\"false\"\n\t\t\t\t\tlabel=\"label\" />\n\t\t\t\t<NcTextField\n\t\t\t\t\tv-else\n\t\t\t\t\tv-model=\"draft[field.key]\"\n\t\t\t\t\t:label=\"field.label\"\n\t\t\t\t\t:error=\"Boolean(errors[field.key])\"\n\t\t\t\t\t:helperText=\"errors[field.key] || ''\" />\n\t\t\t</div>\n\t\t\t<NcButton type=\"submit\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\tdata-testid=\"cn-field-list-submit\">\n\t\t\t\t{{ addLabel }}\n\t\t\t</NcButton>\n\t\t</form>\n\t\t<p v-if=\"rows.length === 0\" class=\"cn-field-list-widget__empty\" data-testid=\"cn-field-list-empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<div v-else-if=\"isTable\" class=\"cn-field-list-widget__table-wrap\">\n\t\t\t<table class=\"cn-field-list-widget__table\" data-testid=\"cn-field-list-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th\n\t\t\t\t\t\t\tv-for=\"column in tableColumns\"\n\t\t\t\t\t\t\t:key=\"column.key\"\n\t\t\t\t\t\t\tscope=\"col\"\n\t\t\t\t\t\t\tclass=\"cn-field-list-widget__th\">\n\t\t\t\t\t\t\t{{ column.header }}\n\t\t\t\t\t\t</th>\n\t\t\t\t\t\t<th v-if=\"hasMenu\" scope=\"col\" class=\"cn-field-list-widget__th cn-field-list-widget__th--menu\">\n\t\t\t\t\t\t\t<span class=\"cn-field-list-widget__sr\">{{ tr('Actions') }}</span>\n\t\t\t\t\t\t</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr\n\t\t\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t\t\t:key=\"row.key\"\n\t\t\t\t\t\tclass=\"cn-field-list-widget__tr\"\n\t\t\t\t\t\t:data-testid=\"`cn-field-list-row-${row.key}`\">\n\t\t\t\t\t\t<td\n\t\t\t\t\t\t\tv-for=\"(column, index) in tableColumns\"\n\t\t\t\t\t\t\t:key=\"column.key\"\n\t\t\t\t\t\t\tclass=\"cn-field-list-widget__td\">\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-if=\"column.pill && row.cells[index].pill\"\n\t\t\t\t\t\t\t\t:label=\"row.cells[index].pill.label\"\n\t\t\t\t\t\t\t\t:variant=\"row.cells[index].pill.variant\"\n\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t\t<strong v-else-if=\"column.strong\">{{ row.cells[index].text }}</strong>\n\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t{{ row.cells[index].text }}\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td v-if=\"hasMenu\" class=\"cn-field-list-widget__td cn-field-list-widget__td--menu\">\n\t\t\t\t\t\t\t<NcActions\n\t\t\t\t\t\t\t\tv-if=\"menuItems(row).length > 0\"\n\t\t\t\t\t\t\t\t:forceMenu=\"true\"\n\t\t\t\t\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\t\t\t\t\t:ariaLabel=\"`${tr('More actions')}: ${row.title}`\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-field-list-menu-${row.key}`\">\n\t\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\t\tv-for=\"item in menuItems(row)\"\n\t\t\t\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\t\t\t\t:data-testid=\"`cn-field-list-menu-${item.id}-${row.key}`\"\n\t\t\t\t\t\t\t\t\t@click=\"item.run\">\n\t\t\t\t\t\t\t\t\t{{ item.label }}\n\t\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t</NcActions>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t\t<div\n\t\t\t\tv-for=\"row in bandRows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-field-list-widget__band\"\n\t\t\t\trole=\"note\"\n\t\t\t\t:data-testid=\"`cn-field-list-band-${row.key}`\">\n\t\t\t\t<span class=\"cn-field-list-widget__band-text\">{{ row.detail }}</span>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-for=\"action in row.bandActions\"\n\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\t\t:data-testid=\"`cn-field-list-band-action-${action.id}-${row.key}`\"\n\t\t\t\t\t@click=\"runAction(action, row)\">\n\t\t\t\t\t{{ action.label }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<ul v-else class=\"cn-field-list-widget__rows\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-field-list-widget__row\"\n\t\t\t\t:data-testid=\"`cn-field-list-row-${row.key}`\">\n\t\t\t\t<div class=\"cn-field-list-widget__line\">\n\t\t\t\t\t<span v-if=\"row.initials\" class=\"cn-field-list-widget__avatar\" aria-hidden=\"true\">{{ row.initials }}</span>\n\t\t\t\t\t<span class=\"cn-field-list-widget__main\">\n\t\t\t\t\t\t<span class=\"cn-field-list-widget__title\">{{ row.title }}</span>\n\t\t\t\t\t\t<span v-if=\"row.meta\" class=\"cn-field-list-widget__meta\">{{ row.meta }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\tv-if=\"row.pill\"\n\t\t\t\t\t\t:label=\"row.pill.label\"\n\t\t\t\t\t\t:variant=\"row.pill.variant\"\n\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t<span v-if=\"row.aside\" class=\"cn-field-list-widget__aside\">{{ row.aside }}</span>\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-for=\"action in row.actions\"\n\t\t\t\t\t\t:key=\"action.id\"\n\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\t\t\t:data-testid=\"`cn-field-list-action-${action.id}-${row.key}`\"\n\t\t\t\t\t\t@click=\"runAction(action, row)\">\n\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"canRemove\"\n\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\t\t\t:aria-label=\"removeAriaLabel(row)\"\n\t\t\t\t\t\t:data-testid=\"`cn-field-list-remove-${row.key}`\"\n\t\t\t\t\t\t@click=\"remove(row)\">\n\t\t\t\t\t\t{{ removeLabel }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"row.detail\" class=\"cn-field-list-widget__detail\">\n\t\t\t\t\t{{ row.detail }}\n\t\t\t\t</p>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<p v-if=\"hint\" class=\"cn-field-list-widget__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\n\t\t<div v-if=\"canAdd && addTrigger && addPlacement !== 'header' && !adding\" class=\"cn-field-list-widget__toolbar\">\n\t\t\t<NcButton\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\tdata-testid=\"cn-field-list-open-add\"\n\t\t\t\t@click=\"adding = true\">\n\t\t\t\t+ {{ addLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<form\n\t\t\tv-if=\"canAdd && !(addTrigger && addPlacement === 'header') && (!addTrigger || adding)\"\n\t\t\tclass=\"cn-field-list-widget__add\"\n\t\t\tdata-testid=\"cn-field-list-add\"\n\t\t\t@submit.prevent=\"add\">\n\t\t\t<div\n\t\t\t\tv-for=\"field in addFields\"\n\t\t\t\t:key=\"field.key\"\n\t\t\t\tclass=\"cn-field-list-widget__field\"\n\t\t\t\t:data-testid=\"`cn-field-list-input-${field.key}`\">\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-if=\"field.type === 'select'\"\n\t\t\t\t\tv-model=\"draft[field.key]\"\n\t\t\t\t\t:inputLabel=\"field.label\"\n\t\t\t\t\t:options=\"field.options\"\n\t\t\t\t\t:reduce=\"(option) => option.value\"\n\t\t\t\t\t:clearable=\"false\"\n\t\t\t\t\tlabel=\"label\" />\n\t\t\t\t<NcTextField\n\t\t\t\t\tv-else\n\t\t\t\t\tv-model=\"draft[field.key]\"\n\t\t\t\t\t:label=\"field.label\"\n\t\t\t\t\t:error=\"Boolean(errors[field.key])\"\n\t\t\t\t\t:helperText=\"errors[field.key] || ''\" />\n\t\t\t</div>\n\t\t\t<NcButton type=\"submit\"\n\t\t\t\tvariant=\"secondary\"\n\t\t\t\t:disabled=\"busy !== ''\"\n\t\t\t\tdata-testid=\"cn-field-list-submit\">\n\t\t\t\t{{ addLabel }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<NcNoteCard v-if=\"notice\" :type=\"noticeType\" data-testid=\"cn-field-list-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcActionButton, NcActions, NcButton, NcNoteCard, NcSelect, NcTextField } from '@nextcloud/vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport { isBadgeVariant } from '../../utils/badgeVariants.js'\nimport { formatBoardDate } from '../../utils/boardDate.js'\nimport { parseDateValue } from '../../utils/dateVariant.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnFieldListWidget — the `field-list` widget: a list stored INSIDE one field\n * of the current object (a portal's `domains[]`, its `editors[]`), shown as\n * rows and edited in place.\n *\n * Rows are drawn from configuration (title, meta line, pill, aside, a detail\n * line); a small form adds an entry, a button removes one, and each change is\n * saved as ONE PATCH of that field on the object, after re-reading the stored\n * value so a concurrent change to the same list is not overwritten with a\n * stale copy. Optional row actions call a configured endpoint (a \"check\n * again\"), and an optional `rowSource` merges live per-row state read from an\n * endpoint by key without writing it back.\n *\n * The server decides who may write: a refused PATCH shows the server's words\n * and leaves the list as stored.\n *\n * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md\n */\nexport default {\n\tname: 'CnFieldListWidget',\n\n\tcomponents: { CnStatusBadge, NcActionButton, NcActions, NcButton, NcNoteCard, NcSelect, NcTextField },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `field` (required) — the object field holding the array.\n\t\t * - `key` — the item field that identifies an entry (default: the item itself for strings).\n\t\t * - `row` — `{ title, titleFallback?, avatar?, meta?: [paths|{ path, map?, format? }], pill?: { path, map?, variantMap? }, aside?: { path, format?, prefix?, fallback? }, detail?: { template, when? } }`.\n\t\t * - `add` — `{ label?, fields: [{ key, label, type?: 'text'|'select', options?, required?, pattern?, patternMessage? }], unique?, defaults? }`.\n\t\t * - `remove` — `{ label? }`; omitted = no remove.\n\t\t * - `rowActions` — `[{ id, label, when?, placement?: 'band', request: { method?, url, payload? } }]`; tokens `@object.<field>`, `@objectId`, `@row.<field>`.\n\t\t * - `rowSource` — `{ url, path?, key }`: live per-row state merged by key.\n\t\t * - `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'`.\n\t\t * - `add.trigger: 'button'`, `add.placement: 'header' | 'footer'` — the add form opens from a button.\n\t\t * - `readOnly`, `hint`, `emptyText`.\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\treturn {\n\t\t\t/** The list as last saved by this widget; null = read it off objectData. */\n\t\t\tsaved: null,\n\t\t\t/** Live per-row state from `rowSource`, by key. */\n\t\t\tlive: {},\n\t\t\tdraft: {},\n\t\t\t/** Whether the add form is open (only with `add.trigger: 'button'`). */\n\t\t\tadding: false,\n\t\t\terrors: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t\tnoticeType: 'error',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The stored list.\n\t\t *\n\t\t * @return {Array}\n\t\t */\n\t\titems() {\n\t\t\tconst list = this.saved !== null ? this.saved : readPath(this.objectData || {}, this.content.field)\n\t\t\treturn Array.isArray(list) ? list : []\n\t\t},\n\n\t\t/**\n\t\t * The rows to draw.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md#requirement-a-field-list-draws-the-entries-of-one-object-field\n\t\t */\n\t\trows() {\n\t\t\tconst spec = this.content.row || {}\n\t\t\treturn this.items.map((item, index) => {\n\t\t\t\tconst key = this.keyOf(item, index)\n\t\t\t\tconst entry = item && typeof item === 'object'\n\t\t\t\t\t? { ...item, ...(this.live[key] || {}) }\n\t\t\t\t\t: { value: item, ...(this.live[key] || {}) }\n\t\t\t\tconst title = this.text(entry, spec.title) || this.text(entry, spec.titleFallback) || (typeof item === 'string' ? item : key)\n\t\t\t\tconst meta = (Array.isArray(spec.meta) ? spec.meta : [])\n\t\t\t\t\t.map((part) => this.text(entry, part))\n\t\t\t\t\t.filter((part) => part !== '')\n\t\t\t\t\t.join(' · ')\n\t\t\t\treturn {\n\t\t\t\t\tkey,\n\t\t\t\t\titem,\n\t\t\t\t\tentry,\n\t\t\t\t\ttitle,\n\t\t\t\t\tinitials: spec.avatar ? this.initials(title) : '',\n\t\t\t\t\tmeta,\n\t\t\t\t\tpill: this.pillOf(entry, spec.pill),\n\t\t\t\t\taside: spec.aside ? this.asideOf(entry, spec.aside) : '',\n\t\t\t\t\tdetail: spec.detail && this.matches(entry, spec.detail.when) ? this.fill(spec.detail.template, entry) : '',\n\t\t\t\t\tactions: this.actionsFor(entry),\n\t\t\t\t\tcells: this.isTable ? this.cellsOf(entry) : [],\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** Whether the list is read-only. */\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\t/** Whether entries can be added. */\n\t\tcanAdd() {\n\t\t\treturn !this.readOnly && this.addFields.length > 0 && Boolean(this.content.field)\n\t\t},\n\n\t\t/** Whether entries can be removed. */\n\t\tcanRemove() {\n\t\t\treturn !this.readOnly && Boolean(this.content.remove) && Boolean(this.content.field)\n\t\t},\n\n\t\t/**\n\t\t * The add form's fields, labels translated, select options translated.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\taddFields() {\n\t\t\tconst fields = this.content.add && Array.isArray(this.content.add.fields) ? this.content.add.fields : []\n\t\t\treturn fields\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\tlabel: this.tr(field.label || field.key),\n\t\t\t\t\toptions: (Array.isArray(field.options) ? field.options : []).map((option) => (\n\t\t\t\t\t\ttypeof option === 'object' ? { value: option.value, label: this.tr(option.label || String(option.value)) } : { value: option, label: this.tr(String(option)) }\n\t\t\t\t\t)),\n\t\t\t\t}))\n\t\t},\n\n\t\t/** Whether the rows are drawn as a table (`variant: 'table'`). */\n\t\tisTable() {\n\t\t\treturn this.content.variant === 'table' && this.tableColumns.length > 0\n\t\t},\n\n\t\t/**\n\t\t * The table columns, headers translated.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\ttableColumns() {\n\t\t\treturn (Array.isArray(this.content.columns) ? this.content.columns : [])\n\t\t\t\t.filter((column) => column && column.path)\n\t\t\t\t.map((column, index) => ({ ...column, key: `${column.path}-${index}`, header: this.tr(column.header || '') }))\n\t\t},\n\n\t\t/** Whether each row has a \"more actions\" menu (row actions not placed in the band, and remove). */\n\t\thasMenu() {\n\t\t\treturn this.isTable && !this.readOnly && (this.canRemove || this.rows.some((row) => this.menuItems(row).length > 0))\n\t\t},\n\n\t\t/** Rows with a detail line: in the table variant it is a warning band under the table. */\n\t\tbandRows() {\n\t\t\treturn this.rows\n\t\t\t\t.filter((row) => row.detail !== '')\n\t\t\t\t.map((row) => ({ ...row, bandActions: row.actions.filter((action) => action.placement === 'band') }))\n\t\t},\n\n\t\t/** Whether the add form opens from a button (`add.trigger: 'button'`). */\n\t\taddTrigger() {\n\t\t\treturn Boolean(this.content.add && this.content.add.trigger === 'button')\n\t\t},\n\n\t\t/** Where the add button sits: `header` (above the rows) or `footer` (default). */\n\t\taddPlacement() {\n\t\t\treturn this.content.add && this.content.add.placement === 'header' ? 'header' : 'footer'\n\t\t},\n\n\t\taddLabel() {\n\t\t\treturn this.tr((this.content.add && this.content.add.label) || 'Add')\n\t\t},\n\n\t\tremoveLabel() {\n\t\t\treturn this.tr((this.content.remove && this.content.remove.label) || 'Remove')\n\t\t},\n\n\t\thint() {\n\t\t\treturn this.tr(this.content.hint || '')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn this.tr(this.content.emptyText || 'Nothing listed yet')\n\t\t},\n\n\t\t/** The object URL the list is saved to, or '' when it is not known. */\n\t\tobjectUrl() {\n\t\t\tconst id = this.objectId || (this.objectData && this.objectData.id)\n\t\t\tif (!this.register || !this.schema || !id || typeof this.register !== 'string' || typeof this.schema !== 'string') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn `/apps/openregister/api/objects/${encodeURIComponent(this.register)}/${encodeURIComponent(this.schema)}/${encodeURIComponent(String(id))}`\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.saved = null\n\t\t\tthis.loadLive()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.resetDraft()\n\t\tthis.loadLive()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The cells of one table row, one per column.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @return {Array<{text: string, pill: object|null}>}\n\t\t */\n\t\tcellsOf(entry) {\n\t\t\treturn this.tableColumns.map((column) => ({\n\t\t\t\ttext: this.text(entry, column),\n\t\t\t\tpill: column.pill ? this.pillOf(entry, column) : null,\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The items of a row's menu in the table variant: the row actions not\n\t\t * placed in the band, then remove.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Array<{id: string, label: string, run: Function}>}\n\t\t */\n\t\tmenuItems(row) {\n\t\t\tconst items = row.actions\n\t\t\t\t.filter((action) => action.placement !== 'band')\n\t\t\t\t.map((action) => ({ id: action.id, label: action.label, run: () => this.runAction(action, row) }))\n\t\t\tif (this.canRemove) {\n\t\t\t\titems.push({ id: 'remove', label: this.removeLabel, run: () => this.remove(row) })\n\t\t\t}\n\t\t\treturn items\n\t\t},\n\n\t\t/**\n\t\t * The identity of an entry.\n\t\t *\n\t\t * @param {unknown} item The entry.\n\t\t * @param {number} index Its position.\n\t\t * @return {string}\n\t\t */\n\t\tkeyOf(item, index) {\n\t\t\tif (item === null || typeof item !== 'object') {\n\t\t\t\treturn String(item)\n\t\t\t}\n\t\t\tconst key = this.content.key ? readPath(item, this.content.key) : undefined\n\t\t\treturn key === undefined || key === null || key === '' ? `item-${index}` : String(key)\n\t\t},\n\n\t\t/**\n\t\t * A display text off an entry: a path, or `{ path, map?, format? }`.\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {string|object} spec The spec.\n\t\t * @return {string}\n\t\t */\n\t\ttext(entry, spec) {\n\t\t\tif (!spec) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst def = typeof spec === 'string' ? { path: spec } : spec\n\t\t\tconst raw = readPath(entry, def.path)\n\t\t\tif (raw === null || raw === undefined || raw === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (def.format === 'date' || def.format === 'date-long') {\n\t\t\t\tconst date = parseDateValue(raw)\n\t\t\t\tif (date === null) {\n\t\t\t\t\treturn ''\n\t\t\t\t}\n\t\t\t\treturn def.format === 'date-long' ? formatBoardDate(date, new Date(date.getFullYear() + 1, 0, 1)) : formatBoardDate(date)\n\t\t\t}\n\t\t\tif (def.map && Object.hasOwn(def.map, String(raw))) {\n\t\t\t\treturn this.tr(def.map[String(raw)])\n\t\t\t}\n\t\t\treturn typeof raw === 'object' ? '' : String(raw)\n\t\t},\n\n\t\tpillOf(entry, spec) {\n\t\t\tif (!spec || !spec.path) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst raw = readPath(entry, spec.path)\n\t\t\tif (raw === null || raw === undefined || raw === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst label = this.text(entry, spec)\n\t\t\tconst variant = spec.variantMap && spec.variantMap[String(raw)]\n\t\t\treturn { label, variant: isBadgeVariant(variant) ? variant : 'default' }\n\t\t},\n\n\t\tasideOf(entry, spec) {\n\t\t\tconst value = this.text(entry, spec)\n\t\t\tif (value === '') {\n\t\t\t\t// No value: the optional `fallback` label, translated, instead of an empty aside.\n\t\t\t\treturn this.tr(spec.fallback)\n\t\t\t}\n\t\t\treturn spec.prefix ? `${this.tr(spec.prefix)} ${value}` : value\n\t\t},\n\n\t\t/**\n\t\t * Whether an entry matches a `{ field: value }` condition (every field equal).\n\t\t *\n\t\t * @param {object} entry The entry.\n\t\t * @param {object|undefined} when The condition.\n\t\t * @return {boolean}\n\t\t */\n\t\tmatches(entry, when) {\n\t\t\tif (!when || typeof when !== 'object') {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn Object.entries(when).every(([field, expected]) => {\n\t\t\t\tconst actual = readPath(entry, field)\n\t\t\t\tif (expected === false) {\n\t\t\t\t\treturn actual === false || actual === undefined || actual === null || actual === ''\n\t\t\t\t}\n\t\t\t\treturn String(actual) === String(expected)\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Fill `{path}` placeholders from an entry; '' when one stays empty.\n\t\t *\n\t\t * @param {string} template The template, translated first.\n\t\t * @param {object} entry The entry.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template, entry) {\n\t\t\tif (typeof template !== 'string') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tlet missing = false\n\t\t\tconst out = this.tr(template).replace(/\\{([\\w.@]+)\\}/g, (match, path) => {\n\t\t\t\tconst value = readPath(entry, path)\n\t\t\t\tif (value === undefined || value === null || value === '') {\n\t\t\t\t\tmissing = true\n\t\t\t\t\treturn match\n\t\t\t\t}\n\t\t\t\treturn String(value)\n\t\t\t})\n\t\t\treturn missing ? '' : out\n\t\t},\n\n\t\tactionsFor(entry) {\n\t\t\tif (this.readOnly) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst actions = Array.isArray(this.content.rowActions) ? this.content.rowActions : []\n\t\t\treturn actions\n\t\t\t\t.filter((action) => action && action.id && action.request && action.request.url && this.matches(entry, action.when))\n\t\t\t\t.map((action) => ({ ...action, label: this.tr(action.label || action.id) }))\n\t\t},\n\n\t\tinitials(name) {\n\t\t\treturn String(name || '').split(/[\\s@._-]+/).filter(Boolean).slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join('')\n\t\t},\n\n\t\tremoveAriaLabel(row) {\n\t\t\treturn `${this.removeLabel}: ${row.title}`\n\t\t},\n\n\t\tresetDraft() {\n\t\t\tconst draft = {}\n\t\t\tfor (const field of this.addFields) {\n\t\t\t\tconst first = field.type === 'select' && field.options.length > 0 ? field.options[0].value : ''\n\t\t\t\tdraft[field.key] = field.default !== undefined ? field.default : first\n\t\t\t}\n\t\t\tthis.draft = draft\n\t\t\tthis.errors = {}\n\t\t},\n\n\t\t/**\n\t\t * Resolve `@objectId`, `@object.<field>` and `@row.<field>` inside a string or a payload.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @param {object} entry The row entry.\n\t\t * @return {unknown}\n\t\t */\n\t\tresolve(value, entry) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.map((v) => this.resolve(v, entry))\n\t\t\t}\n\t\t\tif (value && typeof value === 'object') {\n\t\t\t\treturn Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.resolve(v, entry)]))\n\t\t\t}\n\t\t\tif (typeof value !== 'string') {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\tconst object = this.objectData || {}\n\t\t\tconst read = (source, path) => {\n\t\t\t\tconst v = readPath(source || {}, path)\n\t\t\t\treturn v === undefined || v === null ? '' : v\n\t\t\t}\n\t\t\tconst whole = value.match(/^@(row|object)\\.([\\w.@]+)$/)\n\t\t\tif (whole) {\n\t\t\t\treturn read(whole[1] === 'row' ? entry : object, whole[2])\n\t\t\t}\n\t\t\treturn value\n\t\t\t\t.replace(/@objectId/g, () => encodeURIComponent(String(this.objectId || object.id || '')))\n\t\t\t\t.replace(/@(row|object)\\.([\\w.@]+)/g, (m, scope, path) => encodeURIComponent(String(read(scope === 'row' ? entry : object, path))))\n\t\t},\n\n\t\tasync http() {\n\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\treturn { axios }\n\t\t},\n\n\t\t/**\n\t\t * Read live per-row state from `rowSource` and keep it by key.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadLive() {\n\t\t\tconst source = this.content.rowSource\n\t\t\tif (!source || !source.url || !source.key || !this.objectData) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst { axios } = await this.http()\n\t\t\t\tconst response = await axios.get(prefixUrl(this.resolve(source.url, {})))\n\t\t\t\tconst data = response && response.data\n\t\t\t\tconst list = source.path ? readPath(data, source.path) : data\n\t\t\t\tconst live = {}\n\t\t\t\tfor (const item of Array.isArray(list) ? list : []) {\n\t\t\t\t\tconst key = item && readPath(item, source.key)\n\t\t\t\t\tif (key !== undefined && key !== null) {\n\t\t\t\t\t\tlive[String(key)] = item\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.live = live\n\t\t\t} catch (e) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn('[CnFieldListWidget] rowSource could not be read:', e?.message || e)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Save a new list: re-read the stored value, apply the change to it, and\n\t\t * PATCH that one field.\n\t\t *\n\t\t * @param {(stored: Array) => Array} change Builds the next list from the stored one, or throws an Error with a `userMessage`.\n\t\t * @param {string} busyKey What is busy.\n\t\t * @return {Promise<boolean>} Whether it saved.\n\t\t * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md#requirement-a-field-list-saves-one-field-with-one-patch\n\t\t */\n\t\tasync save(change, busyKey) {\n\t\t\tif (!this.objectUrl) {\n\t\t\t\tthis.notify(this.tr('This list cannot be saved here.'))\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tthis.busy = busyKey\n\t\t\tthis.notice = ''\n\t\t\ttry {\n\t\t\t\tconst { axios } = await this.http()\n\t\t\t\tconst { data: stored } = await axios.get(prefixUrl(this.objectUrl))\n\t\t\t\tconst current = readPath(stored || {}, this.content.field)\n\t\t\t\tconst next = change(Array.isArray(current) ? current : [])\n\t\t\t\tconst { data } = await axios.patch(prefixUrl(this.objectUrl), { [this.content.field]: next })\n\t\t\t\tconst written = readPath(data || {}, this.content.field)\n\t\t\t\tthis.saved = Array.isArray(written) ? written : next\n\t\t\t\t/**\n\t\t\t\t * @event saved The list was saved: one PATCH of the field succeeded.\n\t\t\t\t * @type {{field: string, value: Array}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field: this.content.field, value: this.saved })\n\t\t\t\treturn true\n\t\t\t} catch (e) {\n\t\t\t\tthis.notify(e && e.userMessage ? e.userMessage : serverErrorMessage(e))\n\t\t\t\treturn false\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\n\t\tnotify(message, type = 'error') {\n\t\t\tthis.notice = message\n\t\t\tthis.noticeType = type\n\t\t},\n\n\t\t/**\n\t\t * Validate the draft and add it.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md#requirement-a-field-list-adds-and-removes-entries\n\t\t */\n\t\tasync add() {\n\t\t\tconst errors = {}\n\t\t\tfor (const field of this.addFields) {\n\t\t\t\tconst value = this.draft[field.key]\n\t\t\t\tconst empty = value === undefined || value === null || String(value).trim() === ''\n\t\t\t\tif (field.required && empty) {\n\t\t\t\t\terrors[field.key] = this.tr('Fill this in.')\n\t\t\t\t} else if (!empty && field.pattern && !new RegExp(field.pattern).test(String(value).trim())) {\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\tthis.errors = errors\n\t\t\tif (Object.keys(errors).length > 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst entry = { ...((this.content.add && this.content.add.defaults) || {}) }\n\t\t\tfor (const field of this.addFields) {\n\t\t\t\tconst value = this.draft[field.key]\n\t\t\t\tif (value !== undefined && value !== null && String(value).trim() !== '') {\n\t\t\t\t\tentry[field.key] = typeof value === 'string' ? value.trim() : value\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst unique = this.content.add && this.content.add.unique\n\t\t\tconst saved = await this.save((stored) => {\n\t\t\t\tif (unique && stored.some((item) => item && String(readPath(item, unique)) === String(entry[unique]))) {\n\t\t\t\t\tconst error = new Error('duplicate')\n\t\t\t\t\terror.userMessage = this.tr('This is already in the list.')\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t\treturn [...stored, entry]\n\t\t\t}, '*')\n\t\t\tif (saved) {\n\t\t\t\tthis.resetDraft()\n\t\t\t\tthis.adding = false\n\t\t\t\tthis.loadLive()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Remove an entry by its key.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync remove(row) {\n\t\t\tawait this.save((stored) => stored.filter((item, index) => this.keyOf(item, index) !== row.key), row.key)\n\t\t},\n\n\t\t/**\n\t\t * Run a row action's request, then re-read the live state.\n\t\t *\n\t\t * @param {object} action The action.\n\t\t * @param {object} row The row.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-field-list/specs/field-list/spec.md#requirement-a-field-list-row-can-run-a-configured-request\n\t\t */\n\t\tasync runAction(action, row) {\n\t\t\tthis.busy = row.key\n\t\t\tthis.notice = ''\n\t\t\ttry {\n\t\t\t\tconst { axios } = await this.http()\n\t\t\t\tconst method = String(action.request.method || 'POST').toLowerCase()\n\t\t\t\tconst payload = this.resolve(action.request.payload || {}, row.entry)\n\t\t\t\tconst response = method === 'get'\n\t\t\t\t\t? await axios.get(prefixUrl(this.resolve(action.request.url, row.entry)))\n\t\t\t\t\t: await axios[method](prefixUrl(this.resolve(action.request.url, row.entry)), payload)\n\t\t\t\tconst message = response && response.data && typeof response.data.message === 'string' ? response.data.message : ''\n\t\t\t\tif (message) {\n\t\t\t\t\tthis.notify(message, 'info')\n\t\t\t\t}\n\t\t\t\tawait this.loadLive()\n\t\t\t} catch (e) {\n\t\t\t\tthis.notify(serverErrorMessage(e))\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-field-list-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmin-width: 0;\n}\n\n.cn-field-list-widget__rows {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-field-list-widget__row {\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-field-list-widget__row:first-child {\n\tborder-top: none;\n\tpadding-top: 0;\n}\n\n.cn-field-list-widget__line {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tmin-width: 0;\n}\n\n.cn-field-list-widget__avatar {\n\tflex: 0 0 auto;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 50%;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text, var(--color-main-text));\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-field-list-widget__main {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-field-list-widget__title {\n\tfont-weight: 600;\n\toverflow-wrap: anywhere;\n}\n\n.cn-field-list-widget__meta,\n.cn-field-list-widget__aside,\n.cn-field-list-widget__detail,\n.cn-field-list-widget__hint,\n.cn-field-list-widget__empty {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-field-list-widget__meta,\n.cn-field-list-widget__aside,\n.cn-field-list-widget__detail {\n\tfont-size: 13px;\n}\n\n.cn-field-list-widget__aside {\n\twhite-space: nowrap;\n}\n\n.cn-field-list-widget__detail,\n.cn-field-list-widget__hint,\n.cn-field-list-widget__empty {\n\tmargin: 4px 0 0;\n\toverflow-wrap: anywhere;\n}\n\n.cn-field-list-widget__add {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-end;\n\tgap: 8px 12px;\n}\n\n.cn-field-list-widget__add > * {\n\tflex: 1 1 180px;\n}\n\n.cn-field-list-widget__add > button {\n\tflex: 0 0 auto;\n}\n\n.cn-field-list-widget__toolbar {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n}\n\n.cn-field-list-widget__table-wrap {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\toverflow-x: auto;\n}\n\n.cn-field-list-widget__table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-field-list-widget__th {\n\tpadding: 8px 12px;\n\ttext-align: start;\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n\tcolor: var(--color-text-maxcontrast);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-field-list-widget__th--menu,\n.cn-field-list-widget__td--menu {\n\twidth: 1%;\n\ttext-align: end;\n}\n\n.cn-field-list-widget__tr {\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-field-list-widget__td {\n\tpadding: 10px 12px;\n\tvertical-align: middle;\n\toverflow-wrap: anywhere;\n}\n\n.cn-field-list-widget__sr {\n\tposition: absolute;\n\twidth: 1px;\n\theight: 1px;\n\toverflow: hidden;\n\tclip-path: inset(50%);\n}\n\n.cn-field-list-widget__band {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 8px 12px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-warning);\n\tborder-radius: 10px;\n\tbackground: color-mix(in srgb, var(--color-warning) 14%, var(--color-main-background));\n\tfont-size: 14px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createTextVNode","_Fragment","_renderList","_createBlock","_createVNode","_toDisplayString","_createElementVNode"],"mappings":"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"}
@@ -503,7 +503,6 @@ var script = {
503
503
  default: true,
504
504
  },
505
505
 
506
- // eslint-disable-next-line vue/no-unused-properties
507
506
  /**
508
507
  * Draw this page in the `board` look (or `nextcloud`) whatever the app
509
508
  * does. Empty follows the `cnLook` CnAppRoot provides. Manifest key