@conduction/nextcloud-vue 2.117.0 → 2.118.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +2 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +6 -6
  5. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  6. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js +2 -1
  7. package/dist/esm/components/CnAssignDialog/CnAssignDialog.vue2.js.map +1 -1
  8. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  9. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +18 -0
  10. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  11. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +14 -8
  12. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  13. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  14. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +11 -1
  15. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  16. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  17. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +9 -4
  18. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  19. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  20. package/dist/esm/components/CnMailTab/CnMailTab.vue2.js +2 -1
  21. package/dist/esm/components/CnMailTab/CnMailTab.vue2.js.map +1 -1
  22. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  23. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +71 -0
  24. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  25. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +25 -9
  26. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  27. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  28. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +11 -2
  29. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  30. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  31. package/dist/esm/components/CnSearchPage/CnSearchPage.vue.js +1 -1
  32. package/dist/esm/components/CnSearchPage/CnSearchPage.vue2.js +161 -5
  33. package/dist/esm/components/CnSearchPage/CnSearchPage.vue2.js.map +1 -1
  34. package/dist/esm/components/CnSearchPage/CnSearchPage.vue3.js +9 -9
  35. package/dist/esm/components/CnSearchPage/CnSearchPage.vue3.js.map +1 -1
  36. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  37. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +35 -5
  38. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  39. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  40. package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue.js +9 -0
  41. package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue.js.map +1 -0
  42. package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue2.js +435 -0
  43. package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue2.js.map +1 -0
  44. package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue3.js +300 -0
  45. package/dist/esm/components/CnTransitionInputFields/CnTransitionInputFields.vue3.js.map +1 -0
  46. package/dist/esm/composables/useEndpointSource.js +1 -36
  47. package/dist/esm/composables/useEndpointSource.js.map +1 -1
  48. package/dist/esm/dialogs/CnTransitionInputDialog.vue.js +1 -1
  49. package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js +57 -336
  50. package/dist/esm/dialogs/CnTransitionInputDialog.vue2.js.map +1 -1
  51. package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js +18 -155
  52. package/dist/esm/dialogs/CnTransitionInputDialog.vue3.js.map +1 -1
  53. package/dist/esm/index.js +2 -0
  54. package/dist/esm/index.js.map +1 -1
  55. package/dist/esm/l10n/en.json.js +2 -1
  56. package/dist/esm/l10n/en.json.js.map +1 -1
  57. package/dist/esm/l10n/nl.json.js +2 -1
  58. package/dist/esm/l10n/nl.json.js.map +1 -1
  59. package/dist/esm/library-style.js +1 -1
  60. package/dist/esm/nextcloud-vue.css +308 -229
  61. package/dist/esm/utils/actionsDispatcher.js +3 -2
  62. package/dist/esm/utils/actionsDispatcher.js.map +1 -1
  63. package/dist/esm/utils/interpolateUrlTokens.js +43 -0
  64. package/dist/esm/utils/interpolateUrlTokens.js.map +1 -0
  65. package/dist/esm/utils/labelsByField.js +72 -0
  66. package/dist/esm/utils/labelsByField.js.map +1 -0
  67. package/dist/esm/utils/listCreateAction.js +91 -0
  68. package/dist/esm/utils/listCreateAction.js.map +1 -0
  69. package/dist/esm/utils/transitionInputs.js +493 -0
  70. package/dist/esm/utils/transitionInputs.js.map +1 -0
  71. package/dist/esm/utils/visibleWhen.js +9 -2
  72. package/dist/esm/utils/visibleWhen.js.map +1 -1
  73. package/dist/nextcloud-vue.cjs.js +6690 -5404
  74. package/dist/nextcloud-vue.cjs.js.map +2 -2
  75. package/dist/nextcloud-vue.css +308 -229
  76. package/l10n/en.json +2 -1
  77. package/l10n/nl.json +2 -1
  78. package/package.json +1 -1
  79. package/src/components/CnActionsBar/CnActionsBar.vue +6 -6
  80. package/src/components/CnDashboardPage/CnDashboardPage.vue +27 -5
  81. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +11 -1
  82. package/src/components/CnIndexPage/CnIndexPage.vue +9 -4
  83. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +86 -0
  84. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +11 -2
  85. package/src/components/CnSearchPage/CnSearchPage.vue +170 -14
  86. package/src/components/CnTabsWidget/CnTabsWidget.vue +35 -5
  87. package/src/components/CnTransitionInputFields/CnTransitionInputFields.vue +750 -0
  88. package/src/components/CnTransitionInputFields/index.js +11 -0
  89. package/src/components/index.js +1 -0
  90. package/src/composables/useEndpointSource.js +3 -36
  91. package/src/dialogs/CnTransitionInputDialog.vue +73 -465
  92. package/src/index.js +2 -0
  93. package/src/utils/interpolateUrlTokens.js +40 -0
  94. package/src/utils/labelsByField.js +69 -0
  95. package/src/utils/listCreateAction.js +87 -0
  96. package/src/utils/transitionInputs.js +489 -0
  97. package/src/utils/visibleWhen.js +9 -2
