@conduction/nextcloud-vue 2.104.0 → 2.105.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 (110) hide show
  1. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
  2. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
  4. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.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 +93 -1
  7. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  8. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  9. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  10. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +6 -3
  11. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  12. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +3 -3
  13. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  14. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +59 -1
  15. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  16. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  17. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
  18. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +1 -1
  19. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  20. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  21. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +1 -1
  22. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +2 -0
  23. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -1
  24. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +32 -29
  25. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -1
  26. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
  27. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +73 -4
  28. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
  29. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +74 -27
  30. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
  31. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +54 -1
  32. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  33. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  34. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +3 -2
  35. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  36. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js +9 -0
  37. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js.map +1 -0
  38. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js +88 -0
  39. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js.map +1 -0
  40. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js +39 -0
  41. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js.map +1 -0
  42. package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +1 -1
  43. package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -1
  44. package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +3 -3
  45. package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -1
  46. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
  47. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  48. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +16 -4
  49. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  50. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
  51. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +11 -0
  52. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
  53. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +4 -4
  54. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
  55. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +16 -14
  56. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
  57. package/dist/esm/index.js +1 -0
  58. package/dist/esm/index.js.map +1 -1
  59. package/dist/esm/l10n/en.json.js +4 -1
  60. package/dist/esm/l10n/en.json.js.map +1 -1
  61. package/dist/esm/l10n/nl.json.js +4 -1
  62. package/dist/esm/l10n/nl.json.js.map +1 -1
  63. package/dist/esm/library-style.js +1 -1
  64. package/dist/esm/nextcloud-vue.css +566 -295
  65. package/dist/esm/utils/libraryWidgetKeys.js +1 -0
  66. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  67. package/dist/esm/utils/nextcloudApps.js +45 -0
  68. package/dist/esm/utils/nextcloudApps.js.map +1 -0
  69. package/dist/esm/utils/scopeListLayout.js +9 -2
  70. package/dist/esm/utils/scopeListLayout.js.map +1 -1
  71. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  72. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  73. package/dist/esm/utils/visibleWhen.js +12 -4
  74. package/dist/esm/utils/visibleWhen.js.map +1 -1
  75. package/dist/nextcloud-vue.cjs.js +3054 -2517
  76. package/dist/nextcloud-vue.cjs.js.map +2 -2
  77. package/dist/nextcloud-vue.css +566 -295
  78. package/l10n/en.json +4 -1
  79. package/l10n/nl.json +4 -1
  80. package/package.json +1 -1
  81. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -1
  82. package/src/components/CnChartWidget/CnChartWidget.md +2 -0
  83. package/src/components/CnChartWidget/CnChartWidget.vue +93 -1
  84. package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -6
  85. package/src/components/CnDetailPage/CnDetailPage.md +1 -0
  86. package/src/components/CnDetailPage/CnDetailPage.vue +59 -1
  87. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -1
  88. package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +4 -1
  89. package/src/components/CnFlowsPage/CnFlowBoard.vue +132 -8
  90. package/src/components/CnIndexPage/CnIndexPage.md +1 -0
  91. package/src/components/CnIndexPage/CnIndexPage.vue +54 -1
  92. package/src/components/CnIndexPage/useSelfFetchList.js +3 -2
  93. package/src/components/CnNoticeWidget/CnNoticeWidget.vue +153 -0
  94. package/src/components/CnNoticeWidget/index.js +12 -0
  95. package/src/components/CnSettingsField/CnSettingsField.vue +4 -1
  96. package/src/components/CnSetupWizard/CnSetupWizard.vue +9 -1
  97. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +15 -4
  98. package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
  99. package/src/components/index.js +1 -0
  100. package/src/css/dialog.css +20 -2
  101. package/src/css/look-board-detail.css +77 -4
  102. package/src/css/look-board-index.css +36 -2
  103. package/src/css/look-board.css +97 -12
  104. package/src/index.js +1 -0
  105. package/src/schemas/app-manifest-v2.schema.json +36 -3
  106. package/src/utils/libraryWidgetKeys.js +1 -0
  107. package/src/utils/nextcloudApps.js +50 -0
  108. package/src/utils/scopeListLayout.js +9 -2
  109. package/src/utils/validateManifestV2.compiled.js +3 -3
  110. package/src/utils/visibleWhen.js +12 -4
