@conduction/nextcloud-vue 2.100.0 → 2.102.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 (168) hide show
  1. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +22 -0
  2. package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
  3. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +8 -6
  4. package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
  5. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  6. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +29 -4
  7. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  8. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js +9 -1
  9. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  10. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue.js +1 -1
  11. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js +22 -1
  12. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
  13. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +26 -16
  14. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
  15. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  16. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +70 -6
  17. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  18. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +105 -74
  19. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  20. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js +9 -0
  21. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue.js.map +1 -0
  22. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js +139 -0
  23. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue2.js.map +1 -0
  24. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js +76 -0
  25. package/dist/esm/components/CnExportsWidget/CnExportsWidget.vue3.js.map +1 -0
  26. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  27. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +160 -2
  28. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  29. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +206 -94
  30. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  31. package/dist/esm/components/CnFilesBrowser/filesReview.js +61 -0
  32. package/dist/esm/components/CnFilesBrowser/filesReview.js.map +1 -0
  33. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js +9 -0
  34. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue.js.map +1 -0
  35. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js +279 -0
  36. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue2.js.map +1 -0
  37. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js +122 -0
  38. package/dist/esm/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue3.js.map +1 -0
  39. package/dist/esm/components/CnGroupedCardsWidget/index.js +29 -0
  40. package/dist/esm/components/CnGroupedCardsWidget/index.js.map +1 -0
  41. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +320 -74
  42. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  43. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +323 -213
  44. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  45. package/dist/esm/components/CnIndexPage/useNamedSource.js +30 -3
  46. package/dist/esm/components/CnIndexPage/useNamedSource.js.map +1 -1
  47. package/dist/esm/components/CnMapWidget/CnMapWidget.vue.js +1 -1
  48. package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js +15 -0
  49. package/dist/esm/components/CnMapWidget/CnMapWidget.vue2.js.map +1 -1
  50. package/dist/esm/components/CnMapWidget/CnMapWidget.vue3.js.map +1 -1
  51. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue.js +1 -1
  52. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue2.js +25 -1
  53. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue2.js.map +1 -1
  54. package/dist/esm/components/CnMenuWidget/CnMenuWidget.vue3.js.map +1 -1
  55. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  56. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +14 -1
  57. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  58. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +14 -6
  59. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  60. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
  61. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +10 -0
  62. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  63. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +6 -1
  64. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  65. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
  66. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +91 -4
  67. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
  68. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +63 -38
  69. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
  70. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue.js +1 -1
  71. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +106 -4
  72. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
  73. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +70 -25
  74. package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
  75. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js +9 -0
  76. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js.map +1 -0
  77. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js +175 -0
  78. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue2.js.map +1 -0
  79. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js +77 -0
  80. package/dist/esm/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue3.js.map +1 -0
  81. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
  82. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +35 -2
  83. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  84. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  85. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +4 -0
  86. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
  87. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
  88. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  89. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
  90. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +2 -23
  91. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  92. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  93. package/dist/esm/composables/indexSources.js +176 -20
  94. package/dist/esm/composables/indexSources.js.map +1 -1
  95. package/dist/esm/composables/useEndpointSource.js +28 -6
  96. package/dist/esm/composables/useEndpointSource.js.map +1 -1
  97. package/dist/esm/index.js +1 -0
  98. package/dist/esm/index.js.map +1 -1
  99. package/dist/esm/l10n/en.json.js +41 -1
  100. package/dist/esm/l10n/en.json.js.map +1 -1
  101. package/dist/esm/l10n/nl.json.js +39 -1
  102. package/dist/esm/l10n/nl.json.js.map +1 -1
  103. package/dist/esm/library-style.js +1 -1
  104. package/dist/esm/nextcloud-vue.css +939 -376
  105. package/dist/esm/utils/builtInFormatters.js +24 -4
  106. package/dist/esm/utils/builtInFormatters.js.map +1 -1
  107. package/dist/esm/utils/languageMapText.js +50 -0
  108. package/dist/esm/utils/languageMapText.js.map +1 -0
  109. package/dist/esm/utils/libraryWidgetKeys.js +3 -0
  110. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  111. package/dist/esm/utils/mapList.js +71 -0
  112. package/dist/esm/utils/mapList.js.map +1 -0
  113. package/dist/esm/utils/rowClassRules.js +43 -0
  114. package/dist/esm/utils/rowClassRules.js.map +1 -0
  115. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  116. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  117. package/dist/esm/utils/visibleWhen.js +19 -2
  118. package/dist/esm/utils/visibleWhen.js.map +1 -1
  119. package/dist/nextcloud-vue.cjs.js +9681 -7136
  120. package/dist/nextcloud-vue.cjs.js.map +2 -2
  121. package/dist/nextcloud-vue.css +939 -376
  122. package/l10n/en.json +41 -1
  123. package/l10n/nl.json +39 -1
  124. package/package.json +1 -1
  125. package/src/components/CnActionsBar/CnActionsBar.md +1 -0
  126. package/src/components/CnActionsBar/CnActionsBar.vue +31 -4
  127. package/src/components/CnChartWidget/CnChartWidget.md +3 -2
  128. package/src/components/CnChartWidget/CnChartWidget.vue +42 -4
  129. package/src/components/CnChoiceCards/CnChoiceCards.md +39 -0
  130. package/src/components/CnChoiceCards/CnChoiceCards.vue +93 -16
  131. package/src/components/CnDashboardPage/CnDashboardPage.vue +110 -21
  132. package/src/components/CnExportsWidget/CnExportsWidget.vue +233 -0
  133. package/src/components/CnExportsWidget/index.js +7 -0
  134. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +324 -0
  135. package/src/components/CnFilesBrowser/filesReview.js +57 -0
  136. package/src/components/CnGroupedCardsWidget/CnGroupedCardsWidget.vue +433 -0
  137. package/src/components/CnGroupedCardsWidget/index.js +28 -0
  138. package/src/components/CnIndexPage/CnIndexPage.md +5 -1
  139. package/src/components/CnIndexPage/CnIndexPage.vue +313 -9
  140. package/src/components/CnIndexPage/useNamedSource.js +30 -3
  141. package/src/components/CnMapWidget/CnMapWidget.vue +37 -0
  142. package/src/components/CnMenuWidget/CnMenuWidget.vue +25 -1
  143. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +29 -1
  144. package/src/components/CnObjectSidebar/CnFilesTab.vue +15 -0
  145. package/src/components/CnOrderedListField/CnOrderedListField.vue +151 -5
  146. package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +1 -0
  147. package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +159 -5
  148. package/src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue +272 -0
  149. package/src/components/CnSavedViewAlertWidget/index.js +7 -0
  150. package/src/components/CnSetupWizard/CnSetupWizard.vue +35 -2
  151. package/src/components/CnWidgetGrid/builtInWidgets.js +4 -0
  152. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
  153. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +2 -23
  154. package/src/components/index.js +3 -0
  155. package/src/composables/indexSources.js +175 -19
  156. package/src/composables/useEndpointSource.js +28 -6
  157. package/src/css/index-page.css +117 -0
  158. package/src/css/look-board-index.css +10 -0
  159. package/src/css/look-board.css +44 -0
  160. package/src/index.js +1 -0
  161. package/src/schemas/app-manifest-v2.schema.json +85 -3
  162. package/src/utils/builtInFormatters.js +24 -4
  163. package/src/utils/languageMapText.js +46 -0
  164. package/src/utils/libraryWidgetKeys.js +3 -0
  165. package/src/utils/mapList.js +67 -0
  166. package/src/utils/rowClassRules.js +39 -0
  167. package/src/utils/validateManifestV2.compiled.js +3 -3
  168. package/src/utils/visibleWhen.js +19 -2