@@ -0,0 +1,300 @@
1
+ import { resolveComponent, openBlock, createElementBlock, normalizeClass, Fragment, createBlock, resolveDynamicComponent, createCommentVNode, createElementVNode, toDisplayString, renderList, createVNode, withCtx, createTextVNode } from 'vue';
2
+
3
+ const _hoisted_1 = ["data-testid"];
4
+ const _hoisted_2 = { class: "cn-transition-input-fields__card-text" };
5
+ const _hoisted_3 = { class: "cn-transition-input-fields__muted" };
6
+ const _hoisted_4 = {
7
+ key: 1,
8
+ class: "cn-transition-input-fields__badge"
9
+ };
10
+ const _hoisted_5 = ["data-testid"];
11
+ const _hoisted_6 = {
12
+ key: 0,
13
+ class: "cn-transition-input-fields__section-title"
14
+ };
15
+ const _hoisted_7 = { class: "cn-transition-input-fields__facts" };
16
+ const _hoisted_8 = ["data-testid"];
17
+ const _hoisted_9 = {
18
+ key: 2,
19
+ class: "cn-transition-input__reference"
20
+ };
21
+ const _hoisted_10 = { class: "cn-transition-input__label" };
22
+ const _hoisted_11 = {
23
+ key: 3,
24
+ class: "cn-transition-input__object"
25
+ };
26
+ const _hoisted_12 = ["data-testid"];
27
+ const _hoisted_13 = ["data-testid"];
28
+ const _hoisted_14 = ["for"];
29
+ const _hoisted_15 = {
30
+ key: 3,
31
+ class: "cn-transition-input-fields__muted"
32
+ };
33
+ const _hoisted_16 = ["data-testid"];
34
+ const _hoisted_17 = ["data-testid"];
35
+ const _hoisted_18 = { class: "cn-transition-input-fields__label" };
36
+ const _hoisted_19 = ["data-testid"];
37
+ const _hoisted_20 = {
38
+ key: 0,
39
+ class: "cn-transition-input-fields__muted"
40
+ };
41
+ const _hoisted_21 = ["data-testid"];
42
+
43
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
44
+ const _component_CnTemplateSelect = resolveComponent("CnTemplateSelect");
45
+ const _component_NcSelect = resolveComponent("NcSelect");
46
+ const _component_CnResourceSelect = resolveComponent("CnResourceSelect");
47
+ const _component_NcTextArea = resolveComponent("NcTextArea");
48
+ const _component_NcCheckboxRadioSwitch = resolveComponent("NcCheckboxRadioSwitch");
49
+ const _component_NcTextField = resolveComponent("NcTextField");
50
+ const _component_NcNoteCard = resolveComponent("NcNoteCard");
51
+
52
+ return (openBlock(), createElementBlock("div", {
53
+ class: normalizeClass(["cn-transition-input-fields", { 'cn-transition-input-fields--columns': $props.columns === 2 }])
54
+ }, [
55
+ ($options.summaryShown)
56
+ ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
57
+ ($props.summary.card)
58
+ ? (openBlock(), createElementBlock("div", {
59
+ key: 0,
60
+ class: "cn-transition-input-fields__card cn-transition-input-fields__wide",
61
+ "data-testid": $options.summaryTestid('card')
62
+ }, [
63
+ ($props.summary.card.icon)
64
+ ? (openBlock(), createBlock(resolveDynamicComponent($props.summary.card.icon), {
65
+ key: 0,
66
+ size: 20,
67
+ class: "cn-transition-input-fields__card-icon"
68
+ }))
69
+ : createCommentVNode("v-if", true),
70
+ createElementVNode("span", _hoisted_2, [
71
+ createElementVNode("strong", null, toDisplayString($options.contextText($props.summary.card.title)), 1 /* TEXT */),
72
+ createElementVNode("span", _hoisted_3, toDisplayString($options.cardMeta), 1 /* TEXT */)
73
+ ]),
74
+ ($options.contextText($props.summary.card.badge))
75
+ ? (openBlock(), createElementBlock("span", _hoisted_4, toDisplayString($options.contextText($props.summary.card.badge)), 1 /* TEXT */))
76
+ : createCommentVNode("v-if", true)
77
+ ], 8 /* PROPS */, _hoisted_1))
78
+ : createCommentVNode("v-if", true),
79
+ (Array.isArray($props.summary.facts) && $props.summary.facts.length > 0)
80
+ ? (openBlock(), createElementBlock("section", {
81
+ key: 1,
82
+ class: "cn-transition-input-fields__wide",
83
+ "data-testid": $options.summaryTestid('facts')
84
+ }, [
85
+ ($props.summary.title)
86
+ ? (openBlock(), createElementBlock("h3", _hoisted_6, toDisplayString($props.summary.title), 1 /* TEXT */))
87
+ : createCommentVNode("v-if", true),
88
+ createElementVNode("dl", _hoisted_7, [
89
+ (openBlock(true), createElementBlock(Fragment, null, renderList($props.summary.facts, (fact) => {
90
+ return (openBlock(), createElementBlock("div", {
91
+ key: fact.path || fact.label
92
+ }, [
93
+ createElementVNode("dt", null, toDisplayString(fact.label), 1 /* TEXT */),
94
+ createElementVNode("dd", null, toDisplayString($options.contextText(fact.path) || fact.fallback || ''), 1 /* TEXT */)
95
+ ]))
96
+ }), 128 /* KEYED_FRAGMENT */))
97
+ ])
98
+ ], 8 /* PROPS */, _hoisted_5))
99
+ : createCommentVNode("v-if", true)
100
+ ], 64 /* STABLE_FRAGMENT */))
101
+ : createCommentVNode("v-if", true),
102
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.shownFields, (field) => {
103
+ return (openBlock(), createElementBlock(Fragment, {
104
+ key: field.key
105
+ }, [
106
+ createElementVNode("div", {
107
+ class: normalizeClass(["cn-transition-input__field", {
108
+ 'cn-transition-input__field--refused': $options.isRefused(field.key),
109
+ 'cn-transition-input-fields__wide': field.input.wide === true,
110
+ }]),
111
+ "data-testid": `cn-transition-input-${field.key}`
112
+ }, [
113
+ (field.widget === 'template')
114
+ ? (openBlock(), createBlock(_component_CnTemplateSelect, {
115
+ key: 0,
116
+ url: field.input.url || '',
117
+ schema: field.input.schema || '',
118
+ params: field.input.params || {},
119
+ mapOption: field.input.mapOption,
120
+ inputLabel: field.label,
121
+ placeholder: field.input.placeholder || '',
122
+ "data-testid": field.input.testid || `cn-transition-input-template-${field.key}`,
123
+ onApply: $event => ($options.applyTemplate(field, $event))
124
+ }, null, 8 /* PROPS */, ["url", "schema", "params", "mapOption", "inputLabel", "placeholder", "data-testid", "onApply"]))
125
+ : (field.widget === 'select')
126
+ ? (openBlock(), createBlock(_component_NcSelect, {
127
+ key: 1,
128
+ modelValue: $options.selectedOption(field),
129
+ options: field.options,
130
+ label: "label",
131
+ inputLabel: $options.labelOf(field),
132
+ clearable: !field.required,
133
+ disabled: $props.disabled,
134
+ "data-testid": field.input.testid || `cn-transition-input-select-${field.key}`,
135
+ "onUpdate:modelValue": $event => ($options.setValue(field.key, $event && $event.value !== undefined ? $event.value : ''))
136
+ }, null, 8 /* PROPS */, ["modelValue", "options", "inputLabel", "clearable", "disabled", "data-testid", "onUpdate:modelValue"]))
137
+ : (field.widget === 'reference')
138
+ ? (openBlock(), createElementBlock("div", _hoisted_9, [
139
+ createElementVNode("label", _hoisted_10, toDisplayString($options.labelOf(field)), 1 /* TEXT */),
140
+ createVNode(_component_CnResourceSelect, {
141
+ register: field.referenceRegister,
142
+ schema: String(field.reference.schema),
143
+ labelField: (field.picker && field.picker.labelField) || field.reference.labelField || 'name',
144
+ filter: (field.picker && field.picker.filter) || {},
145
+ exclude: $options.excludedIds(field),
146
+ allowCreate: false,
147
+ preload: true,
148
+ inputLabel: $options.labelOf(field),
149
+ modelValue: String($props.modelValue[field.key] ?? ''),
150
+ "data-testid": `cn-transition-input-picker-${field.key}`,
151
+ "onUpdate:modelValue": $event => ($options.setValue(field.key, $event))
152
+ }, null, 8 /* PROPS */, ["register", "schema", "labelField", "filter", "exclude", "inputLabel", "modelValue", "data-testid", "onUpdate:modelValue"])
153
+ ]))
154
+ : (field.widget === 'object')
155
+ ? (openBlock(), createElementBlock("fieldset", _hoisted_11, [
156
+ createElementVNode("legend", null, toDisplayString($options.labelOf(field)), 1 /* TEXT */),
157
+ (openBlock(true), createElementBlock(Fragment, null, renderList(field.subFields, (sub) => {
158
+ return (openBlock(), createElementBlock("div", {
159
+ key: sub.key,
160
+ class: "cn-transition-input__subfield",
161
+ "data-testid": `cn-transition-input-${field.key}-${sub.key}`
162
+ }, [
163
+ (sub.widget === 'textarea')
164
+ ? (openBlock(), createBlock(_component_NcTextArea, {
165
+ key: 0,
166
+ modelValue: String($options.subValue(field.key, sub.key) ?? ''),
167
+ label: $options.subLabel(sub),
168
+ rows: "3",
169
+ "onUpdate:modelValue": $event => ($options.setSubValue(field.key, sub.key, $event))
170
+ }, null, 8 /* PROPS */, ["modelValue", "label", "onUpdate:modelValue"]))
171
+ : (sub.widget === 'checkbox')
172
+ ? (openBlock(), createBlock(_component_NcCheckboxRadioSwitch, {
173
+ key: 1,
174
+ modelValue: $options.subValue(field.key, sub.key) === true,
175
+ type: "switch",
176
+ "onUpdate:modelValue": $event => ($options.setSubValue(field.key, sub.key, $event === true))
177
+ }, {
178
+ default: withCtx(() => [
179
+ createTextVNode(toDisplayString($options.subLabel(sub)), 1 /* TEXT */)
180
+ ]),
181
+ _: 2 /* DYNAMIC */
182
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "onUpdate:modelValue"]))
183
+ : (openBlock(), createBlock(_component_NcTextField, {
184
+ key: 2,
185
+ modelValue: String($options.subValue(field.key, sub.key) ?? ''),
186
+ type: sub.widget === 'number' ? 'number' : 'text',
187
+ label: $options.subLabel(sub),
188
+ "onUpdate:modelValue": $event => ($options.setSubValue(field.key, sub.key, $event))
189
+ }, null, 8 /* PROPS */, ["modelValue", "type", "label", "onUpdate:modelValue"])),
190
+ ($options.isSubRefused(field.key, sub.key))
191
+ ? (openBlock(), createElementBlock("p", {
192
+ key: 3,
193
+ class: "cn-transition-input__field-error",
194
+ "data-testid": `cn-transition-input-error-${field.key}.${sub.key}`
195
+ }, toDisplayString($options.t('nextcloud-vue', 'This value was not accepted.')), 9 /* TEXT, PROPS */, _hoisted_13))
196
+ : createCommentVNode("v-if", true)
197
+ ], 8 /* PROPS */, _hoisted_12))
198
+ }), 128 /* KEYED_FRAGMENT */))
199
+ ]))
200
+ : (field.widget === 'checkbox')
201
+ ? (openBlock(), createBlock(_component_NcCheckboxRadioSwitch, {
202
+ key: 4,
203
+ modelValue: $props.modelValue[field.key] === true,
204
+ type: "switch",
205
+ disabled: $props.disabled,
206
+ "onUpdate:modelValue": $event => ($options.setValue(field.key, $event === true))
207
+ }, {
208
+ default: withCtx(() => [
209
+ createTextVNode(toDisplayString($options.labelOf(field)), 1 /* TEXT */)
210
+ ]),
211
+ _: 2 /* DYNAMIC */
212
+ }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "disabled", "onUpdate:modelValue"]))
213
+ : (openBlock(), createElementBlock(Fragment, { key: 5 }, [
214
+ (field.input.labelOutside === true)
215
+ ? (openBlock(), createElementBlock("label", {
216
+ key: 0,
217
+ class: "cn-transition-input-fields__label",
218
+ for: $options.inputId(field)
219
+ }, toDisplayString($options.labelOf(field)), 9 /* TEXT, PROPS */, _hoisted_14))
220
+ : createCommentVNode("v-if", true),
221
+ (field.widget === 'textarea')
222
+ ? (openBlock(), createBlock(_component_NcTextArea, {
223
+ key: 1,
224
+ id: $options.inputId(field),
225
+ modelValue: String($props.modelValue[field.key] ?? ''),
226
+ label: $options.labelOf(field),
227
+ labelOutside: field.input.labelOutside === true,
228
+ helperText: field.description || '',
229
+ rows: field.input.rows || 4,
230
+ disabled: $props.disabled,
231
+ resize: "vertical",
232
+ "data-testid": field.input.testid || null,
233
+ "onUpdate:modelValue": $event => ($options.setValue(field.key, $event))
234
+ }, null, 8 /* PROPS */, ["id", "modelValue", "label", "labelOutside", "helperText", "rows", "disabled", "data-testid", "onUpdate:modelValue"]))
235
+ : (openBlock(), createBlock(_component_NcTextField, {
236
+ key: 2,
237
+ id: $options.inputId(field),
238
+ modelValue: String($props.modelValue[field.key] ?? ''),
239
+ type: $options.textType(field),
240
+ label: $options.labelOf(field),
241
+ labelOutside: field.input.labelOutside === true,
242
+ helperText: field.description || '',
243
+ disabled: $props.disabled,
244
+ "data-testid": field.input.testid || null,
245
+ "onUpdate:modelValue": $event => ($options.setValue(field.key, $event))
246
+ }, null, 8 /* PROPS */, ["id", "modelValue", "type", "label", "labelOutside", "helperText", "disabled", "data-testid", "onUpdate:modelValue"])),
247
+ (field.input.note)
248
+ ? (openBlock(), createElementBlock("span", _hoisted_15, toDisplayString(field.input.note), 1 /* TEXT */))
249
+ : createCommentVNode("v-if", true)
250
+ ], 64 /* STABLE_FRAGMENT */)),
251
+ ($options.isRefused(field.key))
252
+ ? (openBlock(), createElementBlock("p", {
253
+ key: 6,
254
+ class: "cn-transition-input__field-error",
255
+ "data-testid": `cn-transition-input-error-${field.key}`
256
+ }, toDisplayString($options.refusalFor(field)), 9 /* TEXT, PROPS */, _hoisted_16))
257
+ : createCommentVNode("v-if", true)
258
+ ], 10 /* CLASS, PROPS */, _hoisted_8),
259
+ (field.previewText)
260
+ ? (openBlock(), createElementBlock("div", {
261
+ key: `${field.key}-preview`,
262
+ class: "cn-transition-input-fields__preview cn-transition-input-fields__wide",
263
+ "data-testid": field.input.preview.testid || `cn-transition-input-preview-${field.key}`
264
+ }, [
265
+ createElementVNode("span", _hoisted_18, toDisplayString(field.input.preview.label), 1 /* TEXT */),
266
+ createElementVNode("span", {
267
+ "data-testid": `${field.input.preview.testid || `cn-transition-input-preview-${field.key}`}-value`
268
+ }, toDisplayString(field.previewText), 9 /* TEXT, PROPS */, _hoisted_19),
269
+ (field.input.preview.note)
270
+ ? (openBlock(), createElementBlock("span", _hoisted_20, toDisplayString(field.input.preview.note), 1 /* TEXT */))
271
+ : createCommentVNode("v-if", true)
272
+ ], 8 /* PROPS */, _hoisted_17))
273
+ : createCommentVNode("v-if", true)
274
+ ], 64 /* STABLE_FRAGMENT */))
275
+ }), 128 /* KEYED_FRAGMENT */)),
276
+ ($props.notice && $props.notice.text)
277
+ ? (openBlock(), createBlock(_component_NcNoteCard, {
278
+ key: 1,
279
+ class: "cn-transition-input-fields__wide",
280
+ type: $props.notice.type || 'info',
281
+ heading: $props.notice.heading || ''
282
+ }, {
283
+ default: withCtx(() => [
284
+ createTextVNode(toDisplayString($props.notice.text), 1 /* TEXT */)
285
+ ]),
286
+ _: 1 /* STABLE */
287
+ }, 8 /* PROPS */, ["type", "heading"]))
288
+ : createCommentVNode("v-if", true),
289
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.unofferedRefusals, (key) => {
290
+ return (openBlock(), createElementBlock("p", {
291
+ key: `unoffered-${key}`,
292
+ class: "cn-transition-input__field-error",
293
+ "data-testid": `cn-transition-input-error-${key}`
294
+ }, toDisplayString($options.t('nextcloud-vue', 'This action does not accept the field "{field}".', { field: key })), 9 /* TEXT, PROPS */, _hoisted_21))
295
+ }), 128 /* KEYED_FRAGMENT */))
296
+ ], 2 /* CLASS */))
297
+ }
298
+
299
+ export { render };
300
+ //# sourceMappingURL=CnTransitionInputFields.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnTransitionInputFields.vue3.js","sources":["../../../../src/components/CnTransitionInputFields/CnTransitionInputFields.vue?vue&type=template&id=5d5e2ca9&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div\n\t\tclass=\"cn-transition-input-fields\"\n\t\t:class=\"{ 'cn-transition-input-fields--columns': columns === 2 }\">\n\t\t<template v-if=\"summaryShown\">\n\t\t\t<div v-if=\"summary.card\"\n\t\t\t\tclass=\"cn-transition-input-fields__card cn-transition-input-fields__wide\"\n\t\t\t\t:data-testid=\"summaryTestid('card')\">\n\t\t\t\t<component :is=\"summary.card.icon\"\n\t\t\t\t\tv-if=\"summary.card.icon\"\n\t\t\t\t\t:size=\"20\"\n\t\t\t\t\tclass=\"cn-transition-input-fields__card-icon\" />\n\t\t\t\t<span class=\"cn-transition-input-fields__card-text\">\n\t\t\t\t\t<strong>{{ contextText(summary.card.title) }}</strong>\n\t\t\t\t\t<span class=\"cn-transition-input-fields__muted\">{{ cardMeta }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span v-if=\"contextText(summary.card.badge)\" class=\"cn-transition-input-fields__badge\">\n\t\t\t\t\t{{ contextText(summary.card.badge) }}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t\t<section v-if=\"Array.isArray(summary.facts) && summary.facts.length > 0\"\n\t\t\t\tclass=\"cn-transition-input-fields__wide\"\n\t\t\t\t:data-testid=\"summaryTestid('facts')\">\n\t\t\t\t<h3 v-if=\"summary.title\" class=\"cn-transition-input-fields__section-title\">\n\t\t\t\t\t{{ summary.title }}\n\t\t\t\t</h3>\n\t\t\t\t<dl class=\"cn-transition-input-fields__facts\">\n\t\t\t\t\t<div v-for=\"fact in summary.facts\" :key=\"fact.path || fact.label\">\n\t\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t\t<dd>{{ contextText(fact.path) || fact.fallback || '' }}</dd>\n\t\t\t\t\t</div>\n\t\t\t\t</dl>\n\t\t\t</section>\n\t\t</template>\n\n\t\t<template v-for=\"field in shownFields\" :key=\"field.key\">\n\t\t\t<div\n\t\t\t\tclass=\"cn-transition-input__field\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'cn-transition-input__field--refused': isRefused(field.key),\n\t\t\t\t\t'cn-transition-input-fields__wide': field.input.wide === true,\n\t\t\t\t}\"\n\t\t\t\t:data-testid=\"`cn-transition-input-${field.key}`\">\n\t\t\t\t<!-- A template fills another input; it is never sent itself. -->\n\t\t\t\t<CnTemplateSelect v-if=\"field.widget === 'template'\"\n\t\t\t\t\t:url=\"field.input.url || ''\"\n\t\t\t\t\t:schema=\"field.input.schema || ''\"\n\t\t\t\t\t:params=\"field.input.params || {}\"\n\t\t\t\t\t:mapOption=\"field.input.mapOption\"\n\t\t\t\t\t:inputLabel=\"field.label\"\n\t\t\t\t\t:placeholder=\"field.input.placeholder || ''\"\n\t\t\t\t\t:data-testid=\"field.input.testid || `cn-transition-input-template-${field.key}`\"\n\t\t\t\t\t@apply=\"applyTemplate(field, $event)\" />\n\n\t\t\t\t<!-- An input that declares its choices is picked from them. -->\n\t\t\t\t<NcSelect v-else-if=\"field.widget === 'select'\"\n\t\t\t\t\t:modelValue=\"selectedOption(field)\"\n\t\t\t\t\t:options=\"field.options\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t:inputLabel=\"labelOf(field)\"\n\t\t\t\t\t:clearable=\"!field.required\"\n\t\t\t\t\t:disabled=\"disabled\"\n\t\t\t\t\t:data-testid=\"field.input.testid || `cn-transition-input-select-${field.key}`\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event && $event.value !== undefined ? $event.value : '')\" />\n\n\t\t\t\t<!-- An input that points at another record is picked, never typed. -->\n\t\t\t\t<div v-else-if=\"field.widget === 'reference'\" class=\"cn-transition-input__reference\">\n\t\t\t\t\t<label class=\"cn-transition-input__label\">{{ labelOf(field) }}</label>\n\t\t\t\t\t<CnResourceSelect\n\t\t\t\t\t\t:register=\"field.referenceRegister\"\n\t\t\t\t\t\t:schema=\"String(field.reference.schema)\"\n\t\t\t\t\t\t:labelField=\"(field.picker && field.picker.labelField) || field.reference.labelField || 'name'\"\n\t\t\t\t\t\t:filter=\"(field.picker && field.picker.filter) || {}\"\n\t\t\t\t\t\t:exclude=\"excludedIds(field)\"\n\t\t\t\t\t\t:allowCreate=\"false\"\n\t\t\t\t\t\t:preload=\"true\"\n\t\t\t\t\t\t:inputLabel=\"labelOf(field)\"\n\t\t\t\t\t\t:modelValue=\"String(modelValue[field.key] ?? '')\"\n\t\t\t\t\t\t:data-testid=\"`cn-transition-input-picker-${field.key}`\"\n\t\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- An object input: its sub-properties, one field at a time. -->\n\t\t\t\t<fieldset v-else-if=\"field.widget === 'object'\" class=\"cn-transition-input__object\">\n\t\t\t\t\t<legend>{{ labelOf(field) }}</legend>\n\t\t\t\t\t<div v-for=\"sub in field.subFields\"\n\t\t\t\t\t\t:key=\"sub.key\"\n\t\t\t\t\t\tclass=\"cn-transition-input__subfield\"\n\t\t\t\t\t\t:data-testid=\"`cn-transition-input-${field.key}-${sub.key}`\">\n\t\t\t\t\t\t<NcTextArea v-if=\"sub.widget === 'textarea'\"\n\t\t\t\t\t\t\t:modelValue=\"String(subValue(field.key, sub.key) ?? '')\"\n\t\t\t\t\t\t\t:label=\"subLabel(sub)\"\n\t\t\t\t\t\t\trows=\"3\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event)\" />\n\t\t\t\t\t\t<NcCheckboxRadioSwitch v-else-if=\"sub.widget === 'checkbox'\"\n\t\t\t\t\t\t\t:modelValue=\"subValue(field.key, sub.key) === true\"\n\t\t\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event === true)\">\n\t\t\t\t\t\t\t{{ subLabel(sub) }}\n\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t<NcTextField v-else\n\t\t\t\t\t\t\t:modelValue=\"String(subValue(field.key, sub.key) ?? '')\"\n\t\t\t\t\t\t\t:type=\"sub.widget === 'number' ? 'number' : 'text'\"\n\t\t\t\t\t\t\t:label=\"subLabel(sub)\"\n\t\t\t\t\t\t\t@update:modelValue=\"setSubValue(field.key, sub.key, $event)\" />\n\t\t\t\t\t\t<p v-if=\"isSubRefused(field.key, sub.key)\"\n\t\t\t\t\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-transition-input-error-${field.key}.${sub.key}`\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'This value was not accepted.') }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</fieldset>\n\n\t\t\t\t<NcCheckboxRadioSwitch v-else-if=\"field.widget === 'checkbox'\"\n\t\t\t\t\t:modelValue=\"modelValue[field.key] === true\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t:disabled=\"disabled\"\n\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event === true)\">\n\t\t\t\t\t{{ labelOf(field) }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\n\t\t\t\t<template v-else>\n\t\t\t\t\t<!-- A label drawn above the field, as a form board draws it,\n\t\t\t\t\t is tied to the field by its id. -->\n\t\t\t\t\t<label v-if=\"field.input.labelOutside === true\"\n\t\t\t\t\t\tclass=\"cn-transition-input-fields__label\"\n\t\t\t\t\t\t:for=\"inputId(field)\">{{ labelOf(field) }}</label>\n\t\t\t\t\t<NcTextArea v-if=\"field.widget === 'textarea'\"\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\t:modelValue=\"String(modelValue[field.key] ?? '')\"\n\t\t\t\t\t\t:label=\"labelOf(field)\"\n\t\t\t\t\t\t:labelOutside=\"field.input.labelOutside === true\"\n\t\t\t\t\t\t:helperText=\"field.description || ''\"\n\t\t\t\t\t\t:rows=\"field.input.rows || 4\"\n\t\t\t\t\t\t:disabled=\"disabled\"\n\t\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\t\t:data-testid=\"field.input.testid || null\"\n\t\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\t\t\t\t\t<NcTextField v-else\n\t\t\t\t\t\t:id=\"inputId(field)\"\n\t\t\t\t\t\t:modelValue=\"String(modelValue[field.key] ?? '')\"\n\t\t\t\t\t\t:type=\"textType(field)\"\n\t\t\t\t\t\t:label=\"labelOf(field)\"\n\t\t\t\t\t\t:labelOutside=\"field.input.labelOutside === true\"\n\t\t\t\t\t\t:helperText=\"field.description || ''\"\n\t\t\t\t\t\t:disabled=\"disabled\"\n\t\t\t\t\t\t:data-testid=\"field.input.testid || null\"\n\t\t\t\t\t\t@update:modelValue=\"setValue(field.key, $event)\" />\n\t\t\t\t\t<span v-if=\"field.input.note\" class=\"cn-transition-input-fields__muted\">\n\t\t\t\t\t\t{{ field.input.note }}\n\t\t\t\t\t</span>\n\t\t\t\t</template>\n\n\t\t\t\t<p v-if=\"isRefused(field.key)\"\n\t\t\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t\t\t:data-testid=\"`cn-transition-input-error-${field.key}`\">\n\t\t\t\t\t{{ refusalFor(field) }}\n\t\t\t\t</p>\n\t\t\t</div>\n\n\t\t\t<!-- What the input means once filled in, such as the day a paused\n\t\t\t term comes back. Shown only once it can be worked out. -->\n\t\t\t<div v-if=\"field.previewText\"\n\t\t\t\t:key=\"`${field.key}-preview`\"\n\t\t\t\tclass=\"cn-transition-input-fields__preview cn-transition-input-fields__wide\"\n\t\t\t\t:data-testid=\"field.input.preview.testid || `cn-transition-input-preview-${field.key}`\">\n\t\t\t\t<span class=\"cn-transition-input-fields__label\">{{ field.input.preview.label }}</span>\n\t\t\t\t<span :data-testid=\"`${field.input.preview.testid || `cn-transition-input-preview-${field.key}`}-value`\">{{ field.previewText }}</span>\n\t\t\t\t<span v-if=\"field.input.preview.note\" class=\"cn-transition-input-fields__muted\">\n\t\t\t\t\t{{ field.input.preview.note }}\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<NcNoteCard v-if=\"notice && notice.text\"\n\t\t\tclass=\"cn-transition-input-fields__wide\"\n\t\t\t:type=\"notice.type || 'info'\"\n\t\t\t:heading=\"notice.heading || ''\">\n\t\t\t{{ notice.text }}\n\t\t</NcNoteCard>\n\n\t\t<!-- A key the refusal names that this form never offered is not a\n\t\t field anybody can correct here. Saying so beats saying nothing:\n\t\t the request sent something the action does not accept. -->\n\t\t<p v-for=\"key in unofferedRefusals\"\n\t\t\t:key=\"`unoffered-${key}`\"\n\t\t\tclass=\"cn-transition-input__field-error\"\n\t\t\t:data-testid=\"`cn-transition-input-error-${key}`\">\n\t\t\t{{ t('nextcloud-vue', 'This action does not accept the field \"{field}\".', { field: key }) }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcCheckboxRadioSwitch, NcNoteCard, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'\nimport CnTemplateSelect from '../CnTemplateSelect/CnTemplateSelect.vue'\nimport { readPath } from '../../utils/readPath.js'\nimport { applyTemplateText, isInputFilled, resolveInputFields } from '../../utils/transitionInputs.js'\n\nlet uid = 0\n\n/**\n * CnTransitionInputFields — the declared inputs of a transition or an act,\n * drawn wherever the host puts them.\n *\n * CnTransitionInputDialog draws them in their own dialog. A host that lists\n * several acts and opens the chosen one's inputs in place (under its card)\n * draws them with this component, so both read the same declarations and\n * decide the same way. The values are a `v-model` object keyed by field;\n * whether they are complete is `inputFieldsComplete(resolveInputFields(...))`.\n *\n * Next to the schema-resolved widgets an input may declare `widget` (`text`,\n * `textarea`, `number`, `date`, `select`, `template`), `optionsSource` (a dot\n * path into `context`), `other`, `helperFrom`, `preview`, `default` and\n * presentation keys; see `resolveInputFields` in `utils/transitionInputs.js`.\n *\n * ```vue\n * <CnTransitionInputFields\n * v-model=\"values\"\n * :inputs=\"act.inputs\"\n * :context=\"{ pauseReasons }\"\n * :columns=\"2\" />\n * ```\n *\n * @spec openspec/changes/dq-abstract-forms/specs/transition-inputs/spec.md\n */\nexport default {\n\tname: 'CnTransitionInputFields',\n\n\tcomponents: {\n\t\tCnResourceSelect,\n\t\tCnTemplateSelect,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcNoteCard,\n\t\tNcSelect,\n\t\tNcTextArea,\n\t\tNcTextField,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The declared inputs: `[{ field, required, label, widget, options,\n\t\t * optionsSource, optionValue, optionLabel, other, helperFrom, preview,\n\t\t * default, description, note, labelOutside, id, wide, testid, rows,\n\t\t * placeholder }]`, plus for a `template` input `url`, `schema`,\n\t\t * `params`, `mapOption` and `applyTo`.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\tinputs: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * The values, keyed by field.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The object's JSON Schema, which labels and types the inputs that\n\t\t * declare no widget of their own.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The record the action runs on: `picker.excludeSelf` leaves its id\n\t\t * out, and an object input is merged over its present value.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tcurrentObject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Register slug the reference pickers look in when the schema property\n\t\t * names none of its own.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * What `optionsSource` and the summary paths read, such as the case\n\t\t * type's choices and the record shown in the summary.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontext: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The input keys a refusal named. Each one this form offers is marked\n\t\t * on its own field; each one it does not is reported as a key the\n\t\t * action does not accept.\n\t\t *\n\t\t * @type {string[]}\n\t\t */\n\t\tfieldErrors: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Whether the inputs are locked, such as while the action posts.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tdisabled: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * 1 stacks the inputs; 2 sets them side by side, with `wide` inputs,\n\t\t * previews, the summary and the notice across both columns.\n\t\t *\n\t\t * @type {number}\n\t\t */\n\t\tcolumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: 1,\n\t\t},\n\n\t\t/**\n\t\t * Whether a required input's label carries a ` *` marker.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tmarkRequired: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * A read-only block above the inputs about what the action works on:\n\t\t * `{ when, card: { icon, title, meta: [], badge }, title, facts:\n\t\t * [{ label, path, fallback }], testid }`. `when`, `title`, `meta`,\n\t\t * `badge` and each fact's `path` are dot paths into `context`; the\n\t\t * block is shown only when `when` resolves.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tsummary: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * A note under the inputs: `{ type, heading, text }`.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tnotice: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['update:modelValue'],\n\n\tdata() {\n\t\tuid += 1\n\t\treturn {\n\t\t\tuid,\n\t\t\t// The values with every change made since the host last passed\n\t\t\t// them in, so two changes in one tick both survive.\n\t\t\tlatest: { ...this.modelValue },\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Every declared input, resolved against the schema and the context. */\n\t\tfields() {\n\t\t\treturn resolveInputFields(this.inputs, {\n\t\t\t\tschema: this.schema,\n\t\t\t\tregister: this.register,\n\t\t\t\tcontext: this.context,\n\t\t\t\tvalues: this.modelValue,\n\t\t\t})\n\t\t},\n\n\t\t/** The inputs that are asked now. */\n\t\tshownFields() {\n\t\t\treturn this.fields.filter((field) => !field.hidden)\n\t\t},\n\n\t\t/** Whether the summary block shows. */\n\t\tsummaryShown() {\n\t\t\tif (!this.summary || typeof this.summary !== 'object') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !this.summary.when || Boolean(readPath(this.context, this.summary.when))\n\t\t},\n\n\t\t/** The summary card's second line. */\n\t\tcardMeta() {\n\t\t\tconst meta = Array.isArray(this.summary?.card?.meta) ? this.summary.card.meta : []\n\t\t\treturn meta.map((path) => this.contextText(path)).filter(Boolean).join(' · ')\n\t\t},\n\n\t\t/** The refusal's field keys, normalised to strings. */\n\t\trefusedKeys() {\n\t\t\tif (!Array.isArray(this.fieldErrors)) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn this.fieldErrors.filter((key) => typeof key === 'string' && key !== '')\n\t\t},\n\n\t\t/** The refused keys this form offers no field for. */\n\t\tunofferedRefusals() {\n\t\t\tconst offered = this.fields.map((field) => field.key)\n\t\t\treturn this.refusedKeys.filter((key) => !offered.includes(key))\n\t\t},\n\t},\n\n\twatch: {\n\t\tmodelValue(values) {\n\t\t\tthis.latest = { ...values }\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A context value as text, '' when absent.\n\t\t *\n\t\t * @param {string} path Dot path into the context.\n\t\t * @return {string}\n\t\t */\n\t\tcontextText(path) {\n\t\t\tif (!path) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst value = readPath(this.context, path)\n\t\t\treturn value === null || value === undefined ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * The test id of one part of the summary.\n\t\t *\n\t\t * @param {string} part `card` or `facts`.\n\t\t * @return {string}\n\t\t */\n\t\tsummaryTestid(part) {\n\t\t\treturn `${this.summary.testid || 'cn-transition-input-summary'}-${part}`\n\t\t},\n\n\t\t/**\n\t\t * The field's label, with the required marker when asked for.\n\t\t *\n\t\t * @param {object} field The descriptor.\n\t\t * @return {string}\n\t\t */\n\t\tlabelOf(field) {\n\t\t\treturn this.markRequired && field.required ? `${field.label} *` : field.label\n\t\t},\n\n\t\t/**\n\t\t * Label of a sub-field, with the required marker.\n\t\t *\n\t\t * @param {object} sub The sub-field descriptor.\n\t\t * @return {string}\n\t\t */\n\t\tsubLabel(sub) {\n\t\t\treturn this.markRequired && sub.required ? `${sub.label} *` : sub.label\n\t\t},\n\n\t\t/**\n\t\t * The element id of a text input: the declared one, or one unique to\n\t\t * this form.\n\t\t *\n\t\t * @param {object} field The descriptor.\n\t\t * @return {string}\n\t\t */\n\t\tinputId(field) {\n\t\t\treturn field.input.id || `cn-transition-input-${this.uid}-${field.key}`\n\t\t},\n\n\t\t/**\n\t\t * The native input type of a one-line input.\n\t\t *\n\t\t * @param {object} field The descriptor.\n\t\t * @return {string}\n\t\t */\n\t\ttextType(field) {\n\t\t\treturn field.widget === 'number' || field.widget === 'date' ? field.widget : 'text'\n\t\t},\n\n\t\t/**\n\t\t * The option a picker currently holds, or null.\n\t\t *\n\t\t * @param {object} field The select descriptor.\n\t\t * @return {{value: string, label: string}|null}\n\t\t */\n\t\tselectedOption(field) {\n\t\t\tconst value = this.modelValue[field.key]\n\t\t\treturn field.options.find((option) => option.value === String(value ?? '')) || null\n\t\t},\n\n\t\t/**\n\t\t * Ids a reference picker must not offer: the current record, when the\n\t\t * input's `picker.excludeSelf` says so.\n\t\t *\n\t\t * @param {object} field The reference descriptor.\n\t\t * @return {string[]}\n\t\t */\n\t\texcludedIds(field) {\n\t\t\tif (!field.picker || field.picker.excludeSelf !== true || !this.currentObject) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst self = this.currentObject\n\t\t\treturn [self.id, self.uuid, self['@self'] && self['@self'].id].filter((id) => id !== undefined && id !== null).map(String)\n\t\t},\n\n\t\t/**\n\t\t * Whether the refusal named this field.\n\t\t *\n\t\t * @param {string} key The field key.\n\t\t * @return {boolean}\n\t\t */\n\t\tisRefused(key) {\n\t\t\treturn this.refusedKeys.includes(key)\n\t\t},\n\n\t\t/**\n\t\t * What to say beside a refused field. An empty one is a missing input;\n\t\t * a filled one was refused for what is in it. The kind is decided here\n\t\t * rather than read out of the refusal's sentence, which may be reworded.\n\t\t *\n\t\t * @param {object} field The descriptor.\n\t\t * @return {string}\n\t\t */\n\t\trefusalFor(field) {\n\t\t\treturn isInputFilled(field, this.modelValue)\n\t\t\t\t? t('nextcloud-vue', 'This value was not accepted.')\n\t\t\t\t: t('nextcloud-vue', 'This field is required.')\n\t\t},\n\n\t\t/**\n\t\t * Whether a refusal named `<input>.<sub>`.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @return {boolean}\n\t\t */\n\t\tisSubRefused(key, sub) {\n\t\t\treturn this.refusedKeys.includes(`${key}.${sub}`)\n\t\t},\n\n\t\t/**\n\t\t * A typed sub-value.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @return {unknown}\n\t\t */\n\t\tsubValue(key, sub) {\n\t\t\tconst group = this.modelValue[key]\n\t\t\treturn group && typeof group === 'object' ? group[sub] : undefined\n\t\t},\n\n\t\t/**\n\t\t * Store one sub-value, keeping the rest of the object input's values.\n\t\t *\n\t\t * @param {string} key The input key.\n\t\t * @param {string} sub The sub-field key.\n\t\t * @param {unknown} value The new value.\n\t\t */\n\t\tsetSubValue(key, sub, value) {\n\t\t\tconst group = this.latest[key] && typeof this.latest[key] === 'object' ? this.latest[key] : {}\n\t\t\tthis.setValue(key, { ...group, [sub]: value })\n\t\t},\n\n\t\t/**\n\t\t * Store one input's value.\n\t\t *\n\t\t * @param {string} key The field key.\n\t\t * @param {unknown} value The new value.\n\t\t */\n\t\tsetValue(key, value) {\n\t\t\tthis.latest = { ...this.latest, [key]: value }\n\t\t\t/**\n\t\t\t * @event update:modelValue The values with this one changed.\n\t\t\t * @type {object}\n\t\t\t */\n\t\t\tthis.$emit('update:modelValue', this.latest)\n\t\t},\n\n\t\t/**\n\t\t * Put a chosen template's text into the input it fills, unless that\n\t\t * input already holds text.\n\t\t *\n\t\t * @param {object} field The template descriptor.\n\t\t * @param {object|null} option The chosen template.\n\t\t */\n\t\tapplyTemplate(field, option) {\n\t\t\tconst next = applyTemplateText(this.latest, field.input.applyTo, option)\n\t\t\tif (next !== this.latest) {\n\t\t\t\tthis.latest = next\n\t\t\t\t/** @event update:modelValue The values with the template's text filled in. */\n\t\t\t\tthis.$emit('update:modelValue', next)\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-transition-input-fields {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-transition-input-fields--columns {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, minmax(0, 1fr));\n\talign-items: start;\n}\n\n.cn-transition-input-fields--columns .cn-transition-input-fields__wide {\n\tgrid-column: 1 / -1;\n}\n\n.cn-transition-input__field,\n.cn-transition-input-fields__preview {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-transition-input__label {\n\tdisplay: block;\n\tmargin-bottom: 4px;\n}\n\n.cn-transition-input-fields__label {\n\tfont-size: 14px;\n\tfont-weight: 600;\n}\n\n.cn-transition-input-fields__muted {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-transition-input__field-error {\n\tmargin: 4px 0 0;\n\tfont-size: 0.9em;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n\n.cn-transition-input__field--refused {\n\tborder-inline-start: 2px solid var(--color-error);\n\tpadding-inline-start: 8px;\n}\n\n.cn-transition-input__object {\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\tpadding: 8px 12px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-transition-input-fields__card {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 14px;\n\tpadding: 14px 16px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-transition-input-fields__card-icon {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-transition-input-fields__card-text {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-transition-input-fields__badge {\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tbackground: var(--color-success-light, var(--color-background-dark));\n\tcolor: var(--color-success-text);\n\tfont-size: 13px;\n\tfont-weight: 600;\n}\n\n.cn-transition-input-fields__section-title {\n\tmargin: 0 0 8px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n}\n\n.cn-transition-input-fields__facts {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, minmax(0, 1fr));\n\tgap: 0 24px;\n\tmargin: 0;\n}\n\n.cn-transition-input-fields__facts > div {\n\tpadding: 10px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-transition-input-fields__facts dt {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-transition-input-fields__facts dd {\n\tmargin: 2px 0 0;\n\tfont-size: 15px;\n\tfont-weight: 600;\n}\n</style>\n"],"names":["_normalizeClass","_createElementBlock","_Fragment","_openBlock","_createBlock","_resolveDynamicComponent","_createElementVNode","_toDisplayString","_renderList","_createTextVNode"],"mappings":";;;AAoBU,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,uCAAuC,GAAA;AAE7C,MAAA,UAAA,GAAA,EAAA,KAAA,EAAA,mCAAA,GAAA;;;AAEwC,EAAA,KAAI,EAAC,mCAAmB;;;;;AAO7C,EAAA,KAAK,EAAC,2CAAmC;;AAG9D,MAAA,UAAA,GAAA,EAAA,KAAE,EAAA,mCAAA,GAAA;;;;AAwCmC,EAAA,KAAA,EAAA,gCAAA;;AACjC,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,4BAA4B,GAAA;;;AAgBJ,EAAA,KAAA,EAAA,6BAAA;;;;;;;;;;;AAmFhC,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,mCAAA,GAAA;;;;AAEE,EAAA,KAAA,EAAA,mCAAA;;;;;;;;;;;;;;IAtKR,KAAG,EAAAA,cAAA,CAAA,CAAC,4BAA4B,EAAA,EAAA,qCAAA,EACI,MAAA,CAAA,OAAA,KAAA,CAAA,EAAA,CAAA,CAAA;;KACtB,QAAY,CAAA,YAAA;sBAA1BC,kBA6BS,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;AA5BC,UAAA,CAAA,MAAA,CAAA,OAAO,CAAC,IAAI;8CAcjB,CAAA,KAAA,EAAA;;AAbJ,gBAAA,KAAI,EAAC,mEAAI;AACT,gBAAA,aAAW,EAAE,QAAa,CAAA,aAAA,CAAA,MAAA,CAAA;;iBAEpB,MAAO,CAAA,OAAA,CAAC,IAAI,CAAC,IAAI;AADxB,qBAAAC,SAAA,EAAA,EAAAC,WAAA,CAGMC,uBAHU,CAAA,MAAA,CAAA,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA,EAAA;;AAE/B,sBAAA,IAAG,EAAG,EAAE;AACT,sBAAA,KAAK,EAAA,uCAAA;;;AACN,gBAAAC,kBAAA,CAGI,QAHJ,UAGI,EAAA;AAFH,kBAAAA,kBAAA,CAAoC,gCAAzB,QAAW,CAAA,WAAA,CAAC,cAAO,CAAC,IAAI,CAAC,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;kBACpCA,kBAAK,CAAA,MAAA,EAAL,UAAK,EAAAC,eAAA,CAAA,QAAA,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;;AAEM,gBAAA,CAAA,QAAA,CAAA,WAAW,CAAC,MAAA,CAAA,OAAO,CAAC,IAAI,CAAC,KAAM,CAAA;kCAA3CN,kBAEO,CAAA,MAAA,EAFP,UAEO,EADHM,eAAA,CAAA,QAAA,CAAA,WAAW,CAAC,MAAO,CAAA,OAAA,CAAC,IAAI,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,YAAA;;;;WAGpB,KAAK,CAAA,OAAA,CAAA,MAAA,CAAA,OAAA,CAAA,KAAA,CAAA,IAAA,MAAA,CAAA,OAAA,CAAA,KAAA,CAAA,MAAA,GAAA,CAAA;4BAAlBN,kBAYC,CAAA,SAAA,EAAA;;AAXF,gBAAA,KAAI,EAAA,kCAAA;AACH,gBAAA,aAAW,EAAE,QAAa,CAAA,aAAA,CAAA,OAAA,CAAA;;AACjB,gBAAA,CAAA,MAAA,CAAA,QAAQ,KAAK;qDAElB,gBAAA,EADDM,eAAA,CAAA,MAAA,CAAA,OAAO,CAAC,KAAK,CAAA,EAAA,CAAA,YAAA;;mCAOZ,gBAAA,EAAA;AAJJ,mBAAAJ,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA,SAAG,EAAA,IAAA,EAAAO,UAAA,CAAA,MAAA,CAAA,OAAA,CAAA,KAAA,GAAA,IAAA,KAAA;yCAAHP;AAAG,sBAAA,GAAA,EAAA,IAAA,CAAA,IAAA,IAAA,IAAA,CAAA,KAAA;;sBACFK,kBAAM,CAAA,IAAA,EAAA,IAAA,EAAAC,eAAA,CAAA,IAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;sBACND,kBAAM,CAAA,IAAA,EAAA,IAAA,EAAAC,eAAA,CAAA,oBAAA,CAAA,IAAA,CAAA,IAAA,CAAA,IAAA,IAAA,CAAA,QAAA,IAAA,EAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;wCA+IC,CAAAL,QAAA,EAAA,IAAA,EAAAM,UAAA,CAzIe,QAAW,CAAA,WAAA,EAAA,CAApB,KAAK,KAAA;;AAAuB,QAAA,GAAA,EAAA,KAAK,CAAC,GAAG;;0BA2H/C,CAAA,KAAA,EAAA;AAzHL,UAAA,KAAC,kBAAA,4BAAA,EAAA;4CACgD,QAAA,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,CAAA;yCAAA,KAAA,CAAA,KAAA,CAAA,IAAA,KAAA,IAAA;;UAIhD,aAAW,EAAA,CAAA,oBAAA,EAAsB,KAAA,CAAA,GAAA,CAAA,CAAA;;AAEV,UAAA,CAAA,KAAK,CAAC,MAAI,KAAA,UAAA;4BAAjCJ,WAQkC,CAAA,2BAAA,EAAA;;AAPjC,gBAAA,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,IAAA,EAAA;AACpB,gBAAA,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,IAAA,EAAA;AAC1B,gBAAA,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,IAAA,EAAA;AAC1B,gBAAA,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,SAAS;;AAEhC,gBAAA,WAAY,EAAC,KAAK,CAAC,KAAK,CAAE,WAAU,IAAA,EAAA;gBACpC,aAAW,EAAE,KAAK,CAAC,KAAK,CAAC,MAAK,IAAA,CAAA,6BAAA,EAAc,KAAA,CAAA,GAAA,CAAA,CAAA;AAC5C,gBAAA,OAAK,EAAE,MAAA,KAAA,QAAA,CAAA,aAAa,CAAC,KAAK,EAAE,MAAK,CAAA,CAAA;;AAGd,cAAA,CAAA,KAAK,CAAC,MAAC,KAAA,QAAA;yCAQ0C,CAAA,mBAAA,EAAA;;kBAPpE,UAAU,EAAE,QAAc,CAAA,cAAA,CAAA,KAAA,CAAA;kBAC1B,OAAO,EAAE,KAAK,CAAC,OAAG;AACnB,kBAAA,KAAK,EAAC,OAAO;kBACZ,UAAU,EAAE,QAAO,CAAA,OAAA,CAAC,KAAK,CAAA;;AAEzB,kBAAA,QAAQ,EAAE,MAAQ,CAAA,QAAA;kBAClB,aAAW,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,IAAA,CAAA,2BAAA,EAAkC,KAAK,CAAC,GAAG,CAAA,CAAA;AAC1E,kBAAA,qBAAiB,aAAE,QAAQ,CAAA,QAAA,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,SAAE,GAAA,MAAA,CAAA,KAAA,GAAA,EAAA,CAAA,CAAA;;AAGtD,gBAAA,CAAA,KAAK,CAAC,MAAM,KAAA,WAAA;AAA1B,mBAAAD,SAAA,EAAA,EAAAF,kBAAA,CAcI,OAdJ,UAcI,EAAA;AAbJ,oBAAAK,kBAAA,CAAqE,OAArE,EAAA,WAAqE,EAAzBC,eAAA,CAAA,QAAA,CAAA,OAAO,CAAC,KAAM,CAAA,CAAA,EAAA,CAAA,YAAA;+BAYP,CAAA,2BAAA,EAAA;sBAVlD,QAAQ,EAAE,KAAK,CAAC,iBAAW;AAC3B,sBAAA,MAAM,EAAE,MAAM,CAAC,KAAG,CAAA,SAAA,CAAA,MAAA,CAAA;AAClB,sBAAA,UAAU,EAAG,CAAA,KAAA,CAAA,MAAA,IAAA,KAAA,CAAA,MAAA,CAAA,UAAA,KAAA,KAAA,CAAA,SAAA,CAAA,UAAA,IAAA,MAAA;sBACb,MAAM,EAAA,CAAG,KAAK,CAAC,MAAM,IAAI,KAAC,CAAA,MAAA,CAAA,MAAA,KAAA,EAAA;sBAC1B,OAAO,EAAE,QAAW,CAAA,WAAA,CAAC,KAAK,CAAA;AAC1B,sBAAA,WAAW,EAAE,KAAK;AAClB,sBAAA,OAAO,EAAE,IAAI;sBACb,UAAE,EAAA,QAAA,CAAA,OAAA,CAAA,KAAA,CAAA;;sBAEF,aAAY,EAAA,CAAA,2BAAA,EAA+B,KAAI,CAAE,GAAG,CAAA,CAAA;AACpD,sBAAA,qBAAiB,aAAE,QAAQ,CAAA,QAAA,CAAC,KAAK,CAAE,GAAE,EAAE,MAAM,CAAA,CAAA;;;AAI3B,kBAAA,CAAA,KAAK,CAAC,MAAM,KAAA,QAAA;AAA/B,qBAAAJ,SAAA,EAAA,EAAAF,kBAAA,CA4BS,YA5BT,WA4BS,EAAA;wCA3B2B,CAAA,QAAA,EAAA,IAAA,EAAAM,eAAA,CAA1B,QAAO,CAAA,OAAA,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,YAAA;AACvB,uBAAAJ,SAAA,CAAA,IAAA,CAAA,EAAAF,kBAAA,CAyBKC,QAzBa,EAAA,IAAA,EAAAM,UAAA,CAAA,KAAK,CAAC,SAAS,GAAvB,GAAI,KAAA;6CAAdP,kBAyBK,CAAA,KAAA,EAAA;0BAxBJ,GAAG,EAAE,GAAG,CAAC,GAAG;AACZ,0BAAA,KAAI,EAAC,+BAAgB;AACrB,0BAAA,aAAO,yBAAA,KAAA,CAAA,GAAA,CAAA,CAAA,EAAA,GAAA,CAAA,GAAA,CAAA,CAAA;;AACU,0BAAA,CAAA,GAAG,CAAC,MAAM,KAAA,UAAA;uDAIoC,CAAA,qBAAA,EAAA;;gCAH9D,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAA,QAAA,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,GAAI,CAAA,IAAA,EAAA,CAAA;gCAC/C,KAAK,EAAE,QAAQ,CAAA,QAAA,CAAC,GAAG,CAAA;AACpB,gCAAA,IAAI,EAAC,GAAG;gCACP,qBAAiB,EAAA,MAAA,KAAE,QAAW,CAAA,WAAA,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,MAAO,CAAA,CAAA;;AACzC,8BAAA,CAAA,GAAA,CAAA,MAAA,KAAA,UAAA;8CAAlBG,WAKqB,CAAA,gCAAA,EAAA;;kCAJpB,UAAU,EAAE,iBAAQ,CAAC,KAAA,CAAA,GAAA,EAAA,GAAA,CAAA,GAAA,CAAA,KAAA,IAAA;AACtB,kCAAA,IAAI,EAAC,QAAQ;kCACZ,qBAAiB,EAAA,MAAA,KAAE,QAAW,CAAA,WAAA,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,MAAG,KAAA,IAAA,CAAA,CAAA;;mDACvD,MAAmB;AAAhB,oCAAAK,eAAA,CAAAF,eAAA,CAAA,QAAA,CAAA,QAAQ,CAAC,GAAG,CAAA,CAAA,EAAA,CAAA,YAAA;;;;yDAMwC,CAAA,sBAAA,EAAA;;4CAH5C,EAAE,MAAM,CAAC,QAAQ,CAAA,QAAA,CAAC,KAAK,CAAC,GAAG,EAAE,GAAA,CAAA,GAAA,CAAA,IAAA,EAAA,CAAA;kCACvC,IAAI,EAAE,GAAG,CAAC,MAAM,KAAA,QAAA,GAAA,QAAA,GAAA,MAAA;kCAChB,KAAK,EAAE,QAAQ,CAAA,QAAA,CAAC,GAAG,CAAA;kCACnB,qBAAiB,EAAA,MAAA,KAAE,QAAW,CAAA,WAAA,CAAC,KAAI,CAAE,GAAE,EAAG,GAAG,CAAC,GAAG,EAAE,MAAG,CAAA,CAAA;;AACrD,0BAAA,CAAA,QAAA,CAAA,YAAA,CAAA,KAAA,CAAA,GAAA,EAAA,GAAA,CAAA,GAAA,CAAA;4CAAHN,kBAII,CAAA,GAAA,EAAA;;AAHH,gCAAA,KAAG,EAAA,kCAAA;AACF,gCAAA,aAAM,+BAAA,KAAA,CAAA,GAAA,CAAA,CAAA,EAAA,GAAA,CAAA,GAAA,CAAA,CAAA;;;;;;AAMwB,oBAAA,CAAA,KAAK,CAAA,MAAO,KAAA,UAAA;+CAMtB,CAAA,gCAAA,EAAA;;AALtB,wBAAA,UAAU,EAAE,MAAA,CAAA,UAAM,CAAA,KAAA,CAAA,GAAA,CAAA,KAAA,IAAA;AACnB,wBAAA,IAAI,EAAC,QAAQ;;AAEZ,wBAAA,qBAAc,aAAA,QAAA,CAAA,QAAA,CAAA,KAAA,CAAA,GAAA,EAAA,MAAA,KAAA,IAAA,CAAA,CAAA;;yCACf,MAAoB;AAAjB,0BAAAQ,eAAA,CAAAF,eAAA,CAAA,QAAA,CAAA,OAAO,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,YAAA;;;;oCAGfN,kBA8BS,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;yBA3BG,KAAK,CAAC,KAAC,CAAA,YAAA,KAAA,IAAA;0CAAnBD,kBAEsB,CAAA,OAAA,EAAA;;AADtB,8BAAA,KAAK,EAAC,mCAAkC;8BACvC,GAAG,EAAE,QAAO,CAAA,OAAA,CAAC,KAAK,CAAA;AAAG,6BAAA,EAAAM,eAAA,CAAA,QAAA,CAAA,OAAA,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,oBAAA,WAAA,CAAA;;AACL,wBAAA,CAAA,KAAK,CAAC,MAAM,KAAA,UAAA;qDAUP,CAAA,qBAAA,EAAA;;8BATrB,EAAE,EAAE,QAAO,CAAA,OAAA,CAAC,KAAK,CAAA;AACjB,8BAAA,UAAU,EAAE,MAAM,CAAC,iBAAQ,CAAA,KAAA,CAAA,GAAA,CAAA,IAAA,EAAA,CAAA;8BAC3B,KAAK,EAAE,QAAO,CAAA,OAAA,CAAC,KAAG,CAAA;AAClB,8BAAA,YAAY,EAAE,KAAC,CAAA,KAAA,CAAA,YAAA,KAAA,IAAA;8BACf,UAAU,EAAE,KAAK,CAAC,WAAW,IAAA,EAAA;AAC7B,8BAAA,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,IAAA,CAAA;AACtB,8BAAA,QAAQ,EAAG,MAAK,CAAA,QAAA;AACjB,8BAAA,MAAM,EAAC,UAAU;AAChB,8BAAA,aAAW,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,IAAA,IAAA;AAC/B,8BAAA,qBAAiB,aAAE,QAAE,CAAA,QAAA,CAAA,KAAA,CAAA,GAAA,EAAA,MAAA,CAAA,CAAA;;qDAUd,CAAA,sBAAA,EAAA;;8BARP,EAAE,EAAE,QAAO,CAAA,OAAA,CAAC,KAAK,CAAA;AACjB,8BAAA,UAAU,EAAE,MAAM,CAAC,iBAAS,CAAE,KAAK,CAAA,GAAA,CAAA,IAAA,EAAA,CAAA;8BACnC,IAAI,EAAE,QAAQ,CAAA,QAAA,CAAC,KAAG,CAAA;8BAClB,KAAK,EAAE,QAAO,CAAA,OAAA,CAAC,KAAK,CAAA;AACpB,8BAAA,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,YAAW,KAAA,IAAA;8BACrC,UAAU,EAAE,KAAK,CAAC,WAAW,IAAA,EAAA;AAC7B,8BAAA,QAAQ,EAAE;AACV,8BAAA,aAAI,EAAA,KAAA,CAAA,KAAA,CAAA,MAAA,IAAA,IAAA;AACJ,8BAAA,qBAAO,aAAA,QAAA,CAAA,QAAA,CAAA,KAAA,CAAA,GAAA,EAAA,MAAA,CAAA,CAAA;;;6DAGF,mBAAA,EAAAA,eAAA,CADH,KAAK,CAAC,KAAK,CAAC,IAAI,CAAA,EAAA,CAAA,YAAA;;;WAIlB,QAAA,CAAA,SAAA,CAAA,KAAA,CAAA,GAAA,CAAA;4BAAHN,kBAII,CAAA,GAAA,EAAA;;AAHH,gBAAA,KAAG,EAAA,kCAAA;;AAEA,eAAA,EAAAM,eAAA,CAAA,QAAA,CAAA,UAAU,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,oBAAA,WAAA,CAAA;;;AAMV,QAAA,CAAA,KAAK,CAAC,WAAW;0BAA3BN,kBASK,CAAA,KAAA,EAAA;cARJ,GAAG,EAAA,CAAA,EAAK,KAAK,CAAC,GAAG,CAAA,QAAA,CAAA;AAClB,cAAA,KAAI,EAAE,sEAAsE;cAC3E,aAAW,EAAE,KAAK,CAAC,KAAK,CAAC,OAAI,CAAA,MAAA,IAAA,CAAA,4BAAA,EAAA,KAAA,CAAA,GAAA,CAAA,CAAA;;cAC9BK,kBAAM,CAAA,MAAA,EAAN,WAAM,EAAAC,eAAA,CAAA,KAAA,CAAA,KAAA,CAAA,OAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;cACND,kBAAI,CAAA,MAAA,EAAA;gBAAA,aAAA,EAAA,CAAA,EAAA,KAAA,CAAA,KAAA,CAAA,OAAA,CAAA,MAAA,IAAA,CAAA,4BAAA,EAAA,KAAA,CAAA,GAAA,CAAA,CAAA,CAAA,MAAA,CAAA;AAAA,eAAA,EAAAC,eAAA,CAAA,KAAA,CAAA,WAAA,CAAA,EAAA,CAAA,oBAAA,WAAA,CAAA;AACI,cAAA,CAAA,KAAA,CAAA,KAAA,CAAA,OAAA,CAAA,IAAA;gCAARN,kBAEO,CAAA,MAAA,EAFP,WAEO;;;;;;KAIQ,MAAA,CAAA,MAAA,IAAA,MAAA,CAAA,MAAA,CAAA,IAAA;sBAAhBG,WAKY,CAAA,qBAAA,EAAA;;AAJZ,UAAA,KAAK,EAAC,kCAAK;;UAEV,OAAO,EAAE,MAAM,CAAA,MAAA,CAAC,OAAO,IAAA,EAAA;;iCACR;yDAAR,CAAE,IAAI,CAAA,EAAA,CAAA,YAAA;;;;;sBAMdH,8CAAgB,QAAiB,CAAA,iBAAA,EAAA,CAAxB,GAAG,KAAA;2BAAZA;AACC,QAAA,GAAC,eAAA,GAAA,CAAA,CAAA;AACF,QAAA,KAAG,EAAA,kCAAA;;;;;;;;;"}
@@ -1,5 +1,6 @@
1
1
  import { subscribe, unsubscribe } from '@nextcloud/event-bus';