@@ -27,6 +27,8 @@
27
27
  /* Cards. */
28
28
  --cn-board-card-radius: 12px;
29
29
  --cn-board-card-padding: 20px 22px;
30
+ /* The side inset of a dashboard card: its title and its rows. */
31
+ --cn-board-dashboard-card-inset: 24px;
30
32
  /* Hairline inside a card, and the soft secondary text. */
31
33
  --cn-board-hairline: var(--color-border);
32
34
  --cn-board-text-soft: var(--color-main-text);
@@ -56,6 +58,23 @@
56
58
  margin-inline: 0;
57
59
  }
58
60
 
61
+ /* The page shows the content area's ground (the theme's content surface,
62
+ light grey on the boards) and draws none of its own; only its cards are
63
+ white. A theme rule that paints every `[class*="panel"]` with the main
64
+ background (the nldesign theme's element overrides) caught an index page
65
+ with a side panel (`cn-index-page--with-side-panel`) and drew the whole
66
+ page white (DqTeamwachtrij). That rule carries an id through
67
+ `:not(#header *)`, so this one names an id in `:not()` to outrank it.
68
+ @spec openspec/changes/board-page-ground/specs/board-page-ground/spec.md#requirement-a-board-page-draws-no-ground-of-its-own */
69
+ .cn-look-board .cn-index-page:not(#cn-board-page-ground):not(.cn-look-nextcloud *),
70
+ .cn-look-board .cn-detail-page:not(#cn-board-page-ground):not(.cn-look-nextcloud *),
71
+ .cn-look-board .cn-dashboard-page:not(#cn-board-page-ground):not(.cn-look-nextcloud *),
72
+ .cn-look-board .cn-settings-page:not(#cn-board-page-ground):not(.cn-look-nextcloud *),
73
+ .cn-look-board .cn-store-page:not(#cn-board-page-ground):not(.cn-look-nextcloud *),
74
+ .cn-look-board .cn-admin-settings-shell:not(#cn-board-page-ground):not(.cn-look-nextcloud *) {
75
+ background-color: transparent;
76
+ }
77
+
59
78
  .cn-look-board .cn-index-page:not(.cn-look-nextcloud *),
60
79
  .cn-look-board .cn-settings-page:not(.cn-look-nextcloud *) {
61
80
  gap: var(--cn-board-section-gap);
@@ -155,6 +174,27 @@
155
174
  gap: 10px;
156
175
  }
157
176
 
177
+ /* The nldesign theme paints every primary and secondary button with
178
+ `!important` through its button tokens: weight 700, and a secondary in
179
+ the primary colour with a primary border on no ground. The board draws
180
+ header buttons at 600, the secondary on the main background with a grey
181
+ border (DqMijnWerk, DqZaak, DqZaken). The look hands the theme those values
182
+ through the same tokens, so the theme's own rules draw the board's button.
183
+ @spec openspec/changes/board-header-buttons-theme/specs/board-header-buttons-theme/spec.md#requirement-board-header-buttons-keep-the-boards-weight-and-ground-under-a-theme */
184
+ .cn-look-board .cn-index-page__header-buttons:not(.cn-look-nextcloud *),
185
+ .cn-look-board .cn-detail-page__header-actions:not(.cn-look-nextcloud *),
186
+ .cn-look-board .cn-dashboard-page__header-actions:not(.cn-look-nextcloud *),
187
+ .cn-look-board .cn-settings-page__header-buttons:not(.cn-look-nextcloud *),
188
+ .cn-look-board .cn-admin-settings-shell__header-buttons:not(.cn-look-nextcloud *),
189
+ .cn-look-board .cn-action-buttons:not(.cn-look-nextcloud *) {
190
+ --nldesign-component-button-font-weight: 600;
191
+ --nldesign-component-button-primary-action-font-weight: 600;
192
+ --nldesign-component-button-secondary-action-color: var(--color-main-text);
193
+ --nldesign-component-button-secondary-action-background-color: var(--color-main-background);
194
+ --nldesign-component-button-secondary-action-border-color: var(--color-border-dark);
195
+ --nldesign-component-button-secondary-action-hover-background-color: var(--color-background-hover);
196
+ }
197
+
158
198
  .cn-look-board .cn-index-page__header-buttons:not(.cn-look-nextcloud *) .button-vue,
159
199
  .cn-look-board .cn-detail-page__header-actions:not(.cn-look-nextcloud *) .button-vue,
160
200
  .cn-look-board .cn-dashboard-page__header-actions:not(.cn-look-nextcloud *) .button-vue,
@@ -1158,6 +1198,20 @@
1158
1198
  line-height: 1.3;
1159
1199
  }
1160
1200
 
1201
+ /* The board draws no rule under a dashboard card's title (DqMijnWerk,
1202
+ DqDashboard, PqMijnWerk): the title sits 20px from the card's top and on
1203
+ the card's 24px side inset, the line its rows start on, 12px above the
1204
+ content. A borderless card has no edge to inset from and keeps the
1205
+ wrapper's padding.
1206
+ @spec openspec/changes/board-dashboard-card-header/specs/board-dashboard-card-header/spec.md#requirement-a-board-dashboard-card-draws-no-header-rule */
1207
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--nc-dashboard) .cn-widget-wrapper__header {
1208
+ border-bottom: none;
1209
+ }
1210
+
1211
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--nc-dashboard):not(.cn-widget-wrapper--borderless) .cn-widget-wrapper__header {
1212
+ padding: 20px var(--cn-board-dashboard-card-inset) 12px;
1213
+ }
1214
+
1161
1215
  /* ---- Record list on a dashboard card (PtDashboard) ---------------------- */
1162
1216
  /* The dashboard's card body is flush, so the rows carry their own inset: the
1163
1217
  board's card pads 24px at the sides and each row 14px, a soft hairline
@@ -1274,6 +1328,47 @@
1274
1328
  display: none;
1275
1329
  }
1276
1330
 
1331
+ /* ---- Widgets that drew their rows on the card's edge -------------------- */
1332
+ /* The card body is flush, so a widget carries the card's side inset itself,
1333
+ as the record list and saved views do. Without it the task list's
1334
+ checkboxes, the step bar and its legend, the week strip's days, the bar
1335
+ list and the activity items started on the card's edge, and a table's
1336
+ first column 16px in (DqMijnWerk "Mijn taken", "Mijn 14 zaken per stap",
1337
+ "Termijnen deze week", "Recente activiteit"; DqDashboard "Zaken per
1338
+ status", "Vastgelopen zaken"). The top inset is 4px: with the header's
1339
+ 12px it is the board's 16px from title to bar. This also replaces the
1340
+ step bar's and week strip's opt-in `content.inset` on a board dashboard.
1341
+ A borderless card stands on the page ground and keeps its rows flush.
1342
+ @spec openspec/changes/board-dashboard-widget-inset/specs/board-dashboard-widget-inset/spec.md#requirement-a-board-dashboard-widget-keeps-the-cards-side-inset */
1343
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-tasks-widget {
1344
+ padding: 0 var(--cn-board-dashboard-card-inset) 10px;
1345
+ }
1346
+
1347
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-stacked-bar,
1348
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-week-strip {
1349
+ box-sizing: border-box;
1350
+ padding: 4px var(--cn-board-dashboard-card-inset) 22px;
1351
+ }
1352
+
1353
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-chart-widget__html {
1354
+ padding: 4px var(--cn-board-dashboard-card-inset) 20px;
1355
+ }
1356
+
1357
+ /* An activity item pads itself 4px, so the body takes 4px less. */
1358
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-nc-widget-widget__body {
1359
+ padding: 0 calc(var(--cn-board-dashboard-card-inset) - 4px) 16px;
1360
+ }
1361
+
1362
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-widget-object-table .cn-data-table th:first-child,
1363
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-widget-object-table .cn-data-table td:first-child {
1364
+ padding-inline-start: var(--cn-board-dashboard-card-inset);
1365
+ }
1366
+
1367
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-widget-object-table .cn-data-table th:last-child,
1368
+ .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:not(.cn-widget-wrapper--borderless) .cn-widget-object-table .cn-data-table td:last-child {
1369
+ padding-inline-end: var(--cn-board-dashboard-card-inset);
1370
+ }
1371
+
1277
1372
  /* ---- Week strip (DqMijnWerk "Termijnen deze week") ---------------------- */
1278
1373
  /* The days wrap inside the card instead of scrolling sideways: a row holds
1279
1374
  as many days of at least 120px as the card fits, and the rest go to the
@@ -1293,23 +1388,13 @@
1293
1388
  flex-wrap: wrap;
1294
1389
  }
1295
1390
 
1296
- /* ---- Bar-list and matrix cards (DqDashboard) ----------------------------- */
1297
- /* The board draws no rule under the title of a card holding a bar list or a
1298
- matrix. Other cards, plain stat tiles among them, keep theirs.
1299
- @spec openspec/changes/chart-bar-list-and-matrix/specs/chart-bar-list-and-matrix/spec.md#requirement-board-bar-list-and-matrix-cards-draw-no-header-rule */
1300
- .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:has(.cn-chart-widget__html) .cn-widget-wrapper__header {
1301
- border-bottom: none;
1302
- }
1303
-
1304
1391
  /* ---- A card of boxed stat tiles (DcRapportages "Vergaderingen en efficiëntie") -- */
1305
1392
  /* The board draws this card 22px from its edge on every side but the bottom
1306
- (20px), the header 14px above the tiles, and no rule under the header. The
1307
- card-fit cell padding (8px 14px) plus the grid's own 24px came to 38px at
1308
- the sides, with the wrapper's divider under the title.
1393
+ (20px) and the header 14px above the tiles. The card-fit cell padding
1394
+ (8px 14px) plus the grid's own 24px came to 38px at the sides.
1309
1395
  @spec openspec/changes/stats-box-card-inset/specs/stats-box-card-inset/spec.md#requirement-a-card-of-boxed-stat-tiles-keeps-the-boards-inset */
1310
1396
  .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:has(.cn-stats-block-widget--tiles-box) .cn-widget-wrapper__header {
1311
1397
  padding: 20px 22px 0;
1312
- border-bottom: none;
1313
1398
  }
1314
1399
 
1315
1400
  .cn-look-board .cn-dashboard-page:not(.cn-look-nextcloud *) .cn-widget-wrapper:has(.cn-stats-block-widget--tiles-box) .cn-widget-wrapper__content {
package/src/index.js CHANGED
@@ -220,6 +220,7 @@ export {
220
220
  CnNotepadWidget,
221
221
  CnNotepadWidgetForm,
222
222
  CnNotesCard,
223
+ CnNoticeWidget,
223
224
  CnNotificationMatrix,
224
225
  CnNotificationPreferences,
225
226
  CnObjectAccessTab,
@@ -3,7 +3,7 @@
3
3
  "$id": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest-v2.schema.json",
4
4
  "title": "Conduction App Manifest v2",
5
5
  "description": "v2 schema for the JSON-driven page and navigation manifest consumed by @conduction/nextcloud-vue. Introduces a uniform widgets[] array on every page type with a per-slot grid coordinate system, a typed actions[] discriminator, and the required $schema field for version detection. v1 manifests continue to validate against app-manifest.schema.json (unchanged).",
6
- "version": "2.127.0",
6
+ "version": "2.128.0",
7
7
  "type": "object",
8
8
  "required": ["$schema", "version"],
9
9
  "allOf": [
@@ -120,6 +120,7 @@
120
120
  "optionsByParent": { "type": "object", "description": "choice: map of parent-choice value → options[] for a dependent (dependsOn) choice. Same option item shape as `options`.", "additionalProperties": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": {}, "label": { "type": "string" } } } } },
121
121
  "suggestFrom": { "type": "string", "description": "choice: the configKey of an earlier choice this step pre-fills a suggestion from. When that value is set and the user has not yet picked here, the option matching suggestMap[parentValue] is auto-selected (still user-overridable)." },
122
122
  "default": { "description": "choice: the option value chosen when the step opens (an array of values with `multiple`). Not applied to a step the server already completed." },
123
+ "noteStyle": { "type": "string", "enum": ["line", "card"], "default": "line", "description": "choice: how `note` is drawn: a muted line under the options (`line`) or an info note card (`card`)." },
123
124
  "suggestMap": { "type": "object", "description": "choice: map of suggestFrom value → suggested option value. Used to auto-suggest a default (e.g. RGS template suggested from organisation type).", "additionalProperties": { "type": "string" } },
124
125
  "multiple": { "type": "boolean", "default": false, "description": "choice: allow multi-select." },
125
126
  "loadAction": { "type": "string", "minLength": 1, "description": "choice with display cards: an actionId each option card loads itself with. Every card except the one whose value is `none` gets its own Load button, which POSTs { dataset: <value> } to /api/setup/action/{loadAction}, spins while it runs and shows the result on that card. A successful load also selects the card. With loadAction the separate run-action step that loaded the picked dataset is no longer needed; manifests that keep it still work." },
@@ -2209,6 +2210,31 @@
2209
2210
  }
2210
2211
  }
2211
2212
  },
2213
+ {
2214
+ "description": "notice built-in widget (CnNoticeWidget): one toned box with an icon, a bold title and a text, through the host's translate, in the side column or the grid (DqSociaalDomein, 2.128.0).",
2215
+ "if": {
2216
+ "properties": { "widgetKey": { "const": "notice" } },
2217
+ "required": ["widgetKey"]
2218
+ },
2219
+ "then": {
2220
+ "properties": {
2221
+ "props": {
2222
+ "type": "object",
2223
+ "properties": {
2224
+ "content": {
2225
+ "type": "object",
2226
+ "properties": {
2227
+ "variant": { "type": "string", "enum": ["info", "warning", "error", "success"], "default": "info" },
2228
+ "title": { "type": "string" },
2229
+ "text": { "type": "string" },
2230
+ "icon": { "type": "string", "minLength": 1 }
2231
+ }
2232
+ }
2233
+ }
2234
+ }
2235
+ }
2236
+ }
2237
+ },
2212
2238
  {
2213
2239
  "description": "audit-trail built-in widget (CnAuditTrailWidget, Wave 1): the object change-log card. All props are optional — register/schema/objectId normally arrive via the detail-page object-context merge; explicit props win.",
2214
2240
  "if": {
@@ -2269,6 +2295,8 @@
2269
2295
  "emptyLabel": { "type": "string", "description": "Empty-state message rendered instead of the chart when the resolved series contain no data points." },
2270
2296
  "barMax": { "type": "number", "exclusiveMinimum": 0, "description": "chartKind 'bar-list': the value a full track stands for (100 for percentages). Omitted = the largest value." },
2271
2297
  "footnote": { "type": "string", "description": "A line under the chart, through the host's translate: under the rows of a bar-list or matrix, and under the plot of a line, area or bar chart." },
2298
+ "referenceLines": { "type": "array", "description": "line, area and bar charts: dashed horizontal reference lines on the value axis, such as a norm. Each `{ value, label?, color? }`; the label goes through the host's translate, the colour defaults to the theme's error colour.", "items": { "type": "object", "required": ["value"], "properties": { "value": { "type": "number" }, "label": { "type": "string" }, "color": { "type": "string" } } } },
2299
+ "categoryFormat": { "type": "string", "enum": ["", "month", "month-year"], "description": "How date categories read on the x-axis: `month` (\"jan\") or `month-year` (\"jan 2026\"), in the user's language. Categories that are not dates are left as is." },
2272
2300
  "emptyCellLabel": { "type": "string", "description": "chartKind 'matrix': the text of a cell without a value (\"geen\"), through the host's translate. Empty leaves the cell blank. Passed through to CnChartWidget." },
2273
2301
  "highlight": {
2274
2302
  "type": "object",
@@ -3248,9 +3276,9 @@
3248
3276
  },
3249
3277
  "op": {
3250
3278
  "type": "string",
3251
- "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "empty", "notEmpty", "in", "anyOf"],
3279
+ "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "empty", "notEmpty", "in", "anyOf", "contains"],
3252
3280
  "default": "eq",
3253
- "description": "Comparison operator (default eq). eq/neq compare loosely-normalised primitives; ordering operators coerce both sides to Number. `in` holds when the value is one of the listed `value` array (2.87.0). `anyOf` holds when the value, or any entry of a list value, is one of the listed `value` array: a record whose `dataCategories` holds \"health\" among others matches `anyOf [\"health\", \"ethnicity\"]` (2.126.0). `empty` / `notEmpty` take no `value` and treat undefined, null, '' and an empty array alike — the one question eq cannot ask, because an unset field arrives in a shape that depends on the store and String(null) is the word 'null' rather than blank."
3281
+ "description": "Comparison operator (default eq). eq/neq compare loosely-normalised primitives; ordering operators coerce both sides to Number. `in` holds when the value is one of the listed `value` array (2.87.0). `anyOf` holds when the value, or any entry of a list value, is one of the listed `value` array: a record whose `dataCategories` holds \"health\" among others matches `anyOf [\"health\", \"ethnicity\"]` (2.126.0). `contains` holds when a list value holds the given `value`, e.g. a case type's overviewCards switching a card on (2.128.0). `empty` / `notEmpty` take no `value` and treat undefined, null, '' and an empty array alike — the one question eq cannot ask, because an unset field arrives in a shape that depends on the store and String(null) is the word 'null' rather than blank."
3254
3282
  },
3255
3283
  "value": {
3256
3284
  "description": "The right-hand side of the comparison, resolved through the shared @-token grammar so `@me` names the signed-in reader rather than a literal only the server knows. Omitted for `empty` / `notEmpty`."
@@ -4218,6 +4246,11 @@
4218
4246
  ]
4219
4247
  }
4220
4248
  },
4249
+ "tabsFrom": {
4250
+ "type": "string",
4251
+ "minLength": 1,
4252
+ "description": "type='detail': a field path, read like a `visibleWhen` field, whose value picks the tabs of the page's tabs widgets and their order for this record, e.g. `@context.caseType.tabs` (DqAanbesteding). A non-empty list of tab ids keeps those tabs in that order; otherwise the declared tabs stay, and edit mode shows them all (2.128.0)."
4253
+ },
4221
4254
  "sideColumnFrom": {
4222
4255
  "type": "string",
4223
4256
  "minLength": 1,
@@ -58,6 +58,7 @@ export const BUILT_IN_WIDGET_KEYS = Object.freeze([
58
58
  'object-table',
59
59
  'form-renderer',
60
60
  'map-viewer',
61
+ 'notice',
61
62
  'object-geo',
62
63
  'card-grid',
63
64
  'nav-card-grid',
@@ -0,0 +1,50 @@
1
+ /**
2
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
3
+ * SPDX-License-Identifier: EUPL-1.2
4
+ */
5
+
6
+ import { generateOcsUrl } from '@nextcloud/router'
7
+
8
+ /**
9
+ * The display names of the apps in Nextcloud's navigation, by app id, read
10
+ * once per page load from the OCS navigation endpoint with the reader's
11
+ * session. An app outside the navigation, or a failed read, has no entry.
12
+ *
13
+ * @module utils/nextcloudApps
14
+ */
15
+
16
+ let pending = null
17
+
18
+ /**
19
+ * The app display names by app id.
20
+ *
21
+ * @param {object} axios The axios instance.
22
+ * @return {Promise<Record<string, string>>} The names; empty when the read fails.
23
+ */
24
+ export function appDisplayNames(axios) {
25
+ if (!pending) {
26
+ pending = axios.get(generateOcsUrl('core/navigation/apps'), { params: { format: 'json' }, headers: { 'OCS-APIRequest': 'true' } })
27
+ .then((res) => {
28
+ const entries = (res && res.data && res.data.ocs && res.data.ocs.data) || []
29
+ const names = {}
30
+ for (const entry of Array.isArray(entries) ? entries : Object.values(entries)) {
31
+ const id = entry && (entry.app || entry.id)
32
+ if (id && typeof entry.name === 'string' && entry.name !== '') {
33
+ names[String(id)] = entry.name
34
+ }
35
+ }
36
+ return names
37
+ })
38
+ .catch(() => ({}))
39
+ }
40
+ return pending
41
+ }
42
+
43
+ /**
44
+ * Forget the names read, so the next call reads them again.
45
+ *
46
+ * @return {void}
47
+ */
48
+ export function clearAppDisplayNames() {
49
+ pending = null
50
+ }
@@ -153,8 +153,15 @@ export function resolveScopeLayout({ scope = null, row = null, pageColumns = []
153
153
  return
154
154
  }
155
155
  // The page's own entry is used, not the scope's, so the label and
156
- // formatter a column was declared with survive being selected.
157
- columns.push(byKey.get(key))
156
+ // formatter a column was declared with survive being selected. A
157
+ // column the page hides by default shows: the scope asked for it.
158
+ const own = byKey.get(key)
159
+ if (own && typeof own === 'object' && own.hidden === true) {
160
+ const { hidden, ...shown } = own
161
+ columns.push(shown)
162
+ return
163
+ }
164
+ columns.push(own)
158
165
  })
159
166
 
160
167
  return { columns, sortKeys, searchFields }