@@ -0,0 +1,9 @@
1
+ import script from './CnSavedViewAlertWidget.vue2.js';
2
+ import { render } from './CnSavedViewAlertWidget.vue3.js';
3
+
4
+ script.render = render;
5
+ script.__scopeId = "data-v-4439a3f3";
6
+ const __sfc_main = script;
7
+
8
+ export { __sfc_main as default };
9
+ //# sourceMappingURL=CnSavedViewAlertWidget.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnSavedViewAlertWidget.vue.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
@@ -0,0 +1,175 @@
1
+ import { getCurrentUser } from '@nextcloud/auth';
2
+ import { translatePlural, translate } from '@nextcloud/l10n';
3
+ import { NcCheckboxRadioSwitch, NcTextField } from '@nextcloud/vue';
4
+ import { useSavedViewsApi } from '../../composables/useSavedViewsApi.js';
5
+
6
+ /**
7
+ * CnSavedViewAlertWidget — the saved view an index page has applied, with its
8
+ * count alert (DqZoekresultaten "Opgeslagen zoekopdracht"): its name, how many
9
+ * rows it holds now, and a switch that asks OpenRegister to tell the reader
10
+ * when the count reaches a threshold.
11
+ *
12
+ * The alert is the view's own `alert` (`{ operator: 'gte', threshold,
13
+ * recipients }`), saved with a PATCH on the view; OpenRegister evaluates it on
14
+ * its sweep and fires on the crossing, not on the state. Switching it off
15
+ * clears it. The widget reads the page through the `cnIndexList` CnIndexPage
16
+ * provides, so it belongs in an index page's `sidePanel`
17
+ * (`type: "saved-view-alert"`).
18
+ *
19
+ * Example (manifest):
20
+ * ```json
21
+ * { "id": "alert", "type": "saved-view-alert", "title": "Saved search", "content": { "noun": { "one": "case", "other": "cases" } } }
22
+ * ```
23
+ */
24
+ var script = {
25
+ name: 'CnSavedViewAlertWidget',
26
+
27
+ components: { NcCheckboxRadioSwitch, NcTextField },
28
+
29
+ inject: {
30
+ /** The index page's list: its applied saved view and its total. */
31
+ cnIndexList: { default: null },
32
+ /** Host translate function provided by CnAppRoot. */
33
+ cnTranslate: { default: () => (key) => key },
34
+ },
35
+
36
+ props: {
37
+ /**
38
+ * The widget content: `{ noun?: { one, other }, emptyText? }`. `noun`
39
+ * names what is counted ("9 zaken"); `emptyText` shows while no saved
40
+ * view is applied. Both are translated with the app's catalogue.
41
+ */
42
+ content: {
43
+ type: Object,
44
+ default: () => ({}),
45
+ },
46
+ },
47
+
48
+ data() {
49
+ return { saving: false, error: '', draft: null }
50
+ },
51
+
52
+ computed: {
53
+ /** @return {object|null} The applied saved view, or null. */
54
+ view() {
55
+ return (this.cnIndexList && this.cnIndexList.appliedView) || null
56
+ },
57
+
58
+ /** @return {boolean} Whether the view carries an alert. */
59
+ enabled() {
60
+ const alert = this.view && this.view.alert;
61
+ return Boolean(alert && typeof alert === 'object' && Number.isFinite(Number(alert.threshold)))
62
+ },
63
+
64
+ /** @return {number} The threshold being edited, else the view's, else 10. */
65
+ threshold() {
66
+ if (this.draft !== null) {
67
+ return this.draft
68
+ }
69
+ const value = this.enabled ? Number(this.view.alert.threshold) : 10;
70
+ return Number.isFinite(value) ? value : 10
71
+ },
72
+
73
+ /** @return {boolean} Whether the reader may change the view: its owner, or when the view says nothing. */
74
+ canEdit() {
75
+ const owner = this.view && this.view.owner;
76
+ if (!owner) {
77
+ return true
78
+ }
79
+ const user = getCurrentUser();
80
+ return Boolean(user && user.uid === owner)
81
+ },
82
+
83
+ /** @return {string} "9 zaken", or '' while the total is unknown. */
84
+ countText() {
85
+ const total = this.cnIndexList ? this.cnIndexList.total : undefined;
86
+ if (typeof total !== 'number') {
87
+ return ''
88
+ }
89
+ const noun = this.content && this.content.noun;
90
+ if (noun && typeof noun === 'object' && noun.one && noun.other) {
91
+ return `${total} ${this.cnTranslate(total === 1 ? noun.one : noun.other)}`
92
+ }
93
+ return translatePlural('nextcloud-vue', '%n result', '%n results', total)
94
+ },
95
+
96
+ /** @return {string} The line under the switch. */
97
+ hintText() {
98
+ return translate('nextcloud-vue', 'A message to you when there are {threshold} or more', { threshold: this.threshold })
99
+ },
100
+
101
+ /** @return {string} What shows while no saved view is applied. */
102
+ emptyText() {
103
+ const own = this.content && this.content.emptyText;
104
+ return own ? this.cnTranslate(own) : translate('nextcloud-vue', 'Save this search or open a saved one to set an alert on it.')
105
+ },
106
+ },
107
+
108
+ methods: {
109
+ t: translate,
110
+
111
+ /**
112
+ * Switch the alert on (at the shown threshold) or off.
113
+ *
114
+ * @param {boolean} on The new state.
115
+ * @return {Promise<void>}
116
+ */
117
+ async onToggle(on) {
118
+ await this.save(on ? this.alertFor(this.threshold) : null);
119
+ },
120
+
121
+ /**
122
+ * Save a new threshold, when the alert is on.
123
+ *
124
+ * @param {string} value The typed value.
125
+ * @return {Promise<void>}
126
+ */
127
+ async onThreshold(value) {
128
+ const number = Math.max(0, Math.floor(Number(value)));
129
+ if (!Number.isFinite(number)) {
130
+ return
131
+ }
132
+ this.draft = number;
133
+ await this.save(this.alertFor(number));
134
+ this.draft = null;
135
+ },
136
+
137
+ /**
138
+ * The alert the view stores: reaching the threshold tells the reader.
139
+ *
140
+ * @param {number} threshold The threshold.
141
+ * @return {{operator: string, threshold: number, recipients: Array<string>}}
142
+ */
143
+ alertFor(threshold) {
144
+ const user = getCurrentUser();
145
+ return { operator: 'gte', threshold, recipients: user && user.uid ? [user.uid] : [] }
146
+ },
147
+
148
+ /**
149
+ * PATCH the view's alert and hand the saved view back to the page.
150
+ *
151
+ * @param {object|null} alert The alert, or null to clear it.
152
+ * @return {Promise<void>}
153
+ */
154
+ async save(alert) {
155
+ if (!this.view) {
156
+ return
157
+ }
158
+ this.saving = true;
159
+ this.error = '';
160
+ try {
161
+ const saved = await useSavedViewsApi().patchView(this.view.uuid || this.view.id, { alert });
162
+ if (saved && this.cnIndexList && typeof this.cnIndexList.replaceSavedView === 'function') {
163
+ this.cnIndexList.replaceSavedView(saved);
164
+ }
165
+ } catch (error) {
166
+ this.error = (error && error.response && error.response.data && error.response.data.error) || translate('nextcloud-vue', 'The alert could not be saved.');
167
+ } finally {
168
+ this.saving = false;
169
+ }
170
+ },
171
+ },
172
+ };
173
+
174
+ export { script as default };
175
+ //# sourceMappingURL=CnSavedViewAlertWidget.vue2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnSavedViewAlertWidget.vue2.js","sources":["../../../../src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-saved-view-alert\" data-testid=\"cn-saved-view-alert\">\n\t\t<p v-if=\"!view\" class=\"cn-saved-view-alert__empty\" data-testid=\"cn-saved-view-alert-empty\">\n\t\t\t{{ emptyText }}\n\t\t</p>\n\t\t<template v-else>\n\t\t\t<dl class=\"cn-saved-view-alert__facts\">\n\t\t\t\t<dt>{{ t('nextcloud-vue', 'Name') }}</dt>\n\t\t\t\t<dd data-testid=\"cn-saved-view-alert-name\">\n\t\t\t\t\t{{ view.name }}\n\t\t\t\t</dd>\n\t\t\t\t<template v-if=\"countText\">\n\t\t\t\t\t<dt>{{ t('nextcloud-vue', 'Now') }}</dt>\n\t\t\t\t\t<dd data-testid=\"cn-saved-view-alert-count\">\n\t\t\t\t\t\t{{ countText }}\n\t\t\t\t\t</dd>\n\t\t\t\t</template>\n\t\t\t</dl>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\ttype=\"switch\"\n\t\t\t\t:modelValue=\"enabled\"\n\t\t\t\t:disabled=\"saving || !canEdit\"\n\t\t\t\tdata-testid=\"cn-saved-view-alert-switch\"\n\t\t\t\t@update:modelValue=\"onToggle\">\n\t\t\t\t<span class=\"cn-saved-view-alert__switch-text\">\n\t\t\t\t\t<span>{{ t('nextcloud-vue', 'Tell me above a number') }}</span>\n\t\t\t\t\t<span class=\"cn-saved-view-alert__hint\">{{ hintText }}</span>\n\t\t\t\t</span>\n\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t<NcTextField v-if=\"enabled\"\n\t\t\t\t:modelValue=\"String(threshold)\"\n\t\t\t\ttype=\"number\"\n\t\t\t\tmin=\"0\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Threshold')\"\n\t\t\t\t:disabled=\"saving || !canEdit\"\n\t\t\t\tdata-testid=\"cn-saved-view-alert-threshold\"\n\t\t\t\t@update:modelValue=\"onThreshold\" />\n\t\t\t<p v-if=\"error\"\n\t\t\t\tclass=\"cn-saved-view-alert__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-saved-view-alert-error\">\n\t\t\t\t{{ error }}\n\t\t\t</p>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcCheckboxRadioSwitch, NcTextField } from '@nextcloud/vue'\nimport { useSavedViewsApi } from '../../composables/useSavedViewsApi.js'\n\n/**\n * CnSavedViewAlertWidget — the saved view an index page has applied, with its\n * count alert (DqZoekresultaten \"Opgeslagen zoekopdracht\"): its name, how many\n * rows it holds now, and a switch that asks OpenRegister to tell the reader\n * when the count reaches a threshold.\n *\n * The alert is the view's own `alert` (`{ operator: 'gte', threshold,\n * recipients }`), saved with a PATCH on the view; OpenRegister evaluates it on\n * its sweep and fires on the crossing, not on the state. Switching it off\n * clears it. The widget reads the page through the `cnIndexList` CnIndexPage\n * provides, so it belongs in an index page's `sidePanel`\n * (`type: \"saved-view-alert\"`).\n *\n * Example (manifest):\n * ```json\n * { \"id\": \"alert\", \"type\": \"saved-view-alert\", \"title\": \"Saved search\", \"content\": { \"noun\": { \"one\": \"case\", \"other\": \"cases\" } } }\n * ```\n */\nexport default {\n\tname: 'CnSavedViewAlertWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcTextField },\n\n\tinject: {\n\t\t/** The index page's list: its applied saved view and its total. */\n\t\tcnIndexList: { default: null },\n\t\t/** Host translate function provided by CnAppRoot. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget content: `{ noun?: { one, other }, emptyText? }`. `noun`\n\t\t * names what is counted (\"9 zaken\"); `emptyText` shows while no saved\n\t\t * view is applied. Both are translated with the app's catalogue.\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn { saving: false, error: '', draft: null }\n\t},\n\n\tcomputed: {\n\t\t/** @return {object|null} The applied saved view, or null. */\n\t\tview() {\n\t\t\treturn (this.cnIndexList && this.cnIndexList.appliedView) || null\n\t\t},\n\n\t\t/** @return {boolean} Whether the view carries an alert. */\n\t\tenabled() {\n\t\t\tconst alert = this.view && this.view.alert\n\t\t\treturn Boolean(alert && typeof alert === 'object' && Number.isFinite(Number(alert.threshold)))\n\t\t},\n\n\t\t/** @return {number} The threshold being edited, else the view's, else 10. */\n\t\tthreshold() {\n\t\t\tif (this.draft !== null) {\n\t\t\t\treturn this.draft\n\t\t\t}\n\t\t\tconst value = this.enabled ? Number(this.view.alert.threshold) : 10\n\t\t\treturn Number.isFinite(value) ? value : 10\n\t\t},\n\n\t\t/** @return {boolean} Whether the reader may change the view: its owner, or when the view says nothing. */\n\t\tcanEdit() {\n\t\t\tconst owner = this.view && this.view.owner\n\t\t\tif (!owner) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst user = getCurrentUser()\n\t\t\treturn Boolean(user && user.uid === owner)\n\t\t},\n\n\t\t/** @return {string} \"9 zaken\", or '' while the total is unknown. */\n\t\tcountText() {\n\t\t\tconst total = this.cnIndexList ? this.cnIndexList.total : undefined\n\t\t\tif (typeof total !== 'number') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst noun = this.content && this.content.noun\n\t\t\tif (noun && typeof noun === 'object' && noun.one && noun.other) {\n\t\t\t\treturn `${total} ${this.cnTranslate(total === 1 ? noun.one : noun.other)}`\n\t\t\t}\n\t\t\treturn n('nextcloud-vue', '%n result', '%n results', total)\n\t\t},\n\n\t\t/** @return {string} The line under the switch. */\n\t\thintText() {\n\t\t\treturn t('nextcloud-vue', 'A message to you when there are {threshold} or more', { threshold: this.threshold })\n\t\t},\n\n\t\t/** @return {string} What shows while no saved view is applied. */\n\t\temptyText() {\n\t\t\tconst own = this.content && this.content.emptyText\n\t\t\treturn own ? this.cnTranslate(own) : t('nextcloud-vue', 'Save this search or open a saved one to set an alert on it.')\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Switch the alert on (at the shown threshold) or off.\n\t\t *\n\t\t * @param {boolean} on The new state.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onToggle(on) {\n\t\t\tawait this.save(on ? this.alertFor(this.threshold) : null)\n\t\t},\n\n\t\t/**\n\t\t * Save a new threshold, when the alert is on.\n\t\t *\n\t\t * @param {string} value The typed value.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onThreshold(value) {\n\t\t\tconst number = Math.max(0, Math.floor(Number(value)))\n\t\t\tif (!Number.isFinite(number)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.draft = number\n\t\t\tawait this.save(this.alertFor(number))\n\t\t\tthis.draft = null\n\t\t},\n\n\t\t/**\n\t\t * The alert the view stores: reaching the threshold tells the reader.\n\t\t *\n\t\t * @param {number} threshold The threshold.\n\t\t * @return {{operator: string, threshold: number, recipients: Array<string>}}\n\t\t */\n\t\talertFor(threshold) {\n\t\t\tconst user = getCurrentUser()\n\t\t\treturn { operator: 'gte', threshold, recipients: user && user.uid ? [user.uid] : [] }\n\t\t},\n\n\t\t/**\n\t\t * PATCH the view's alert and hand the saved view back to the page.\n\t\t *\n\t\t * @param {object|null} alert The alert, or null to clear it.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync save(alert) {\n\t\t\tif (!this.view) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst saved = await useSavedViewsApi().patchView(this.view.uuid || this.view.id, { alert })\n\t\t\t\tif (saved && this.cnIndexList && typeof this.cnIndexList.replaceSavedView === 'function') {\n\t\t\t\t\tthis.cnIndexList.replaceSavedView(saved)\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.error = (error && error.response && error.response.data && error.response.data.error) || t('nextcloud-vue', 'The alert could not be saved.')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-saved-view-alert {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tfont-size: 14px;\n}\n\n.cn-saved-view-alert__facts {\n\tdisplay: grid;\n\tgrid-template-columns: max-content 1fr;\n\tgap: 6px 16px;\n\tmargin: 0;\n}\n\n.cn-saved-view-alert__facts dt {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-saved-view-alert__facts dd {\n\tmargin: 0;\n\tfont-weight: 500;\n}\n\n.cn-saved-view-alert__switch-text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-saved-view-alert__hint,\n.cn-saved-view-alert__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-saved-view-alert__empty,\n.cn-saved-view-alert__error {\n\tmargin: 0;\n}\n\n.cn-saved-view-alert__error {\n\tcolor: var(--color-error-text, var(--color-error));\n\tfont-size: 13px;\n}\n</style>\n"],"names":["n","t"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import { resolveComponent, openBlock, createElementBlock, toDisplayString, Fragment, createElementVNode, createCommentVNode, createVNode, withCtx, createBlock } from 'vue';
2
+
3
+ const _hoisted_1 = {
4
+ class: "cn-saved-view-alert",
5
+ "data-testid": "cn-saved-view-alert"
6
+ };
7
+ const _hoisted_2 = {
8
+ key: 0,
9
+ class: "cn-saved-view-alert__empty",
10
+ "data-testid": "cn-saved-view-alert-empty"
11
+ };
12
+ const _hoisted_3 = { class: "cn-saved-view-alert__facts" };
13
+ const _hoisted_4 = { "data-testid": "cn-saved-view-alert-name" };
14
+ const _hoisted_5 = { "data-testid": "cn-saved-view-alert-count" };
15
+ const _hoisted_6 = { class: "cn-saved-view-alert__switch-text" };
16
+ const _hoisted_7 = { class: "cn-saved-view-alert__hint" };
17
+ const _hoisted_8 = {
18
+ key: 1,
19
+ class: "cn-saved-view-alert__error",
20
+ role: "alert",
21
+ "data-testid": "cn-saved-view-alert-error"
22
+ };
23
+
24
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
25
+ const _component_NcCheckboxRadioSwitch = resolveComponent("NcCheckboxRadioSwitch");
26
+ const _component_NcTextField = resolveComponent("NcTextField");
27
+
28
+ return (openBlock(), createElementBlock("div", _hoisted_1, [
29
+ (!$options.view)
30
+ ? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString($options.emptyText), 1 /* TEXT */))
31
+ : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
32
+ createElementVNode("dl", _hoisted_3, [
33
+ createElementVNode("dt", null, toDisplayString($options.t('nextcloud-vue', 'Name')), 1 /* TEXT */),
34
+ createElementVNode("dd", _hoisted_4, toDisplayString($options.view.name), 1 /* TEXT */),
35
+ ($options.countText)
36
+ ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
37
+ createElementVNode("dt", null, toDisplayString($options.t('nextcloud-vue', 'Now')), 1 /* TEXT */),
38
+ createElementVNode("dd", _hoisted_5, toDisplayString($options.countText), 1 /* TEXT */)
39
+ ], 64 /* STABLE_FRAGMENT */))
40
+ : createCommentVNode("v-if", true)
41
+ ]),
42
+ createVNode(_component_NcCheckboxRadioSwitch, {
43
+ type: "switch",
44
+ modelValue: $options.enabled,
45
+ disabled: $data.saving || !$options.canEdit,
46
+ "data-testid": "cn-saved-view-alert-switch",
47
+ "onUpdate:modelValue": $options.onToggle
48
+ }, {
49
+ default: withCtx(() => [
50
+ createElementVNode("span", _hoisted_6, [
51
+ createElementVNode("span", null, toDisplayString($options.t('nextcloud-vue', 'Tell me above a number')), 1 /* TEXT */),
52
+ createElementVNode("span", _hoisted_7, toDisplayString($options.hintText), 1 /* TEXT */)
53
+ ])
54
+ ]),
55
+ _: 1 /* STABLE */
56
+ }, 8 /* PROPS */, ["modelValue", "disabled", "onUpdate:modelValue"]),
57
+ ($options.enabled)
58
+ ? (openBlock(), createBlock(_component_NcTextField, {
59
+ key: 0,
60
+ modelValue: String($options.threshold),
61
+ type: "number",
62
+ min: "0",
63
+ label: $options.t('nextcloud-vue', 'Threshold'),
64
+ disabled: $data.saving || !$options.canEdit,
65
+ "data-testid": "cn-saved-view-alert-threshold",
66
+ "onUpdate:modelValue": $options.onThreshold
67
+ }, null, 8 /* PROPS */, ["modelValue", "label", "disabled", "onUpdate:modelValue"]))
68
+ : createCommentVNode("v-if", true),
69
+ ($data.error)
70
+ ? (openBlock(), createElementBlock("p", _hoisted_8, toDisplayString($data.error), 1 /* TEXT */))
71
+ : createCommentVNode("v-if", true)
72
+ ], 64 /* STABLE_FRAGMENT */))
73
+ ]))
74
+ }
75
+
76
+ export { render };
77
+ //# sourceMappingURL=CnSavedViewAlertWidget.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnSavedViewAlertWidget.vue3.js","sources":["../../../../src/components/CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue?vue&type=template&id=4439a3f3&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-saved-view-alert\" data-testid=\"cn-saved-view-alert\">\n\t\t<p v-if=\"!view\" class=\"cn-saved-view-alert__empty\" data-testid=\"cn-saved-view-alert-empty\">\n\t\t\t{{ emptyText }}\n\t\t</p>\n\t\t<template v-else>\n\t\t\t<dl class=\"cn-saved-view-alert__facts\">\n\t\t\t\t<dt>{{ t('nextcloud-vue', 'Name') }}</dt>\n\t\t\t\t<dd data-testid=\"cn-saved-view-alert-name\">\n\t\t\t\t\t{{ view.name }}\n\t\t\t\t</dd>\n\t\t\t\t<template v-if=\"countText\">\n\t\t\t\t\t<dt>{{ t('nextcloud-vue', 'Now') }}</dt>\n\t\t\t\t\t<dd data-testid=\"cn-saved-view-alert-count\">\n\t\t\t\t\t\t{{ countText }}\n\t\t\t\t\t</dd>\n\t\t\t\t</template>\n\t\t\t</dl>\n\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\ttype=\"switch\"\n\t\t\t\t:modelValue=\"enabled\"\n\t\t\t\t:disabled=\"saving || !canEdit\"\n\t\t\t\tdata-testid=\"cn-saved-view-alert-switch\"\n\t\t\t\t@update:modelValue=\"onToggle\">\n\t\t\t\t<span class=\"cn-saved-view-alert__switch-text\">\n\t\t\t\t\t<span>{{ t('nextcloud-vue', 'Tell me above a number') }}</span>\n\t\t\t\t\t<span class=\"cn-saved-view-alert__hint\">{{ hintText }}</span>\n\t\t\t\t</span>\n\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t<NcTextField v-if=\"enabled\"\n\t\t\t\t:modelValue=\"String(threshold)\"\n\t\t\t\ttype=\"number\"\n\t\t\t\tmin=\"0\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Threshold')\"\n\t\t\t\t:disabled=\"saving || !canEdit\"\n\t\t\t\tdata-testid=\"cn-saved-view-alert-threshold\"\n\t\t\t\t@update:modelValue=\"onThreshold\" />\n\t\t\t<p v-if=\"error\"\n\t\t\t\tclass=\"cn-saved-view-alert__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-saved-view-alert-error\">\n\t\t\t\t{{ error }}\n\t\t\t</p>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcCheckboxRadioSwitch, NcTextField } from '@nextcloud/vue'\nimport { useSavedViewsApi } from '../../composables/useSavedViewsApi.js'\n\n/**\n * CnSavedViewAlertWidget — the saved view an index page has applied, with its\n * count alert (DqZoekresultaten \"Opgeslagen zoekopdracht\"): its name, how many\n * rows it holds now, and a switch that asks OpenRegister to tell the reader\n * when the count reaches a threshold.\n *\n * The alert is the view's own `alert` (`{ operator: 'gte', threshold,\n * recipients }`), saved with a PATCH on the view; OpenRegister evaluates it on\n * its sweep and fires on the crossing, not on the state. Switching it off\n * clears it. The widget reads the page through the `cnIndexList` CnIndexPage\n * provides, so it belongs in an index page's `sidePanel`\n * (`type: \"saved-view-alert\"`).\n *\n * Example (manifest):\n * ```json\n * { \"id\": \"alert\", \"type\": \"saved-view-alert\", \"title\": \"Saved search\", \"content\": { \"noun\": { \"one\": \"case\", \"other\": \"cases\" } } }\n * ```\n */\nexport default {\n\tname: 'CnSavedViewAlertWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcTextField },\n\n\tinject: {\n\t\t/** The index page's list: its applied saved view and its total. */\n\t\tcnIndexList: { default: null },\n\t\t/** Host translate function provided by CnAppRoot. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget content: `{ noun?: { one, other }, emptyText? }`. `noun`\n\t\t * names what is counted (\"9 zaken\"); `emptyText` shows while no saved\n\t\t * view is applied. Both are translated with the app's catalogue.\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn { saving: false, error: '', draft: null }\n\t},\n\n\tcomputed: {\n\t\t/** @return {object|null} The applied saved view, or null. */\n\t\tview() {\n\t\t\treturn (this.cnIndexList && this.cnIndexList.appliedView) || null\n\t\t},\n\n\t\t/** @return {boolean} Whether the view carries an alert. */\n\t\tenabled() {\n\t\t\tconst alert = this.view && this.view.alert\n\t\t\treturn Boolean(alert && typeof alert === 'object' && Number.isFinite(Number(alert.threshold)))\n\t\t},\n\n\t\t/** @return {number} The threshold being edited, else the view's, else 10. */\n\t\tthreshold() {\n\t\t\tif (this.draft !== null) {\n\t\t\t\treturn this.draft\n\t\t\t}\n\t\t\tconst value = this.enabled ? Number(this.view.alert.threshold) : 10\n\t\t\treturn Number.isFinite(value) ? value : 10\n\t\t},\n\n\t\t/** @return {boolean} Whether the reader may change the view: its owner, or when the view says nothing. */\n\t\tcanEdit() {\n\t\t\tconst owner = this.view && this.view.owner\n\t\t\tif (!owner) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst user = getCurrentUser()\n\t\t\treturn Boolean(user && user.uid === owner)\n\t\t},\n\n\t\t/** @return {string} \"9 zaken\", or '' while the total is unknown. */\n\t\tcountText() {\n\t\t\tconst total = this.cnIndexList ? this.cnIndexList.total : undefined\n\t\t\tif (typeof total !== 'number') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst noun = this.content && this.content.noun\n\t\t\tif (noun && typeof noun === 'object' && noun.one && noun.other) {\n\t\t\t\treturn `${total} ${this.cnTranslate(total === 1 ? noun.one : noun.other)}`\n\t\t\t}\n\t\t\treturn n('nextcloud-vue', '%n result', '%n results', total)\n\t\t},\n\n\t\t/** @return {string} The line under the switch. */\n\t\thintText() {\n\t\t\treturn t('nextcloud-vue', 'A message to you when there are {threshold} or more', { threshold: this.threshold })\n\t\t},\n\n\t\t/** @return {string} What shows while no saved view is applied. */\n\t\temptyText() {\n\t\t\tconst own = this.content && this.content.emptyText\n\t\t\treturn own ? this.cnTranslate(own) : t('nextcloud-vue', 'Save this search or open a saved one to set an alert on it.')\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Switch the alert on (at the shown threshold) or off.\n\t\t *\n\t\t * @param {boolean} on The new state.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onToggle(on) {\n\t\t\tawait this.save(on ? this.alertFor(this.threshold) : null)\n\t\t},\n\n\t\t/**\n\t\t * Save a new threshold, when the alert is on.\n\t\t *\n\t\t * @param {string} value The typed value.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync onThreshold(value) {\n\t\t\tconst number = Math.max(0, Math.floor(Number(value)))\n\t\t\tif (!Number.isFinite(number)) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.draft = number\n\t\t\tawait this.save(this.alertFor(number))\n\t\t\tthis.draft = null\n\t\t},\n\n\t\t/**\n\t\t * The alert the view stores: reaching the threshold tells the reader.\n\t\t *\n\t\t * @param {number} threshold The threshold.\n\t\t * @return {{operator: string, threshold: number, recipients: Array<string>}}\n\t\t */\n\t\talertFor(threshold) {\n\t\t\tconst user = getCurrentUser()\n\t\t\treturn { operator: 'gte', threshold, recipients: user && user.uid ? [user.uid] : [] }\n\t\t},\n\n\t\t/**\n\t\t * PATCH the view's alert and hand the saved view back to the page.\n\t\t *\n\t\t * @param {object|null} alert The alert, or null to clear it.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync save(alert) {\n\t\t\tif (!this.view) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.error = ''\n\t\t\ttry {\n\t\t\t\tconst saved = await useSavedViewsApi().patchView(this.view.uuid || this.view.id, { alert })\n\t\t\t\tif (saved && this.cnIndexList && typeof this.cnIndexList.replaceSavedView === 'function') {\n\t\t\t\t\tthis.cnIndexList.replaceSavedView(saved)\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.error = (error && error.response && error.response.data && error.response.data.error) || t('nextcloud-vue', 'The alert could not be saved.')\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-saved-view-alert {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tfont-size: 14px;\n}\n\n.cn-saved-view-alert__facts {\n\tdisplay: grid;\n\tgrid-template-columns: max-content 1fr;\n\tgap: 6px 16px;\n\tmargin: 0;\n}\n\n.cn-saved-view-alert__facts dt {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-saved-view-alert__facts dd {\n\tmargin: 0;\n\tfont-weight: 500;\n}\n\n.cn-saved-view-alert__switch-text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-saved-view-alert__hint,\n.cn-saved-view-alert__empty {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-saved-view-alert__empty,\n.cn-saved-view-alert__error {\n\tmargin: 0;\n}\n\n.cn-saved-view-alert__error {\n\tcolor: var(--color-error-text, var(--color-error));\n\tfont-size: 13px;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_toDisplayString","_createElementVNode","_Fragment","_createVNode","_createBlock"],"mappings":";;;AASM,EAAA,KAAI,EAAE,qBAAM;AAAA,EAAA,aAAA,EAAA,qBAAA;;;;AACA,EAAA,KAAK,EAAC,4BAAiB;AAAA,EAAA,aAAA,EAAA,2BAAA;;AAIlC,MAAA,UAAA,GAAA,EAAA,KAAC,EAAA,4BAAA,GAAA;AAEA,MAAA,UAAA,GAAA,EAAA,aAAW,EAAC,0BAAwB,GAAA;AAKrC,MAAA,UAAA,GAAA,EAAA,aAAA,EAAA,2BAAA,GAAA;AAWG,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,kCAAU,GAAA;AAEf,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,2BAAiB,GAAA;;;AAY9B,EAAA,KAAE,EAAA,4BAAA;AACF,EAAA,IAAI,EAAC,OAAG;AACR,EAAA,aAAE,EAAA,2BAAA;;;;;;;AAvCJ,EAAA,QAAAA,SAAA,EAAA,EAAAC,kBAAA,QAAA;MACU,QAAI,CAAA,IAAA;sBAAbA,kBAEG,CAAA,GAAA,EAFH,UAEG,EAAAC,eAAA,CADA,QAAS,CAAA,SAAA,CAAA,EAAA,CAAA,YAAA;;6BAcP,gBAAA,EAAA;AAVJ,YAAAC,kBAAA,CAA0B,4BAAnB,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,MAAA,CAAA,CAAA,EAAA,CAAA,YAAA;AACP,YAAAA,kBAAA,CAEI,IAFJ,EAAA,UAEI,EADAD,eAAA,CAAA,QAAA,CAAA,IAAG,CAAC,IAAI,CAAA,EAAA,CAAA,YAAA;aAER,QAAA,CAAA,SAAA;gDAKM,CAAAE,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAA;AAJV,kBAAAD,kBAAA,CAAS,4BAAF,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;kBACRA,kBAEK,CAAA,IAAA,EAFL,UAEK,EAAAD,eAAA,CADD,QAAS,CAAA,SAAA,CAAA,EAAA,CAAA,YAAA;;;;UAIdG,WAUM,CAAA,gCAAA,EAAA;AATN,YAAA,IAAI,EAAC,QAAQ;AACZ,YAAA,UAAU,EAAE,QAAO,CAAA,OAAA;YACnB,QAAS,EAAC,KAAM,CAAA,MAAA,IAAA,CAAK,QAAO,CAAA,OAAA;yBAClB,EAAC,4BAA4B;AACvC,YAAA,qBAAK,EAAA,QAAA,CAAA,QAAA;;6BACN,MAGO;AAHP,cAAAF,kBAAA,CAGO,QAHP,UAGO,EAAA;AAFN,gBAAAA,kBAAA,CAAwB,8BAAf,QAAA,CAAA,CAAA,CAAA,eAAA,EAAA,wBAAA,CAAA,CAAA,EAAA,CAAA,YAAA;gBACTA,kBAA6B,CAAA,MAAA,EAA7B,UAA6B,EAAAD,eAAA,CAAA,QAAA,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;;;;;WAGZ,QAAO,CAAA,OAAA;4BAAzBI,WAOmC,CAAA,sBAAA,EAAA;;gBANlC,UAAU,EAAE,MAAM,CAAE,QAAQ,CAAA,SAAA,CAAA;AAC7B,gBAAA,IAAI,EAAC,QAAQ;AACb,gBAAA,GAAG,EAAC,GAAG;AACP,gBAAA,KAAM,EAAE,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,WAAA,CAAA;gBACR,QAAQ,EAAE,KAAM,CAAA,MAAA,IAAA,CAAK,QAAO,CAAA,OAAA;AAC7B,gBAAA,aAAW,EAAA,+BAAA;AACV,gBAAA,qBAAiB,EAAE,QAAW,CAAA,WAAA;;;gBACrB,CAAA,KAAA;4BAAVL,wBAAA;;;;;;;;"}
@@ -2,7 +2,7 @@ import script from './CnSetupWizard.vue2.js';
2
2
  import { render } from './CnSetupWizard.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-32874a44";
5
+ script.__scopeId = "data-v-44988d3d";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -223,7 +223,7 @@ var script = {
223
223
  */
224
224
  setup(props) {
225
225
  const { isBoard } = useLook();
226
- const wantsSource = (props.steps || []).some((s) => s && s.optionsSource);
226
+ const wantsSource = (props.steps || []).some((s) => s && (s.optionsSource || s.visibleWhen));
227
227
  if (!wantsSource) {
228
228
  return { isBoard }
229
229
  }
@@ -291,7 +291,7 @@ var script = {
291
291
 
292
292
  setupSteps() {
293
293
  const skipped = new Set(this.skippedSteps.map((entry) => entry.step.id));
294
- return this.declaredSteps.filter((s) => !skipped.has(s.id))
294
+ return this.declaredSteps.filter((s) => !skipped.has(s.id) && this.stepConditionHolds(s))
295
295
  },
296
296
 
297
297
  /**
@@ -654,6 +654,39 @@ var script = {
654
654
  })
655
655
  },
656
656
 
657
+ /**
658
+ * Whether a step's `visibleWhen` holds: the value at that path in the
659
+ * setup status (`"flags.hasPayouts"`, dots walk into objects) is truthy,
660
+ * or equals `equals` when the step gives `{ path, equals }`. A step
661
+ * without `visibleWhen` always shows; one with it stays hidden until the
662
+ * status says so, also while the status loads (DqInstellen: the dwangsom
663
+ * step only when the app pays penalties).
664
+ *
665
+ * @param {object} step The step declaration.
666
+ * @return {boolean}
667
+ */
668
+ stepConditionHolds(step) {
669
+ const when = step && step.visibleWhen;
670
+ if (when === undefined || when === null || when === '') {
671
+ return true
672
+ }
673
+ const path = typeof when === 'string' ? when : when.path;
674
+ if (typeof path !== 'string' || path === '') {
675
+ return true
676
+ }
677
+ let node = this.setupStatus;
678
+ for (const key of path.split('.')) {
679
+ if (node === null || node === undefined || typeof node !== 'object') {
680
+ return false
681
+ }
682
+ node = node[key];
683
+ }
684
+ if (typeof when === 'object' && Object.hasOwn(when, 'equals')) {
685
+ return node === when.equals
686
+ }
687
+ return Boolean(node)
688
+ },
689
+
657
690
  /**
658
691
  * The option list a `choice` step declares `optionsSource` for, read
659
692
  * from the setup status document the app already serves.