2
2
  import { ref, computed, watch, getCurrentScope, onScopeDispose, unref } from 'vue';
3
+ import { interpolateUrlTokens } from '../utils/interpolateUrlTokens.js';
3
4
  import { resolveFilterTokens, dropOptionalUnresolved, hasUnresolvedTokens } from '../utils/resolveFilterTokens.js';
4
5
 
5
6
  /**
@@ -106,42 +107,6 @@ function getByPath(obj, path) {
106
107
  )
107
108
  }
108
109
 
109
- /**
110
- * Interpolate `@page.<key>` / `@workspace.<key>` / `@config.<key>` /
111
- * `@objectId` / `@object.<field>` tokens inside a URL string against the
112
- * token context. `@page.*` is an alias for `@workspace.*` (both read the
113
- * page-level workspace context). Unresolved tokens collapse to an empty
114
- * string so a half-built URL never sends a literal `@page.period`.
115
- *
116
- * @param {string} str The raw URL (or any string) to interpolate.
117
- * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object, range?: object}} [ctx] The token context.
118
- * @return {string} The interpolated string.
119
- */
120
- function interpolateUrlTokens(str, ctx) {
121
- if (typeof str !== 'string') {
122
- return str
123
- }
124
- const c = ctx || {};
125
- const workspace = c.workspace || {};
126
- const config = c.config || {};
127
- return str.replace(/@(page|workspace)\.([A-Za-z0-9_]+)/g, (_, _ns, key) => {
128
- const v = workspace[key];
129
- return (v === undefined || v === null) ? '' : String(v)
130
- }).replace(/@config\.([A-Za-z0-9_]+)/g, (_, key) => {
131
- const v = config[key];
132
- return (v === undefined || v === null) ? '' : String(v)
133
- }).replace(/@range\.([A-Za-z0-9_]+)/g, (_, key) => {
134
- const v = c.range && c.range[key];
135
- return (v === undefined || v === null) ? '' : String(v)
136
- }).replace(/@objectId/g, () => {
137
- const id = c.objectId;
138
- return (id === undefined || id === null) ? '' : String(id)
139
- }).replace(/@object\.([A-Za-z0-9_]+)/g, (_, field) => {
140
- const v = c.object && c.object[field];
141
- return (v === undefined || v === null) ? '' : String(v)
142
- })
143
- }
144
-
145
110
  /**
146
111
  * Resolve an `endpointSource` config against a token context into a concrete
147
112
  * request descriptor. `params` run through the SAME `resolveFilterTokens`
@@ -1 +1 @@
1
- {"version":3,"file":"useEndpointSource.js","sources":["../../../src/composables/useEndpointSource.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * useEndpointSource — ONE coherent endpoint data binding for the abstract\n * widgets (stat / delta / chart / object-table). A manifest-authored\n * `endpointSource` block reads an arbitrary app REST endpoint (a bespoke\n * analytics controller, a summary aggregation OpenRegister can't express)\n * and hands the widget the payload at a dot-path of the response:\n *\n * ```js\n * endpointSource: {\n * url: '/apps/pipelinq/api/analytics/overview', // app-relative (generateUrl) or absolute path\n * method: 'GET', // 'GET' (default) | 'POST' (params become the JSON body)\n * params: { period: '@workspace.datePreset?' }, // SAME token grammar as widget filters\n * responsePath: 'summary', // dot-path pluck of the payload (default: whole body)\n * }\n * ```\n *\n * `params` values pass through the SAME token resolution widget filters use\n * (`resolveFilterTokens`): `@me`, `@today` / `@today±Nd`, `@monthStart`,\n * `@workspace.<key>` / `@config.<key>` (with the trailing-`?` OPTIONAL\n * convention — an unresolved optional param is dropped, an unresolved\n * REQUIRED one blocks the fetch), `@objectId` / `@object.<field>` on detail\n * pages. The `url` itself may interpolate `@page.*` / `@workspace.*` /\n * `@config.*` / `@objectId` / `@object.*` tokens inline (unresolved URL\n * tokens collapse to an empty string so a literal `@page.period` never hits\n * the wire).\n *\n * Requests are SHARED: one in-flight promise + short-TTL cache entry per\n * `(method, url, resolved params)` — the same per-period caching semantics\n * pipelinq's `dashboardData.js` used, so four KPI tiles reading the same\n * overview endpoint issue ONE request per render pass. `responsePath`\n * plucking happens per subscriber, after the shared response resolves.\n *\n * Refresh signal — grounded in the library's own event-bus channels (the\n * mechanism `CnActionsMenu` broadcasts on): the composable subscribes to\n * `cn:page:refresh` (the page-level Refresh action → every endpoint source\n * force-refetches past the cache) and, when a `widgetId` option is given,\n * to `cn:widget:refresh` with a matching `widgetId` payload (the per-widget\n * Refresh action). App-LOCAL refresh signals (e.g. a `Vue.observable` token\n * like pipelinq's `refreshDashboardData()`) are not observable from the\n * library — for those, pass the reactive token as the `refreshKey` option\n * and bump it; every bump force-refetches.\n *\n * @module composables/useEndpointSource\n */\n\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { computed, getCurrentScope, onScopeDispose, ref, unref, watch } from 'vue'\nimport {\n\tdropOptionalUnresolved,\n\thasUnresolvedTokens,\n\tresolveFilterTokens,\n} from '../utils/resolveFilterTokens.js'\n\n/**\n * Cache TTL for shared endpoint responses — 5 minutes, matching the\n * per-period dashboard cache the fleet apps used (pipelinq dashboardData.js).\n *\n * @type {number}\n */\nexport const ENDPOINT_SOURCE_TTL_MS = 5 * 60 * 1000\n\n/**\n * Minimum time a FORCED refetch (a Refresh action, a `refreshKey` bump) keeps\n * `loading` true. A refresh against a fast endpoint settles in a few\n * milliseconds — too briefly for the widget's loading state to be perceived,\n * so the click reads as having done nothing. Only the loading FLAG is held;\n * the fresh data lands the moment the response arrives. Initial and\n * signature-change loads are not held — first paint should never wait.\n *\n * @type {number}\n */\nexport const MIN_FORCED_LOADING_MS = 400\n\n/** Event-bus channel the page-level Refresh action broadcasts on. */\nconst PAGE_REFRESH_CHANNEL = 'cn:page:refresh'\n\n/** Event-bus channel the per-widget Refresh action broadcasts on. */\nconst WIDGET_REFRESH_CHANNEL = 'cn:widget:refresh'\n\n/**\n * Module-level response cache: cacheKey → `{ promise, timestamp }`.\n * Shared across every widget instance in the page so identical requests\n * dedupe to one in-flight promise (pipelinq `cached()` semantics: an\n * errored fetch drops its entry so the next mount retries).\n *\n * @type {Map<string, {promise: Promise<unknown>, timestamp: number}>}\n */\nconst responseCache = new Map()\n\n/**\n * Read a dot-path off an object (e.g. `\"data.totalLeads\"`, `\"series.0.value\"`).\n * Returns the object itself for an empty path and `undefined` when any\n * segment is missing.\n *\n * @param {unknown} obj The source object.\n * @param {string} [path] The dot-path.\n * @return {unknown} The resolved value or undefined.\n */\nexport function getByPath(obj, path) {\n\tif (path === undefined || path === null || path === '') {\n\t\treturn obj\n\t}\n\treturn String(path).split('.').reduce(\n\t\t(o, k) => (o === null || o === undefined ? undefined : o[k]),\n\t\tobj,\n\t)\n}\n\n/**\n * Interpolate `@page.<key>` / `@workspace.<key>` / `@config.<key>` /\n * `@objectId` / `@object.<field>` tokens inside a URL string against the\n * token context. `@page.*` is an alias for `@workspace.*` (both read the\n * page-level workspace context). Unresolved tokens collapse to an empty\n * string so a half-built URL never sends a literal `@page.period`.\n *\n * @param {string} str The raw URL (or any string) to interpolate.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object, range?: object}} [ctx] The token context.\n * @return {string} The interpolated string.\n */\nexport function interpolateUrlTokens(str, ctx) {\n\tif (typeof str !== 'string') {\n\t\treturn str\n\t}\n\tconst c = ctx || {}\n\tconst workspace = c.workspace || {}\n\tconst config = c.config || {}\n\treturn str.replace(/@(page|workspace)\\.([A-Za-z0-9_]+)/g, (_, _ns, key) => {\n\t\tconst v = workspace[key]\n\t\treturn (v === undefined || v === null) ? '' : String(v)\n\t}).replace(/@config\\.([A-Za-z0-9_]+)/g, (_, key) => {\n\t\tconst v = config[key]\n\t\treturn (v === undefined || v === null) ? '' : String(v)\n\t}).replace(/@range\\.([A-Za-z0-9_]+)/g, (_, key) => {\n\t\tconst v = c.range && c.range[key]\n\t\treturn (v === undefined || v === null) ? '' : String(v)\n\t}).replace(/@objectId/g, () => {\n\t\tconst id = c.objectId\n\t\treturn (id === undefined || id === null) ? '' : String(id)\n\t}).replace(/@object\\.([A-Za-z0-9_]+)/g, (_, field) => {\n\t\tconst v = c.object && c.object[field]\n\t\treturn (v === undefined || v === null) ? '' : String(v)\n\t})\n}\n\n/**\n * Resolve an `endpointSource` config against a token context into a concrete\n * request descriptor. `params` run through the SAME `resolveFilterTokens`\n * grammar widget filters use; optional (`…?`) tokens that stay unresolved are\n * dropped, and a REQUIRED token that stays unresolved marks the request\n * `blocked` (the page context it depends on isn't set yet — callers skip the\n * fetch instead of sending a literal `@workspace.…`).\n *\n * @param {{url: string, method?: string, params?: object}} config The endpointSource block.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object, range?: object}} [ctx] The token context.\n * @return {{url: string, method: ('GET'|'POST'), params: object, blocked: boolean, responsePath: string}} The resolved request.\n */\nexport function resolveEndpointRequest(config, ctx) {\n\tconst cfg = config || {}\n\tconst url = interpolateUrlTokens(cfg.url || '', ctx)\n\tconst resolved = resolveFilterTokens(cfg.params || {}, ctx)\n\tconst params = dropOptionalUnresolved(resolved)\n\tconst method = String(cfg.method || 'GET').toUpperCase() === 'POST' ? 'POST' : 'GET'\n\tconst responsePath = resolveResponsePath(cfg.responsePath, ctx)\n\tconst blocked = hasUnresolvedTokens(params) || hasEmptyPathSegment(cfg.url || '', url) || responsePath === null\n\treturn { url, method, params, blocked, responsePath: responsePath || '' }\n}\n\n/**\n * Resolve the tokens in a `responsePath` (`phaseDays.@workspace.measure`), so a\n * page control can choose which part of one response a widget reads. Null when\n * a token resolved to nothing and left an empty path segment: the read waits\n * instead of plucking the wrong part.\n *\n * @param {string|undefined} path The configured path.\n * @param {object} [ctx] The token context.\n * @return {string|null} The resolved path, '' for none, null when blocked.\n */\nfunction resolveResponsePath(path, ctx) {\n\tif (typeof path !== 'string' || path === '') {\n\t\treturn ''\n\t}\n\tif (path.indexOf('@') === -1) {\n\t\treturn path\n\t}\n\tconst resolved = interpolateUrlTokens(path, ctx)\n\treturn resolved.split('.').some((segment) => segment === '') ? null : resolved\n}\n\n/**\n * Whether interpolation left an EMPTY PATH SEGMENT in a URL that had tokens.\n *\n * An unresolved token collapses to `''` so a literal `@object.caseType` never\n * hits the wire. In a query value that is harmless. In a PATH it silently\n * builds a different URL: `…/milestones/progress/@object.caseType` becomes\n * `…/milestones/progress/`, which is a route that does not exist.\n *\n * Measured on dossiq: a KPI tile bound to the loaded record fired that 404 on\n * every case-detail load, then re-fired correctly once the record arrived. The\n * tile showed the same value throughout, because the widget's zero and a failed\n * fetch render identically — so nothing looked wrong and the 404 simply became\n * background noise in the console.\n *\n * Only PATH segments are judged, and only when the raw URL actually carried a\n * token: an empty query value stays a caller's business, and a URL with no\n * tokens is never blocked by this.\n *\n * @param {string} rawUrl The URL before interpolation.\n * @param {string} resolvedUrl The URL after interpolation.\n * @return {boolean} true when a token collapsed into an empty path segment.\n */\nfunction hasEmptyPathSegment(rawUrl, resolvedUrl) {\n\tif (typeof rawUrl !== 'string' || rawUrl.indexOf('@') === -1) {\n\t\treturn false\n\t}\n\tconst path = String(resolvedUrl).split('?')[0].split('#')[0]\n\t// A trailing slash on a URL that HAD no trailing slash before interpolation,\n\t// or any `//` inside the path, is a segment that resolved to nothing.\n\tconst rawPath = rawUrl.split('?')[0].split('#')[0]\n\tif (path.includes('//') && !rawPath.includes('//')) {\n\t\treturn true\n\t}\n\treturn path.length > 1 && path.endsWith('/') && !rawPath.endsWith('/')\n}\n\n/**\n * Stable cache key for a resolved endpoint request. One entry per\n * `(method, url, resolved params)` — the params carry the resolved period /\n * date window, so a period switch is a different key (per-period caching).\n *\n * @param {{url: string, method: string, params: object}} request The resolved request.\n * @return {string} The cache key.\n */\nexport function endpointCacheKey(request) {\n\treturn `${request.method} ${request.url} ${JSON.stringify(request.params || {})}`\n}\n\n/**\n * Drop every cached endpoint response (and any in-flight dedup entry).\n * Tests and page-level refresh flows use this to force fresh data.\n *\n * @return {void}\n */\nexport function invalidateEndpointSourceCache() {\n\tresponseCache.clear()\n}\n\n/**\n * Fetch the shared response body for a resolved request, deduping concurrent\n * identical requests and caching for {@link ENDPOINT_SOURCE_TTL_MS}. An\n * errored fetch drops its cache entry so the next call retries.\n *\n * A forced call that carries a `refresh` token joins an in-flight request of\n * the same refresh, so the widgets of one page refresh that share a request\n * send it once. A later refresh (say, one emitted after a save) never joins an\n * earlier one's request, which may predate the write.\n *\n * A `fresh` call joins any request still in flight but never serves a settled\n * cache entry: concurrent callers share one request, and none reads a stale one.\n *\n * @param {{url: string, method: string, params: object}} request The resolved request.\n * @param {{force?: boolean, refresh?: object, fresh?: boolean}} [opts] `force: true` bypasses (and replaces) the cache entry; `refresh` is the refresh event's payload object, one per emit; `fresh: true` only joins in-flight requests.\n * @return {Promise<unknown>} The raw response body (`res.data`).\n */\nexport async function fetchSharedResponse(request, opts) {\n\tconst key = endpointCacheKey(request)\n\tconst now = Date.now()\n\tconst force = Boolean(opts && opts.force)\n\tconst fresh = Boolean(opts && opts.fresh)\n\tconst refresh = (force && opts.refresh) || null\n\tconst entry = responseCache.get(key)\n\tif (entry && refresh && entry.refresh === refresh && entry.pending) {\n\t\treturn entry.promise\n\t}\n\tif (entry && fresh && !force && entry.pending) {\n\t\treturn entry.promise\n\t}\n\tif (entry && !force && !fresh && (now - entry.timestamp) < ENDPOINT_SOURCE_TTL_MS) {\n\t\treturn entry.promise\n\t}\n\tconst promise = (async () => {\n\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\timport('@nextcloud/axios'),\n\t\t\timport('@nextcloud/router'),\n\t\t])\n\t\t// Leave absolute URLs (http/https) untouched; route app-relative\n\t\t// paths through generateUrl so they resolve under the NC base.\n\t\tconst url = /^https?:\\/\\//i.test(request.url) ? request.url : generateUrl(request.url)\n\t\tconst res = request.method === 'POST'\n\t\t\t? await axios.post(url, request.params || {})\n\t\t\t: await axios.get(url, { params: request.params || {} })\n\t\treturn res && res.data\n\t})().catch((err) => {\n\t\tif (responseCache.get(key)?.promise === promise) {\n\t\t\tresponseCache.delete(key)\n\t\t}\n\t\tthrow err\n\t}).finally(() => {\n\t\tconst current = responseCache.get(key)\n\t\tif (current?.promise === promise) {\n\t\t\tcurrent.pending = false\n\t\t\tcurrent.refresh = null\n\t\t}\n\t})\n\tresponseCache.set(key, { promise, timestamp: now, refresh, pending: true })\n\treturn promise\n}\n\n/**\n * One-shot cached fetch of an `endpointSource`: resolve tokens, share the\n * request, pluck `responsePath`. Returns `null` when the config is unusable\n * (no url) or the request is blocked on an unresolved REQUIRED token, and\n * `null` when the plucked payload is `undefined`.\n *\n * Use this from an imperative fetch flow (Options-API widgets); use\n * {@link useEndpointSource} for the fully reactive form.\n *\n * @param {{url: string, method?: string, params?: object, responsePath?: string}} config The endpointSource block.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object, range?: object}} [ctx] The token context.\n * @param {{force?: boolean}} [opts] `force: true` bypasses the shared cache.\n * @return {Promise<unknown>} The plucked payload (or null).\n */\nexport async function fetchEndpointSource(config, ctx, opts) {\n\tif (!config || !config.url) {\n\t\treturn null\n\t}\n\tconst request = resolveEndpointRequest(config, ctx)\n\tif (request.blocked) {\n\t\treturn null\n\t}\n\tconst body = await fetchSharedResponse(request, opts)\n\tconst payload = getByPath(body, request.responsePath)\n\treturn payload === undefined ? null : payload\n}\n\n/**\n * Unwrap a value that may be a plain value, a ref, or a getter function.\n *\n * @param {unknown} v The wrapped value.\n * @return {unknown} The unwrapped value.\n */\nfunction read(v) {\n\treturn typeof v === 'function' ? v() : unref(v)\n}\n\n/**\n * Reactive endpoint data binding.\n *\n * Resolves the `endpointSource` block into reactive\n * `{ data, loading, error, refetch }`. The request signature (url + resolved\n * params + method) is watched, so a change in the page-level workspace\n * context (the dashboard date-range pills publishing `dateFrom` / `dateTo` /\n * `datePreset`, a page filter publishing `period`, …) re-resolves the tokens\n * and refetches automatically. When the config is `null` / has no `url` the\n * composable never queries and `data.value` stays `null`.\n *\n * Refresh wiring (library event-bus):\n * - `cn:page:refresh` → force-refetch past the shared cache.\n * - `cn:widget:refresh` with a payload `widgetId` matching the non-empty\n * `widgetId` option → force-refetch.\n * - a bump of the optional reactive `refreshKey` → force-refetch (escape\n * hatch for app-local refresh signals the library cannot observe).\n *\n * @param {object|import('vue').Ref<object>|(() => object)} source The endpointSource block (object, ref, or getter).\n * @param {object} [options] Options.\n * @param {object|import('vue').Ref<object>|(() => object)} [options.ctx] Token context `{ objectId?, object?, workspace?, config? }` (object, ref, or getter).\n * @param {string|import('vue').Ref<string>|(() => string)} [options.widgetId] Widget id matched against `cn:widget:refresh` payloads (empty disables widget-scoped refresh).\n * @param {import('vue').Ref<unknown>|(() => unknown)} [options.refreshKey] Reactive value (ref or getter) whose changes force a refetch.\n * @return {{data: import('vue').Ref<unknown>, loading: import('vue').Ref<boolean>, error: import('vue').Ref<string>, blocked: import('vue').Ref<boolean>, refetch: (force?: boolean) => Promise<void>}} Reactive state + a `refetch(force = true)` trigger. `blocked` is true when the last read was NOT ATTEMPTED because a required token is unset — distinct from loading, and the only way to tell \"nothing asked\" from \"asked, still waiting\".\n */\nexport function useEndpointSource(source, options) {\n\tconst opts = options || {}\n\tconst data = ref(null)\n\tconst loading = ref(false)\n\tconst error = ref('')\n\t// Whether the last read was not attempted because a required token is\n\t// unset. The three refs above cannot express it: a blocked read looks\n\t// exactly like the instant before the first request.\n\tconst blocked = ref(false)\n\t// Monotonic fetch id so a stale (slower) response never overwrites a\n\t// newer one after the request signature changed.\n\tlet fetchSeq = 0\n\n\tconst readCtx = () => read(opts.ctx) || {}\n\n\t/**\n\t * Stable request signature: null when there is nothing to fetch,\n\t * otherwise the resolved url/params/method + responsePath (+ blocked\n\t * flag so un-blocking triggers the fetch).\n\t */\n\tconst requestKey = computed(() => {\n\t\tconst cfg = read(source)\n\t\tif (!cfg || !cfg.url) {\n\t\t\treturn null\n\t\t}\n\t\tconst request = resolveEndpointRequest(cfg, readCtx())\n\t\treturn JSON.stringify({\n\t\t\tu: request.url,\n\t\t\tm: request.method,\n\t\t\tp: request.params,\n\t\t\tr: request.responsePath,\n\t\t\tb: request.blocked,\n\t\t})\n\t})\n\n\t/**\n\t * Run (or re-run) the fetch for the current config.\n\t *\n\t * @param {boolean} [force] Bypass the shared cache (refresh semantics).\n\t * @param {object} [refresh] The refresh event's payload, shared by its widgets.\n\t * @return {Promise<void>}\n\t */\n\tasync function load(force, refresh) {\n\t\tconst cfg = read(source)\n\t\tconst seq = ++fetchSeq\n\t\tif (!cfg || !cfg.url) {\n\t\t\tdata.value = null\n\t\t\terror.value = ''\n\t\t\tloading.value = false\n\t\t\tblocked.value = false\n\t\t\treturn\n\t\t}\n\t\tconst request = resolveEndpointRequest(cfg, readCtx())\n\t\tif (request.blocked) {\n\t\t\t// A required context token is unset — wait, don't error.\n\t\t\tdata.value = null\n\t\t\terror.value = ''\n\t\t\tloading.value = false\n\t\t\tblocked.value = true\n\t\t\treturn\n\t\t}\n\t\tblocked.value = false\n\t\tconst startedAt = Date.now()\n\t\tloading.value = true\n\t\terror.value = ''\n\t\ttry {\n\t\t\tconst body = await fetchSharedResponse(request, { force: force === true, refresh })\n\t\t\tif (seq !== fetchSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst payload = getByPath(body, request.responsePath)\n\t\t\tdata.value = payload === undefined ? null : payload\n\t\t} catch (e) {\n\t\t\tif (seq !== fetchSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\terror.value = (e && e.message) || 'error'\n\t\t\tdata.value = null\n\t\t} finally {\n\t\t\tif (seq === fetchSeq) {\n\t\t\t\t// Forced refetches hold `loading` to MIN_FORCED_LOADING_MS so\n\t\t\t\t// the refresh is perceivable even against a fast endpoint; a\n\t\t\t\t// newer run owns the flag once fetchSeq moves on.\n\t\t\t\tconst hold = force === true ? MIN_FORCED_LOADING_MS - (Date.now() - startedAt) : 0\n\t\t\t\tif (hold > 0) {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tif (seq === fetchSeq) {\n\t\t\t\t\t\t\tloading.value = false\n\t\t\t\t\t\t}\n\t\t\t\t\t}, hold)\n\t\t\t\t} else {\n\t\t\t\t\tloading.value = false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Public refetch trigger. Force (cache-bypassing) by default — that is\n\t * what every refresh affordance wants; pass `false` to allow a cache hit.\n\t *\n\t * @param {boolean} [force] Bypass the shared cache (default true).\n\t * @return {Promise<void>}\n\t */\n\tconst refetch = (force = true) => load(force)\n\n\twatch(requestKey, () => {\n\t\tload(false)\n\t}, { immediate: true })\n\n\tif (opts.refreshKey !== undefined) {\n\t\twatch(() => read(opts.refreshKey), () => {\n\t\t\tload(true)\n\t\t})\n\t}\n\n\t// `waitUntil` lets the menu that sent the refresh spin until this fetch lands.\n\tconst onPageRefresh = (payload) => {\n\t\tconst done = load(true, payload)\n\t\tpayload?.waitUntil?.(done)\n\t}\n\tconst onWidgetRefresh = (payload) => {\n\t\tconst id = read(opts.widgetId)\n\t\tif (!id) {\n\t\t\treturn\n\t\t}\n\t\tif (!payload || payload.widgetId !== id) {\n\t\t\treturn\n\t\t}\n\t\tconst done = load(true, payload)\n\t\tpayload.waitUntil?.(done)\n\t}\n\tsubscribe(PAGE_REFRESH_CHANNEL, onPageRefresh)\n\tsubscribe(WIDGET_REFRESH_CHANNEL, onWidgetRefresh)\n\tif (getCurrentScope()) {\n\t\tonScopeDispose(() => {\n\t\t\tunsubscribe(PAGE_REFRESH_CHANNEL, onPageRefresh)\n\t\t\tunsubscribe(WIDGET_REFRESH_CHANNEL, onWidgetRefresh)\n\t\t})\n\t}\n\n\treturn { data, loading, error, blocked, refetch }\n}\n"],"names":[],"mappings":";;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAI;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,qBAAqB,GAAG,IAAG;AACxC;AACA;AACA,MAAM,oBAAoB,GAAG,kBAAiB;AAC9C;AACA;AACA,MAAM,sBAAsB,GAAG,oBAAmB;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,aAAa,GAAG,IAAI,GAAG,GAAE;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE;AACrC,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,EAAE;AACzD,EAAE,OAAO,GAAG;AACZ,EAAE;AACF,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM;AACtC,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,EAAE,GAAG;AACL,EAAE;AACF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE;AAC/C,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC9B,EAAE,OAAO,GAAG;AACZ,EAAE;AACF,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,GAAE;AACpB,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,SAAS,IAAI,GAAE;AACpC,CAAC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,GAAE;AAC9B,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,qCAAqC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,KAAK;AAC5E,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,EAAC;AAC1B,EAAE,OAAO,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC;AACzD,EAAE,CAAC,CAAC,OAAO,CAAC,2BAA2B,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK;AACrD,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,EAAC;AACvB,EAAE,OAAO,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC;AACzD,EAAE,CAAC,CAAC,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK;AACpD,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAC;AACnC,EAAE,OAAO,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC;AACzD,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM;AAChC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,SAAQ;AACvB,EAAE,OAAO,CAAC,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;AAC5D,EAAE,CAAC,CAAC,OAAO,CAAC,2BAA2B,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK;AACvD,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,EAAC;AACvC,EAAE,OAAO,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC;AACzD,EAAE,CAAC;AACH,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,sBAAsB,CAAC,MAAM,EAAE,GAAG,EAAE;AACpD,CAAC,MAAM,GAAG,GAAG,MAAM,IAAI,GAAE;AACzB,CAAC,MAAM,GAAG,GAAG,oBAAoB,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,GAAG,EAAC;AACrD,CAAC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,GAAG,EAAC;AAC5D,CAAC,MAAM,MAAM,GAAG,sBAAsB,CAAC,QAAQ,EAAC;AAChD,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,KAAK,MAAM,GAAG,MAAM,GAAG,MAAK;AACrF,CAAC,MAAM,YAAY,GAAG,mBAAmB,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,EAAC;AAChE,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM,CAAC,IAAI,mBAAmB,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,GAAG,CAAC,IAAI,YAAY,KAAK,KAAI;AAChH,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,IAAI,EAAE,EAAE;AAC1E,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,mBAAmB,CAAC,IAAI,EAAE,GAAG,EAAE;AACxC,CAAC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,EAAE;AAC9C,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE;AAC/B,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,QAAQ,GAAG,oBAAoB,CAAC,IAAI,EAAE,GAAG,EAAC;AACjD,CAAC,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,QAAQ;AAC/E,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE;AAClD,CAAC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE;AAC/D,EAAE,OAAO,KAAK;AACd,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAC;AAC7D;AACA;AACA,CAAC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAC;AACnD,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AACrD,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;AACvE,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gBAAgB,CAAC,OAAO,EAAE;AAC1C,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;AAClF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,6BAA6B,GAAG;AAChD,CAAC,aAAa,CAAC,KAAK,GAAE;AACtB,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAe,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAE;AACzD,CAAC,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,EAAC;AACtC,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,GAAE;AACvB,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAC;AAC1C,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,EAAC;AAC1C,CAAC,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,KAAI;AAChD,CAAC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,EAAC;AACrC,CAAC,IAAI,KAAK,IAAI,OAAO,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;AACrE,EAAE,OAAO,KAAK,CAAC,OAAO;AACtB,EAAE;AACF,CAAC,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE;AAChD,EAAE,OAAO,KAAK,CAAC,OAAO;AACtB,EAAE;AACF,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,SAAS,IAAI,sBAAsB,EAAE;AACpF,EAAE,OAAO,KAAK,CAAC,OAAO;AACtB,EAAE;AACF,CAAC,MAAM,OAAO,GAAG,CAAC,YAAY;AAC9B,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;AAClE,GAAG,OAAO,kBAAkB,CAAC;AAC7B,GAAG,OAAO,mBAAmB,CAAC;AAC9B,GAAG,EAAC;AACJ;AACA;AACA,EAAE,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,GAAG,EAAC;AACxF,EAAE,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,KAAK,MAAM;AACvC,KAAK,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;AAChD,KAAK,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,EAAC;AAC3D,EAAE,OAAO,GAAG,IAAI,GAAG,CAAC,IAAI;AACxB,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK;AACrB,EAAE,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,KAAK,OAAO,EAAE;AACnD,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,EAAC;AAC5B,GAAG;AACH,EAAE,MAAM,GAAG;AACX,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM;AAClB,EAAE,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,EAAC;AACxC,EAAE,IAAI,OAAO,EAAE,OAAO,KAAK,OAAO,EAAE;AACpC,GAAG,OAAO,CAAC,OAAO,GAAG,MAAK;AAC1B,GAAG,OAAO,CAAC,OAAO,GAAG,KAAI;AACzB,GAAG;AACH,EAAE,EAAC;AACH,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,EAAC;AAC5E,CAAC,OAAO,OAAO;AACf,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAe,mBAAmB,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE;AAC7D,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;AAC7B,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,OAAO,GAAG,sBAAsB,CAAC,MAAM,EAAE,GAAG,EAAC;AACpD,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE;AACtB,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,IAAI,EAAC;AACtD,CAAC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,EAAC;AACtD,CAAC,OAAO,OAAO,KAAK,SAAS,GAAG,IAAI,GAAG,OAAO;AAC9C,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,IAAI,CAAC,CAAC,EAAE;AACjB,CAAC,OAAO,OAAO,CAAC,KAAK,UAAU,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;AAChD,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE;AACnD,CAAC,MAAM,IAAI,GAAG,OAAO,IAAI,GAAE;AAC3B,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAC;AACvB,CAAC,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,EAAC;AAC3B,CAAC,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE,EAAC;AACtB;AACA;AACA;AACA,CAAC,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,EAAC;AAC3B;AACA;AACA,CAAC,IAAI,QAAQ,GAAG,EAAC;AACjB;AACA,CAAC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAE;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM;AACnC,EAAE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAC;AAC1B,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE;AACxB,GAAG,OAAO,IAAI;AACd,GAAG;AACH,EAAE,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAC;AACxD,EAAE,OAAO,IAAI,CAAC,SAAS,CAAC;AACxB,GAAG,CAAC,EAAE,OAAO,CAAC,GAAG;AACjB,GAAG,CAAC,EAAE,OAAO,CAAC,MAAM;AACpB,GAAG,CAAC,EAAE,OAAO,CAAC,MAAM;AACpB,GAAG,CAAC,EAAE,OAAO,CAAC,YAAY;AAC1B,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO;AACrB,GAAG,CAAC;AACJ,EAAE,EAAC;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,eAAe,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE;AACrC,EAAE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAC;AAC1B,EAAE,MAAM,GAAG,GAAG,EAAE,SAAQ;AACxB,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE;AACxB,GAAG,IAAI,CAAC,KAAK,GAAG,KAAI;AACpB,GAAG,KAAK,CAAC,KAAK,GAAG,GAAE;AACnB,GAAG,OAAO,CAAC,KAAK,GAAG,MAAK;AACxB,GAAG,OAAO,CAAC,KAAK,GAAG,MAAK;AACxB,GAAG,MAAM;AACT,GAAG;AACH,EAAE,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAC;AACxD,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE;AACvB;AACA,GAAG,IAAI,CAAC,KAAK,GAAG,KAAI;AACpB,GAAG,KAAK,CAAC,KAAK,GAAG,GAAE;AACnB,GAAG,OAAO,CAAC,KAAK,GAAG,MAAK;AACxB,GAAG,OAAO,CAAC,KAAK,GAAG,KAAI;AACvB,GAAG,MAAM;AACT,GAAG;AACH,EAAE,OAAO,CAAC,KAAK,GAAG,MAAK;AACvB,EAAE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,GAAE;AAC9B,EAAE,OAAO,CAAC,KAAK,GAAG,KAAI;AACtB,EAAE,KAAK,CAAC,KAAK,GAAG,GAAE;AAClB,EAAE,IAAI;AACN,GAAG,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,EAAE,OAAO,EAAE,EAAC;AACtF,GAAG,IAAI,GAAG,KAAK,QAAQ,EAAE;AACzB,IAAI,MAAM;AACV,IAAI;AACJ,GAAG,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,EAAC;AACxD,GAAG,IAAI,CAAC,KAAK,GAAG,OAAO,KAAK,SAAS,GAAG,IAAI,GAAG,QAAO;AACtD,GAAG,CAAC,OAAO,CAAC,EAAE;AACd,GAAG,IAAI,GAAG,KAAK,QAAQ,EAAE;AACzB,IAAI,MAAM;AACV,IAAI;AACJ,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,QAAO;AAC5C,GAAG,IAAI,CAAC,KAAK,GAAG,KAAI;AACpB,GAAG,SAAS;AACZ,GAAG,IAAI,GAAG,KAAK,QAAQ,EAAE;AACzB;AACA;AACA;AACA,IAAI,MAAM,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG,qBAAqB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,EAAC;AACtF,IAAI,IAAI,IAAI,GAAG,CAAC,EAAE;AAClB,KAAK,UAAU,CAAC,MAAM;AACtB,MAAM,IAAI,GAAG,KAAK,QAAQ,EAAE;AAC5B,OAAO,OAAO,CAAC,KAAK,GAAG,MAAK;AAC5B,OAAO;AACP,MAAM,EAAE,IAAI,EAAC;AACb,KAAK,MAAM;AACX,KAAK,OAAO,CAAC,KAAK,GAAG,MAAK;AAC1B,KAAK;AACL,IAAI;AACJ,GAAG;AACH,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,MAAM,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC,KAAK,EAAC;AAC9C;AACA,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM;AACzB,EAAE,IAAI,CAAC,KAAK,EAAC;AACb,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAC;AACxB;AACA,CAAC,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE;AACpC,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM;AAC3C,GAAG,IAAI,CAAC,IAAI,EAAC;AACb,GAAG,EAAC;AACJ,EAAE;AACF;AACA;AACA,CAAC,MAAM,aAAa,GAAG,CAAC,OAAO,KAAK;AACpC,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,EAAC;AAClC,EAAE,OAAO,EAAE,SAAS,GAAG,IAAI,EAAC;AAC5B,GAAE;AACF,CAAC,MAAM,eAAe,GAAG,CAAC,OAAO,KAAK;AACtC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAC;AAChC,EAAE,IAAI,CAAC,EAAE,EAAE;AACX,GAAG,MAAM;AACT,GAAG;AACH,EAAE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,EAAE,EAAE;AAC3C,GAAG,MAAM;AACT,GAAG;AACH,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,OAAO,EAAC;AAClC,EAAE,OAAO,CAAC,SAAS,GAAG,IAAI,EAAC;AAC3B,GAAE;AACF,CAAC,SAAS,CAAC,oBAAoB,EAAE,aAAa,EAAC;AAC/C,CAAC,SAAS,CAAC,sBAAsB,EAAE,eAAe,EAAC;AACnD,CAAC,IAAI,eAAe,EAAE,EAAE;AACxB,EAAE,cAAc,CAAC,MAAM;AACvB,GAAG,WAAW,CAAC,oBAAoB,EAAE,aAAa,EAAC;AACnD,GAAG,WAAW,CAAC,sBAAsB,EAAE,eAAe,EAAC;AACvD,GAAG,EAAC;AACJ,EAAE;AACF;AACA,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;AAClD;;;;"}
1
+ {"version":3,"file":"useEndpointSource.js","sources":["../../../src/composables/useEndpointSource.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * useEndpointSource — ONE coherent endpoint data binding for the abstract\n * widgets (stat / delta / chart / object-table). A manifest-authored\n * `endpointSource` block reads an arbitrary app REST endpoint (a bespoke\n * analytics controller, a summary aggregation OpenRegister can't express)\n * and hands the widget the payload at a dot-path of the response:\n *\n * ```js\n * endpointSource: {\n * url: '/apps/pipelinq/api/analytics/overview', // app-relative (generateUrl) or absolute path\n * method: 'GET', // 'GET' (default) | 'POST' (params become the JSON body)\n * params: { period: '@workspace.datePreset?' }, // SAME token grammar as widget filters\n * responsePath: 'summary', // dot-path pluck of the payload (default: whole body)\n * }\n * ```\n *\n * `params` values pass through the SAME token resolution widget filters use\n * (`resolveFilterTokens`): `@me`, `@today` / `@today±Nd`, `@monthStart`,\n * `@workspace.<key>` / `@config.<key>` (with the trailing-`?` OPTIONAL\n * convention — an unresolved optional param is dropped, an unresolved\n * REQUIRED one blocks the fetch), `@objectId` / `@object.<field>` on detail\n * pages. The `url` itself may interpolate `@page.*` / `@workspace.*` /\n * `@config.*` / `@objectId` / `@object.*` tokens inline (unresolved URL\n * tokens collapse to an empty string so a literal `@page.period` never hits\n * the wire).\n *\n * Requests are SHARED: one in-flight promise + short-TTL cache entry per\n * `(method, url, resolved params)` — the same per-period caching semantics\n * pipelinq's `dashboardData.js` used, so four KPI tiles reading the same\n * overview endpoint issue ONE request per render pass. `responsePath`\n * plucking happens per subscriber, after the shared response resolves.\n *\n * Refresh signal — grounded in the library's own event-bus channels (the\n * mechanism `CnActionsMenu` broadcasts on): the composable subscribes to\n * `cn:page:refresh` (the page-level Refresh action → every endpoint source\n * force-refetches past the cache) and, when a `widgetId` option is given,\n * to `cn:widget:refresh` with a matching `widgetId` payload (the per-widget\n * Refresh action). App-LOCAL refresh signals (e.g. a `Vue.observable` token\n * like pipelinq's `refreshDashboardData()`) are not observable from the\n * library — for those, pass the reactive token as the `refreshKey` option\n * and bump it; every bump force-refetches.\n *\n * @module composables/useEndpointSource\n */\n\nimport { subscribe, unsubscribe } from '@nextcloud/event-bus'\nimport { computed, getCurrentScope, onScopeDispose, ref, unref, watch } from 'vue'\nimport { interpolateUrlTokens } from '../utils/interpolateUrlTokens.js'\nimport {\n\tdropOptionalUnresolved,\n\thasUnresolvedTokens,\n\tresolveFilterTokens,\n} from '../utils/resolveFilterTokens.js'\n\nexport { interpolateUrlTokens }\n\n/**\n * Cache TTL for shared endpoint responses — 5 minutes, matching the\n * per-period dashboard cache the fleet apps used (pipelinq dashboardData.js).\n *\n * @type {number}\n */\nexport const ENDPOINT_SOURCE_TTL_MS = 5 * 60 * 1000\n\n/**\n * Minimum time a FORCED refetch (a Refresh action, a `refreshKey` bump) keeps\n * `loading` true. A refresh against a fast endpoint settles in a few\n * milliseconds — too briefly for the widget's loading state to be perceived,\n * so the click reads as having done nothing. Only the loading FLAG is held;\n * the fresh data lands the moment the response arrives. Initial and\n * signature-change loads are not held — first paint should never wait.\n *\n * @type {number}\n */\nexport const MIN_FORCED_LOADING_MS = 400\n\n/** Event-bus channel the page-level Refresh action broadcasts on. */\nconst PAGE_REFRESH_CHANNEL = 'cn:page:refresh'\n\n/** Event-bus channel the per-widget Refresh action broadcasts on. */\nconst WIDGET_REFRESH_CHANNEL = 'cn:widget:refresh'\n\n/**\n * Module-level response cache: cacheKey → `{ promise, timestamp }`.\n * Shared across every widget instance in the page so identical requests\n * dedupe to one in-flight promise (pipelinq `cached()` semantics: an\n * errored fetch drops its entry so the next mount retries).\n *\n * @type {Map<string, {promise: Promise<unknown>, timestamp: number}>}\n */\nconst responseCache = new Map()\n\n/**\n * Read a dot-path off an object (e.g. `\"data.totalLeads\"`, `\"series.0.value\"`).\n * Returns the object itself for an empty path and `undefined` when any\n * segment is missing.\n *\n * @param {unknown} obj The source object.\n * @param {string} [path] The dot-path.\n * @return {unknown} The resolved value or undefined.\n */\nexport function getByPath(obj, path) {\n\tif (path === undefined || path === null || path === '') {\n\t\treturn obj\n\t}\n\treturn String(path).split('.').reduce(\n\t\t(o, k) => (o === null || o === undefined ? undefined : o[k]),\n\t\tobj,\n\t)\n}\n\n/**\n * Resolve an `endpointSource` config against a token context into a concrete\n * request descriptor. `params` run through the SAME `resolveFilterTokens`\n * grammar widget filters use; optional (`…?`) tokens that stay unresolved are\n * dropped, and a REQUIRED token that stays unresolved marks the request\n * `blocked` (the page context it depends on isn't set yet — callers skip the\n * fetch instead of sending a literal `@workspace.…`).\n *\n * @param {{url: string, method?: string, params?: object}} config The endpointSource block.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object, range?: object}} [ctx] The token context.\n * @return {{url: string, method: ('GET'|'POST'), params: object, blocked: boolean, responsePath: string}} The resolved request.\n */\nexport function resolveEndpointRequest(config, ctx) {\n\tconst cfg = config || {}\n\tconst url = interpolateUrlTokens(cfg.url || '', ctx)\n\tconst resolved = resolveFilterTokens(cfg.params || {}, ctx)\n\tconst params = dropOptionalUnresolved(resolved)\n\tconst method = String(cfg.method || 'GET').toUpperCase() === 'POST' ? 'POST' : 'GET'\n\tconst responsePath = resolveResponsePath(cfg.responsePath, ctx)\n\tconst blocked = hasUnresolvedTokens(params) || hasEmptyPathSegment(cfg.url || '', url) || responsePath === null\n\treturn { url, method, params, blocked, responsePath: responsePath || '' }\n}\n\n/**\n * Resolve the tokens in a `responsePath` (`phaseDays.@workspace.measure`), so a\n * page control can choose which part of one response a widget reads. Null when\n * a token resolved to nothing and left an empty path segment: the read waits\n * instead of plucking the wrong part.\n *\n * @param {string|undefined} path The configured path.\n * @param {object} [ctx] The token context.\n * @return {string|null} The resolved path, '' for none, null when blocked.\n */\nfunction resolveResponsePath(path, ctx) {\n\tif (typeof path !== 'string' || path === '') {\n\t\treturn ''\n\t}\n\tif (path.indexOf('@') === -1) {\n\t\treturn path\n\t}\n\tconst resolved = interpolateUrlTokens(path, ctx)\n\treturn resolved.split('.').some((segment) => segment === '') ? null : resolved\n}\n\n/**\n * Whether interpolation left an EMPTY PATH SEGMENT in a URL that had tokens.\n *\n * An unresolved token collapses to `''` so a literal `@object.caseType` never\n * hits the wire. In a query value that is harmless. In a PATH it silently\n * builds a different URL: `…/milestones/progress/@object.caseType` becomes\n * `…/milestones/progress/`, which is a route that does not exist.\n *\n * Measured on dossiq: a KPI tile bound to the loaded record fired that 404 on\n * every case-detail load, then re-fired correctly once the record arrived. The\n * tile showed the same value throughout, because the widget's zero and a failed\n * fetch render identically — so nothing looked wrong and the 404 simply became\n * background noise in the console.\n *\n * Only PATH segments are judged, and only when the raw URL actually carried a\n * token: an empty query value stays a caller's business, and a URL with no\n * tokens is never blocked by this.\n *\n * @param {string} rawUrl The URL before interpolation.\n * @param {string} resolvedUrl The URL after interpolation.\n * @return {boolean} true when a token collapsed into an empty path segment.\n */\nfunction hasEmptyPathSegment(rawUrl, resolvedUrl) {\n\tif (typeof rawUrl !== 'string' || rawUrl.indexOf('@') === -1) {\n\t\treturn false\n\t}\n\tconst path = String(resolvedUrl).split('?')[0].split('#')[0]\n\t// A trailing slash on a URL that HAD no trailing slash before interpolation,\n\t// or any `//` inside the path, is a segment that resolved to nothing.\n\tconst rawPath = rawUrl.split('?')[0].split('#')[0]\n\tif (path.includes('//') && !rawPath.includes('//')) {\n\t\treturn true\n\t}\n\treturn path.length > 1 && path.endsWith('/') && !rawPath.endsWith('/')\n}\n\n/**\n * Stable cache key for a resolved endpoint request. One entry per\n * `(method, url, resolved params)` — the params carry the resolved period /\n * date window, so a period switch is a different key (per-period caching).\n *\n * @param {{url: string, method: string, params: object}} request The resolved request.\n * @return {string} The cache key.\n */\nexport function endpointCacheKey(request) {\n\treturn `${request.method} ${request.url} ${JSON.stringify(request.params || {})}`\n}\n\n/**\n * Drop every cached endpoint response (and any in-flight dedup entry).\n * Tests and page-level refresh flows use this to force fresh data.\n *\n * @return {void}\n */\nexport function invalidateEndpointSourceCache() {\n\tresponseCache.clear()\n}\n\n/**\n * Fetch the shared response body for a resolved request, deduping concurrent\n * identical requests and caching for {@link ENDPOINT_SOURCE_TTL_MS}. An\n * errored fetch drops its cache entry so the next call retries.\n *\n * A forced call that carries a `refresh` token joins an in-flight request of\n * the same refresh, so the widgets of one page refresh that share a request\n * send it once. A later refresh (say, one emitted after a save) never joins an\n * earlier one's request, which may predate the write.\n *\n * A `fresh` call joins any request still in flight but never serves a settled\n * cache entry: concurrent callers share one request, and none reads a stale one.\n *\n * @param {{url: string, method: string, params: object}} request The resolved request.\n * @param {{force?: boolean, refresh?: object, fresh?: boolean}} [opts] `force: true` bypasses (and replaces) the cache entry; `refresh` is the refresh event's payload object, one per emit; `fresh: true` only joins in-flight requests.\n * @return {Promise<unknown>} The raw response body (`res.data`).\n */\nexport async function fetchSharedResponse(request, opts) {\n\tconst key = endpointCacheKey(request)\n\tconst now = Date.now()\n\tconst force = Boolean(opts && opts.force)\n\tconst fresh = Boolean(opts && opts.fresh)\n\tconst refresh = (force && opts.refresh) || null\n\tconst entry = responseCache.get(key)\n\tif (entry && refresh && entry.refresh === refresh && entry.pending) {\n\t\treturn entry.promise\n\t}\n\tif (entry && fresh && !force && entry.pending) {\n\t\treturn entry.promise\n\t}\n\tif (entry && !force && !fresh && (now - entry.timestamp) < ENDPOINT_SOURCE_TTL_MS) {\n\t\treturn entry.promise\n\t}\n\tconst promise = (async () => {\n\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\timport('@nextcloud/axios'),\n\t\t\timport('@nextcloud/router'),\n\t\t])\n\t\t// Leave absolute URLs (http/https) untouched; route app-relative\n\t\t// paths through generateUrl so they resolve under the NC base.\n\t\tconst url = /^https?:\\/\\//i.test(request.url) ? request.url : generateUrl(request.url)\n\t\tconst res = request.method === 'POST'\n\t\t\t? await axios.post(url, request.params || {})\n\t\t\t: await axios.get(url, { params: request.params || {} })\n\t\treturn res && res.data\n\t})().catch((err) => {\n\t\tif (responseCache.get(key)?.promise === promise) {\n\t\t\tresponseCache.delete(key)\n\t\t}\n\t\tthrow err\n\t}).finally(() => {\n\t\tconst current = responseCache.get(key)\n\t\tif (current?.promise === promise) {\n\t\t\tcurrent.pending = false\n\t\t\tcurrent.refresh = null\n\t\t}\n\t})\n\tresponseCache.set(key, { promise, timestamp: now, refresh, pending: true })\n\treturn promise\n}\n\n/**\n * One-shot cached fetch of an `endpointSource`: resolve tokens, share the\n * request, pluck `responsePath`. Returns `null` when the config is unusable\n * (no url) or the request is blocked on an unresolved REQUIRED token, and\n * `null` when the plucked payload is `undefined`.\n *\n * Use this from an imperative fetch flow (Options-API widgets); use\n * {@link useEndpointSource} for the fully reactive form.\n *\n * @param {{url: string, method?: string, params?: object, responsePath?: string}} config The endpointSource block.\n * @param {{objectId?: (string|number), object?: object, workspace?: object, config?: object, range?: object}} [ctx] The token context.\n * @param {{force?: boolean}} [opts] `force: true` bypasses the shared cache.\n * @return {Promise<unknown>} The plucked payload (or null).\n */\nexport async function fetchEndpointSource(config, ctx, opts) {\n\tif (!config || !config.url) {\n\t\treturn null\n\t}\n\tconst request = resolveEndpointRequest(config, ctx)\n\tif (request.blocked) {\n\t\treturn null\n\t}\n\tconst body = await fetchSharedResponse(request, opts)\n\tconst payload = getByPath(body, request.responsePath)\n\treturn payload === undefined ? null : payload\n}\n\n/**\n * Unwrap a value that may be a plain value, a ref, or a getter function.\n *\n * @param {unknown} v The wrapped value.\n * @return {unknown} The unwrapped value.\n */\nfunction read(v) {\n\treturn typeof v === 'function' ? v() : unref(v)\n}\n\n/**\n * Reactive endpoint data binding.\n *\n * Resolves the `endpointSource` block into reactive\n * `{ data, loading, error, refetch }`. The request signature (url + resolved\n * params + method) is watched, so a change in the page-level workspace\n * context (the dashboard date-range pills publishing `dateFrom` / `dateTo` /\n * `datePreset`, a page filter publishing `period`, …) re-resolves the tokens\n * and refetches automatically. When the config is `null` / has no `url` the\n * composable never queries and `data.value` stays `null`.\n *\n * Refresh wiring (library event-bus):\n * - `cn:page:refresh` → force-refetch past the shared cache.\n * - `cn:widget:refresh` with a payload `widgetId` matching the non-empty\n * `widgetId` option → force-refetch.\n * - a bump of the optional reactive `refreshKey` → force-refetch (escape\n * hatch for app-local refresh signals the library cannot observe).\n *\n * @param {object|import('vue').Ref<object>|(() => object)} source The endpointSource block (object, ref, or getter).\n * @param {object} [options] Options.\n * @param {object|import('vue').Ref<object>|(() => object)} [options.ctx] Token context `{ objectId?, object?, workspace?, config? }` (object, ref, or getter).\n * @param {string|import('vue').Ref<string>|(() => string)} [options.widgetId] Widget id matched against `cn:widget:refresh` payloads (empty disables widget-scoped refresh).\n * @param {import('vue').Ref<unknown>|(() => unknown)} [options.refreshKey] Reactive value (ref or getter) whose changes force a refetch.\n * @return {{data: import('vue').Ref<unknown>, loading: import('vue').Ref<boolean>, error: import('vue').Ref<string>, blocked: import('vue').Ref<boolean>, refetch: (force?: boolean) => Promise<void>}} Reactive state + a `refetch(force = true)` trigger. `blocked` is true when the last read was NOT ATTEMPTED because a required token is unset — distinct from loading, and the only way to tell \"nothing asked\" from \"asked, still waiting\".\n */\nexport function useEndpointSource(source, options) {\n\tconst opts = options || {}\n\tconst data = ref(null)\n\tconst loading = ref(false)\n\tconst error = ref('')\n\t// Whether the last read was not attempted because a required token is\n\t// unset. The three refs above cannot express it: a blocked read looks\n\t// exactly like the instant before the first request.\n\tconst blocked = ref(false)\n\t// Monotonic fetch id so a stale (slower) response never overwrites a\n\t// newer one after the request signature changed.\n\tlet fetchSeq = 0\n\n\tconst readCtx = () => read(opts.ctx) || {}\n\n\t/**\n\t * Stable request signature: null when there is nothing to fetch,\n\t * otherwise the resolved url/params/method + responsePath (+ blocked\n\t * flag so un-blocking triggers the fetch).\n\t */\n\tconst requestKey = computed(() => {\n\t\tconst cfg = read(source)\n\t\tif (!cfg || !cfg.url) {\n\t\t\treturn null\n\t\t}\n\t\tconst request = resolveEndpointRequest(cfg, readCtx())\n\t\treturn JSON.stringify({\n\t\t\tu: request.url,\n\t\t\tm: request.method,\n\t\t\tp: request.params,\n\t\t\tr: request.responsePath,\n\t\t\tb: request.blocked,\n\t\t})\n\t})\n\n\t/**\n\t * Run (or re-run) the fetch for the current config.\n\t *\n\t * @param {boolean} [force] Bypass the shared cache (refresh semantics).\n\t * @param {object} [refresh] The refresh event's payload, shared by its widgets.\n\t * @return {Promise<void>}\n\t */\n\tasync function load(force, refresh) {\n\t\tconst cfg = read(source)\n\t\tconst seq = ++fetchSeq\n\t\tif (!cfg || !cfg.url) {\n\t\t\tdata.value = null\n\t\t\terror.value = ''\n\t\t\tloading.value = false\n\t\t\tblocked.value = false\n\t\t\treturn\n\t\t}\n\t\tconst request = resolveEndpointRequest(cfg, readCtx())\n\t\tif (request.blocked) {\n\t\t\t// A required context token is unset — wait, don't error.\n\t\t\tdata.value = null\n\t\t\terror.value = ''\n\t\t\tloading.value = false\n\t\t\tblocked.value = true\n\t\t\treturn\n\t\t}\n\t\tblocked.value = false\n\t\tconst startedAt = Date.now()\n\t\tloading.value = true\n\t\terror.value = ''\n\t\ttry {\n\t\t\tconst body = await fetchSharedResponse(request, { force: force === true, refresh })\n\t\t\tif (seq !== fetchSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst payload = getByPath(body, request.responsePath)\n\t\t\tdata.value = payload === undefined ? null : payload\n\t\t} catch (e) {\n\t\t\tif (seq !== fetchSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\terror.value = (e && e.message) || 'error'\n\t\t\tdata.value = null\n\t\t} finally {\n\t\t\tif (seq === fetchSeq) {\n\t\t\t\t// Forced refetches hold `loading` to MIN_FORCED_LOADING_MS so\n\t\t\t\t// the refresh is perceivable even against a fast endpoint; a\n\t\t\t\t// newer run owns the flag once fetchSeq moves on.\n\t\t\t\tconst hold = force === true ? MIN_FORCED_LOADING_MS - (Date.now() - startedAt) : 0\n\t\t\t\tif (hold > 0) {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tif (seq === fetchSeq) {\n\t\t\t\t\t\t\tloading.value = false\n\t\t\t\t\t\t}\n\t\t\t\t\t}, hold)\n\t\t\t\t} else {\n\t\t\t\t\tloading.value = false\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Public refetch trigger. Force (cache-bypassing) by default — that is\n\t * what every refresh affordance wants; pass `false` to allow a cache hit.\n\t *\n\t * @param {boolean} [force] Bypass the shared cache (default true).\n\t * @return {Promise<void>}\n\t */\n\tconst refetch = (force = true) => load(force)\n\n\twatch(requestKey, () => {\n\t\tload(false)\n\t}, { immediate: true })\n\n\tif (opts.refreshKey !== undefined) {\n\t\twatch(() => read(opts.refreshKey), () => {\n\t\t\tload(true)\n\t\t})\n\t}\n\n\t// `waitUntil` lets the menu that sent the refresh spin until this fetch lands.\n\tconst onPageRefresh = (payload) => {\n\t\tconst done = load(true, payload)\n\t\tpayload?.waitUntil?.(done)\n\t}\n\tconst onWidgetRefresh = (payload) => {\n\t\tconst id = read(opts.widgetId)\n\t\tif (!id) {\n\t\t\treturn\n\t\t}\n\t\tif (!payload || payload.widgetId !== id) {\n\t\t\treturn\n\t\t}\n\t\tconst done = load(true, payload)\n\t\tpayload.waitUntil?.(done)\n\t}\n\tsubscribe(PAGE_REFRESH_CHANNEL, onPageRefresh)\n\tsubscribe(WIDGET_REFRESH_CHANNEL, onWidgetRefresh)\n\tif (getCurrentScope()) {\n\t\tonScopeDispose(() => {\n\t\t\tunsubscribe(PAGE_REFRESH_CHANNEL, onPageRefresh)\n\t\t\tunsubscribe(WIDGET_REFRESH_CHANNEL, onWidgetRefresh)\n\t\t})\n\t}\n\n\treturn { data, loading, error, blocked, refetch }\n}\n"],"names":[],"mappings":";;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAI;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,qBAAqB,GAAG,IAAG;AACxC;AACA;AACA,MAAM,oBAAoB,GAAG,kBAAiB;AAC9C;AACA;AACA,MAAM,sBAAsB,GAAG,oBAAmB;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,aAAa,GAAG,IAAI,GAAG,GAAE;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE;AACrC,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,EAAE;AACzD,EAAE,OAAO,GAAG;AACZ,EAAE;AACF,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM;AACtC,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,EAAE,GAAG;AACL,EAAE;AACF,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,sBAAsB,CAAC,MAAM,EAAE,GAAG,EAAE;AACpD,CAAC,MAAM,GAAG,GAAG,MAAM,IAAI,GAAE;AACzB,CAAC,MAAM,GAAG,GAAG,oBAAoB,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAA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"}
@@ -2,7 +2,7 @@ import script from './CnTransitionInputDialog.vue2.js';
2
2
  import { render } from './CnTransitionInputDialog.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-457532e4";
5
+ script.__scopeId = "data-v-3630e942";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };