@conduction/nextcloud-vue 2.137.0 → 2.138.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 (86) hide show
  1. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
  2. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +6 -4
  3. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  4. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  5. package/dist/esm/components/CnDetailCard/CnDetailCard.vue.js +1 -1
  6. package/dist/esm/components/CnDetailCard/CnDetailCard.vue2.js +6 -0
  7. package/dist/esm/components/CnDetailCard/CnDetailCard.vue2.js.map +1 -1
  8. package/dist/esm/components/CnDetailCard/CnDetailCard.vue3.js +24 -7
  9. package/dist/esm/components/CnDetailCard/CnDetailCard.vue3.js.map +1 -1
  10. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  11. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +2 -0
  12. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  13. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  14. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  15. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +43 -1
  16. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  17. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  18. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +34 -2
  19. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  20. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +23 -15
  21. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  22. package/dist/esm/components/CnMailTab/dashboardRegistration.js +4 -0
  23. package/dist/esm/components/CnMailTab/dashboardRegistration.js.map +1 -1
  24. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue.js +1 -1
  25. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue2.js.map +1 -1
  26. package/dist/esm/components/CnNotificationMatrix/CnNotificationMatrix.vue3.js.map +1 -1
  27. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
  28. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +2 -0
  29. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  30. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +2 -1
  31. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  32. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue.js +1 -1
  33. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js +6 -0
  34. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue2.js.map +1 -1
  35. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js +3 -3
  36. package/dist/esm/components/CnOrderedListField/CnOrderedListField.vue3.js.map +1 -1
  37. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  38. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +16 -0
  39. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  40. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +11 -5
  41. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  42. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue.js +1 -1
  43. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js.map +1 -1
  44. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js +1 -0
  45. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js.map +1 -1
  46. package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +1 -1
  47. package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -1
  48. package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -1
  49. package/dist/esm/composables/indexSources.js +36 -9
  50. package/dist/esm/composables/indexSources.js.map +1 -1
  51. package/dist/esm/l10n/en.json.js +10 -1
  52. package/dist/esm/l10n/en.json.js.map +1 -1
  53. package/dist/esm/l10n/nl.json.js +10 -1
  54. package/dist/esm/l10n/nl.json.js.map +1 -1
  55. package/dist/esm/library-style.js +1 -1
  56. package/dist/esm/nextcloud-vue.css +431 -360
  57. package/dist/esm/utils/resolveFilterTokens.js +9 -0
  58. package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
  59. package/dist/esm/utils/sentinelTokens.js +1 -1
  60. package/dist/esm/utils/sentinelTokens.js.map +1 -1
  61. package/dist/nextcloud-vue.cjs.js +418 -221
  62. package/dist/nextcloud-vue.cjs.js.map +2 -2
  63. package/dist/nextcloud-vue.css +431 -360
  64. package/l10n/en.json +10 -1
  65. package/l10n/nl.json +10 -1
  66. package/package.json +1 -1
  67. package/src/components/CnCellRenderer/CnCellRenderer.vue +6 -4
  68. package/src/components/CnDetailCard/CnDetailCard.md +1 -0
  69. package/src/components/CnDetailCard/CnDetailCard.vue +25 -1
  70. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +2 -0
  71. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +43 -1
  72. package/src/components/CnIndexPage/CnIndexPage.vue +34 -1
  73. package/src/components/CnMailTab/dashboardRegistration.js +4 -0
  74. package/src/components/CnNotificationMatrix/CnNotificationMatrix.vue +4 -0
  75. package/src/components/CnObjectSidebar/CnFilesTab.vue +3 -0
  76. package/src/components/CnOrderedListField/CnOrderedListField.vue +11 -1
  77. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +22 -3
  78. package/src/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue +1 -0
  79. package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +3 -0
  80. package/src/composables/indexSources.js +36 -9
  81. package/src/css/dialog.css +8 -0
  82. package/src/css/index-page.css +5 -0
  83. package/src/css/look-board-detail.css +12 -0
  84. package/src/css/look-board.css +26 -0
  85. package/src/utils/resolveFilterTokens.js +9 -0
  86. package/src/utils/sentinelTokens.js +1 -1
@@ -3601,7 +3601,8 @@ var translations$s = {
3601
3601
  "Talk to {agent}": "Talk to {agent}",
3602
3602
  "Search a person or group": "Search a person or group",
3603
3603
  "Now: by {order}.": "Now: by {order}.",
3604
- "You save the order along with a view.": "You save the order along with a view."
3604
+ "You save the order along with a view.": "You save the order along with a view.",
3605
+ me: "me"
3605
3606
  };
3606
3607
  var plurals$1 = {
3607
3608
  "{count} member": [
@@ -3802,6 +3803,14 @@ var plurals$1 = {
3802
3803
  "within %n day": [
3803
3804
  "within %n day",
3804
3805
  "within %n days"
3806
+ ],
3807
+ "%n other": [
3808
+ "%n other",
3809
+ "%n others"
3810
+ ],
3811
+ "{names} has no location, so it is not on the map.": [
3812
+ "{names} has no location, so it is not on the map.",
3813
+ "{names} have no location, so they are not on the map."
3805
3814
  ]
3806
3815
  };
3807
3816
  var en = {
@@ -6602,7 +6611,8 @@ var translations$c = {
6602
6611
  "Talk to {agent}": "Praten met {agent}",
6603
6612
  "Search a person or group": "Zoek een persoon of groep",
6604
6613
  "Now: by {order}.": "Nu: op {order}.",
6605
- "You save the order along with a view.": "De sortering bewaart u mee in een weergave."
6614
+ "You save the order along with a view.": "De sortering bewaart u mee in een weergave.",
6615
+ me: "ik"
6606
6616
  };
6607
6617
  var plurals = {
6608
6618
  "{count} member": [
@@ -6820,6 +6830,14 @@ var plurals = {
6820
6830
  "within %n day": [
6821
6831
  "binnen %n dag",
6822
6832
  "binnen %n dagen"
6833
+ ],
6834
+ "%n other": [
6835
+ "%n andere",
6836
+ "%n andere"
6837
+ ],
6838
+ "{names} has no location, so it is not on the map.": [
6839
+ "{names} heeft geen locatie, dus staat niet op de kaart.",
6840
+ "{names} hebben geen locatie, dus staan ze niet op de kaart."
6823
6841
  ]
6824
6842
  };
6825
6843
  var nl = {
@@ -7256,9 +7274,9 @@ const _hoisted_4$6l = {
7256
7274
  "data-testid": "cn-ai-history-list-edit"
7257
7275
  };
7258
7276
  const _hoisted_5$5D = { class: "cn-ai-history-list__edit-actions" };
7259
- const _hoisted_6$5b = ["onClick"];
7260
- const _hoisted_7$4J = { class: "cn-ai-history-list__item-title" };
7261
- const _hoisted_8$4h = {
7277
+ const _hoisted_6$5c = ["onClick"];
7278
+ const _hoisted_7$4K = { class: "cn-ai-history-list__item-title" };
7279
+ const _hoisted_8$4i = {
7262
7280
  key: 0,
7263
7281
  class: "cn-ai-history-list__item-desc"
7264
7282
  };
@@ -7360,12 +7378,12 @@ function render$8G(_ctx, _cache, $props, $setup, $data, $options) {
7360
7378
  class: "cn-ai-history-list__item-button",
7361
7379
  onClick: $event => (_ctx.$emit('select', conv.uuid))
7362
7380
  }, [
7363
- vue$1.createElementVNode("span", _hoisted_7$4J, vue$1.toDisplayString(conv.title || $options.cnTranslate('New conversation')), 1 /* TEXT */),
7381
+ vue$1.createElementVNode("span", _hoisted_7$4K, vue$1.toDisplayString(conv.title || $options.cnTranslate('New conversation')), 1 /* TEXT */),
7364
7382
  (conv.description)
7365
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$4h, vue$1.toDisplayString(conv.description), 1 /* TEXT */))
7383
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$4i, vue$1.toDisplayString(conv.description), 1 /* TEXT */))
7366
7384
  : vue$1.createCommentVNode("v-if", true),
7367
7385
  vue$1.createElementVNode("span", _hoisted_9$3Y, vue$1.toDisplayString($options.formatRelative(conv.updatedAt || conv.createdAt)), 1 /* TEXT */)
7368
- ], 8 /* PROPS */, _hoisted_6$5b),
7386
+ ], 8 /* PROPS */, _hoisted_6$5c),
7369
7387
  vue$1.createElementVNode("button", {
7370
7388
  type: "button",
7371
7389
  class: "cn-ai-history-list__item-edit-btn",
@@ -10005,9 +10023,9 @@ const _hoisted_2$7U = {
10005
10023
  const _hoisted_3$73 = { class: "cn-ai-input__chip-name" };
10006
10024
  const _hoisted_4$6k = ["aria-label", "disabled", "data-testid", "onClick"];
10007
10025
  const _hoisted_5$5C = { class: "cn-ai-input__row" };
10008
- const _hoisted_6$5a = ["aria-label", "title", "aria-pressed", "aria-disabled", "disabled", "data-engine"];
10009
- const _hoisted_7$4I = ["aria-label", "title", "aria-pressed", "disabled"];
10010
- const _hoisted_8$4g = ["aria-label", "disabled", "placeholder"];
10026
+ const _hoisted_6$5b = ["aria-label", "title", "aria-pressed", "aria-disabled", "disabled", "data-engine"];
10027
+ const _hoisted_7$4J = ["aria-label", "title", "aria-pressed", "disabled"];
10028
+ const _hoisted_8$4h = ["aria-label", "disabled", "placeholder"];
10011
10029
  const _hoisted_9$3X = ["aria-label", "disabled"];
10012
10030
 
10013
10031
  function render$8F(_ctx, _cache, $props, $setup, $data, $options) {
@@ -10111,7 +10129,7 @@ function render$8F(_ctx, _cache, $props, $setup, $data, $options) {
10111
10129
  key: 2,
10112
10130
  size: 20
10113
10131
  }))
10114
- ], 10 /* CLASS, PROPS */, _hoisted_6$5a))
10132
+ ], 10 /* CLASS, PROPS */, _hoisted_6$5b))
10115
10133
  : vue$1.createCommentVNode("v-if", true),
10116
10134
  ($options.conversationButtonVisible)
10117
10135
  ? (vue$1.openBlock(), vue$1.createElementBlock("button", {
@@ -10134,7 +10152,7 @@ function render$8F(_ctx, _cache, $props, $setup, $data, $options) {
10134
10152
  key: 1,
10135
10153
  size: 20
10136
10154
  }))
10137
- ], 10 /* CLASS, PROPS */, _hoisted_7$4I))
10155
+ ], 10 /* CLASS, PROPS */, _hoisted_7$4J))
10138
10156
  : vue$1.createCommentVNode("v-if", true),
10139
10157
  vue$1.createVNode(_component_NcActions, {
10140
10158
  class: "cn-ai-input__attach-menu",
@@ -10205,7 +10223,7 @@ function render$8F(_ctx, _cache, $props, $setup, $data, $options) {
10205
10223
  _cache[5] || (_cache[5] = vue$1.withKeys(vue$1.withModifiers((...args) => ($options.handleShiftEnter && $options.handleShiftEnter(...args)), ["shift","exact"]), ["enter"]))
10206
10224
  ],
10207
10225
  onInput: _cache[6] || (_cache[6] = (...args) => ($options.autoGrow && $options.autoGrow(...args)))
10208
- }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_8$4g), [
10226
+ }, null, 40 /* PROPS, NEED_HYDRATION */, _hoisted_8$4h), [
10209
10227
  [vue$1.vModelText, $data.inputText]
10210
10228
  ]),
10211
10229
  vue$1.createElementVNode("button", {
@@ -10431,13 +10449,13 @@ const _hoisted_4$6j = {
10431
10449
  class: "cn-ai-message-list__bubble cn-ai-message-list__bubble--user"
10432
10450
  };
10433
10451
  const _hoisted_5$5B = { class: "cn-ai-message-list__user-text" };
10434
- const _hoisted_6$59 = {
10452
+ const _hoisted_6$5a = {
10435
10453
  key: 0,
10436
10454
  class: "cn-ai-message-list__attachments",
10437
10455
  "data-testid": "cn-ai-message-attachments"
10438
10456
  };
10439
- const _hoisted_7$4H = ["href"];
10440
- const _hoisted_8$4f = {
10457
+ const _hoisted_7$4I = ["href"];
10458
+ const _hoisted_8$4g = {
10441
10459
  key: 1,
10442
10460
  class: "cn-ai-message-list__chip"
10443
10461
  };
@@ -10501,7 +10519,7 @@ function render$8E(_ctx, _cache, $props, $setup, $data, $options) {
10501
10519
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_4$6j, [
10502
10520
  vue$1.createElementVNode("span", _hoisted_5$5B, vue$1.toDisplayString(message.content), 1 /* TEXT */),
10503
10521
  ($options.hasAttachments(message))
10504
- ? (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_6$59, [
10522
+ ? (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_6$5a, [
10505
10523
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList(message.attachments, (file, fIdx) => {
10506
10524
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
10507
10525
  key: fIdx,
@@ -10514,8 +10532,8 @@ function render$8E(_ctx, _cache, $props, $setup, $data, $options) {
10514
10532
  href: $options.fileHref(file),
10515
10533
  target: "_blank",
10516
10534
  rel: "noopener noreferrer"
10517
- }, vue$1.toDisplayString(file.name), 9 /* TEXT, PROPS */, _hoisted_7$4H))
10518
- : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$4f, vue$1.toDisplayString(file.name), 1 /* TEXT */))
10535
+ }, vue$1.toDisplayString(file.name), 9 /* TEXT, PROPS */, _hoisted_7$4I))
10536
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$4g, vue$1.toDisplayString(file.name), 1 /* TEXT */))
10519
10537
  ]))
10520
10538
  }), 128 /* KEYED_FRAGMENT */))
10521
10539
  ]))
@@ -11707,12 +11725,12 @@ const _hoisted_2$7S = {
11707
11725
  const _hoisted_3$71 = ["title"];
11708
11726
  const _hoisted_4$6i = { class: "cn-ai-chat-window__identity-name" };
11709
11727
  const _hoisted_5$5A = { class: "cn-ai-chat-window__controls" };
11710
- const _hoisted_6$58 = {
11728
+ const _hoisted_6$59 = {
11711
11729
  key: 1,
11712
11730
  class: "cn-ai-chat-window__body"
11713
11731
  };
11714
- const _hoisted_7$4G = { class: "cn-ai-chat-window__messages" };
11715
- const _hoisted_8$4e = {
11732
+ const _hoisted_7$4H = { class: "cn-ai-chat-window__messages" };
11733
+ const _hoisted_8$4f = {
11716
11734
  class: "cn-ai-chat-window__start",
11717
11735
  "data-testid": "cn-ai-chat-tab-start"
11718
11736
  };
@@ -11952,15 +11970,15 @@ function render$8D(_ctx, _cache, $props, $setup, $data, $options) {
11952
11970
  ]))
11953
11971
  : vue$1.createCommentVNode("v-if", true),
11954
11972
  ($data.activeView === 'chat')
11955
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$58, [
11956
- vue$1.createElementVNode("div", _hoisted_7$4G, [
11973
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$59, [
11974
+ vue$1.createElementVNode("div", _hoisted_7$4H, [
11957
11975
  vue$1.createVNode(_component_CnAiMessageList, {
11958
11976
  messages: $props.streamState.messages,
11959
11977
  currentText: $props.streamState.currentText,
11960
11978
  isStreaming: $props.streamState.isStreaming
11961
11979
  }, {
11962
11980
  empty: vue$1.withCtx(() => [
11963
- vue$1.createElementVNode("div", _hoisted_8$4e, [
11981
+ vue$1.createElementVNode("div", _hoisted_8$4f, [
11964
11982
  vue$1.createVNode(_component_NcEmptyContent, { name: $options.agentLabel }, {
11965
11983
  icon: vue$1.withCtx(() => [
11966
11984
  vue$1.createVNode(_component_Creation, { size: 40 })
@@ -14750,6 +14768,34 @@ function fillMyTeamToken(text, name) {
14750
14768
  .replaceAll('{myTeam}', name)
14751
14769
  }
14752
14770
 
14771
+ /**
14772
+ * SPDX-FileCopyrightText: 2026 Conduction B.V.
14773
+ * SPDX-License-Identifier: EUPL-1.2
14774
+ *
14775
+ * readPath: read a dot-path off an object.
14776
+ *
14777
+ * Its own module, with no imports, so the rules that read a record's fields
14778
+ * (stage, checklist, due date) do not hang on a module a host or a test may
14779
+ * replace.
14780
+ *
14781
+ * @module utils/readPath
14782
+ */
14783
+
14784
+ /**
14785
+ * Read a dot-path (`'a.b.c'`) off an object.
14786
+ *
14787
+ * @param {object|null} data The source object.
14788
+ * @param {string} [path] Dot-path into the object. Empty returns the object itself.
14789
+ * @return {unknown} The value at the path, or undefined when a segment is missing.
14790
+ * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
14791
+ */
14792
+ function readPath$8(data, path) {
14793
+ if (!path) {
14794
+ return data
14795
+ }
14796
+ return String(path).split('.').reduce((value, key) => (value === null || value === undefined ? value : value[key]), data)
14797
+ }
14798
+
14753
14799
  /**
14754
14800
  * SPDX-FileCopyrightText: 2026 Conduction B.V.
14755
14801
  * SPDX-License-Identifier: EUPL-1.2
@@ -14940,7 +14986,7 @@ const SENTINEL_VOCABULARY = Object.freeze({
14940
14986
  members: ['@subject.<field>'],
14941
14987
  },
14942
14988
  context: {
14943
- resolver: 'CnDetailPage visibilityContext (detailWidgetVisibility), read by a grid widget\'s or a tab\'s visibleWhen',
14989
+ resolver: 'CnDetailPage visibilityContext (detailWidgetVisibility), read by a grid widget\'s or a tab\'s visibleWhen, and by a widget\'s props (CnDetailWidgetHost)',
14944
14990
  description: 'A record the detail page reads beside the loaded one, named in `config.visibilityContext` (a case\'s case type). A `visibleWhen` field reads it as `@context.<name>.<field>`, dot paths allowed (`@context.caseType.category`).',
14945
14991
  members: ['@context.<name>.<field>'],
14946
14992
  },
@@ -15268,6 +15314,9 @@ function resetGroupsPeek() {
15268
15314
  * - `@object.<field>` → a field off the current detail-page object (needs `ctx`)
15269
15315
  * - `@workspace.<key>` → a value off the page-level workspace context (needs `ctx.workspace`)
15270
15316
  * - `@config.<key>` → a value off the page-level app config (needs `ctx.config`)
15317
+ * - `@context.<name>.<path>` → a value off a record the detail page reads beside
15318
+ * the loaded one (needs `ctx.context`); left as written
15319
+ * while that record is not read
15271
15320
  *
15272
15321
  * `@objectId` / `@object.<field>` are OBJECT-CONTEXT tokens: they resolve only
15273
15322
  * when a `ctx` `{ objectId, object }` is supplied (a detail page provides it via
@@ -15414,6 +15463,11 @@ function resolveFilterValue(v, ctx) {
15414
15463
  }
15415
15464
  return v
15416
15465
  }
15466
+ if (v.startsWith('@context.')) {
15467
+ // @spec openspec/changes/files-second-line-fields/specs/files-second-line-fields/spec.md#requirement-widget-props-can-read-the-detail-pages-context-records
15468
+ const found = ctx && ctx.context ? readPath$8(ctx.context, v.slice('@context.'.length)) : undefined;
15469
+ return found === undefined ? v : found
15470
+ }
15417
15471
  if (v.startsWith('@workspace.')) {
15418
15472
  // A trailing `?` marks the token OPTIONAL: when unset the caller drops the
15419
15473
  // filter key (show all) instead of waiting (see hasUnresolvedTokens /
@@ -21892,34 +21946,6 @@ function normalizeAllowed(answer) {
21892
21946
  return { keys, reasons }
21893
21947
  }
21894
21948
 
21895
- /**
21896
- * SPDX-FileCopyrightText: 2026 Conduction B.V.
21897
- * SPDX-License-Identifier: EUPL-1.2
21898
- *
21899
- * readPath: read a dot-path off an object.
21900
- *
21901
- * Its own module, with no imports, so the rules that read a record's fields
21902
- * (stage, checklist, due date) do not hang on a module a host or a test may
21903
- * replace.
21904
- *
21905
- * @module utils/readPath
21906
- */
21907
-
21908
- /**
21909
- * Read a dot-path (`'a.b.c'`) off an object.
21910
- *
21911
- * @param {object|null} data The source object.
21912
- * @param {string} [path] Dot-path into the object. Empty returns the object itself.
21913
- * @return {unknown} The value at the path, or undefined when a segment is missing.
21914
- * @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-primary-action-follows-the-stage
21915
- */
21916
- function readPath$8(data, path) {
21917
- if (!path) {
21918
- return data
21919
- }
21920
- return String(path).split('.').reduce((value, key) => (value === null || value === undefined ? value : value[key]), data)
21921
- }
21922
-
21923
21949
  /**
21924
21950
  * SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>
21925
21951
  * SPDX-License-Identifier: EUPL-1.2
@@ -26651,12 +26677,12 @@ const _hoisted_4$6h = {
26651
26677
  "data-testid": "cn-chart-widget-bar-list"
26652
26678
  };
26653
26679
  const _hoisted_5$5z = { class: "cn-chart-widget__bar-list" };
26654
- const _hoisted_6$57 = { class: "cn-chart-widget__bar-label" };
26655
- const _hoisted_7$4F = {
26680
+ const _hoisted_6$58 = { class: "cn-chart-widget__bar-label" };
26681
+ const _hoisted_7$4G = {
26656
26682
  class: "cn-chart-widget__bar-track",
26657
26683
  "aria-hidden": "true"
26658
26684
  };
26659
- const _hoisted_8$4d = { class: "cn-chart-widget__bar-value" };
26685
+ const _hoisted_8$4e = { class: "cn-chart-widget__bar-value" };
26660
26686
  const _hoisted_9$3U = {
26661
26687
  key: 0,
26662
26688
  class: "cn-chart-widget__footnote"
@@ -26759,14 +26785,14 @@ function render$8y(_ctx, _cache, $props, $setup, $data, $options) {
26759
26785
  onClick: $event => (row.drill ? $options.onDataPointSelection(null, null, { dataPointIndex: row.index }) : null)
26760
26786
  }, {
26761
26787
  default: vue$1.withCtx(() => [
26762
- vue$1.createElementVNode("span", _hoisted_6$57, vue$1.toDisplayString(row.label), 1 /* TEXT */),
26763
- vue$1.createElementVNode("span", _hoisted_7$4F, [
26788
+ vue$1.createElementVNode("span", _hoisted_6$58, vue$1.toDisplayString(row.label), 1 /* TEXT */),
26789
+ vue$1.createElementVNode("span", _hoisted_7$4G, [
26764
26790
  vue$1.createElementVNode("span", {
26765
26791
  class: "cn-chart-widget__bar-fill",
26766
26792
  style: vue$1.normalizeStyle({ width: `${row.share}%` })
26767
26793
  }, null, 4 /* STYLE */)
26768
26794
  ]),
26769
- vue$1.createElementVNode("span", _hoisted_8$4d, vue$1.toDisplayString(row.text), 1 /* TEXT */)
26795
+ vue$1.createElementVNode("span", _hoisted_8$4e, vue$1.toDisplayString(row.text), 1 /* TEXT */)
26770
26796
  ]),
26771
26797
  _: 2 /* DYNAMIC */
26772
26798
  }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["type", "class", "onClick"]))
@@ -27771,15 +27797,15 @@ const _hoisted_2$7N = { class: "cn-chart-widget-form__section" };
27771
27797
  const _hoisted_3$6_ = { class: "cn-chart-widget-form__row2" };
27772
27798
  const _hoisted_4$6g = { class: "cn-chart-widget-form__section" };
27773
27799
  const _hoisted_5$5y = { class: "cn-chart-widget-form__row2" };
27774
- const _hoisted_6$56 = {
27800
+ const _hoisted_6$57 = {
27775
27801
  key: 0,
27776
27802
  class: "cn-chart-widget-form__row2"
27777
27803
  };
27778
- const _hoisted_7$4E = {
27804
+ const _hoisted_7$4F = {
27779
27805
  key: 1,
27780
27806
  class: "cn-chart-widget-form__row2"
27781
27807
  };
27782
- const _hoisted_8$4c = { class: "cn-chart-widget-form__row2" };
27808
+ const _hoisted_8$4d = { class: "cn-chart-widget-form__row2" };
27783
27809
  const _hoisted_9$3T = {
27784
27810
  key: 2,
27785
27811
  class: "cn-chart-widget-form__hint"
@@ -27828,7 +27854,7 @@ function render$8u(_ctx, _cache, $props, $setup, $data, $options) {
27828
27854
  }, null, 8 /* PROPS */, ["register", "schema"])
27829
27855
  ]),
27830
27856
  ($data.mode === 'timeseries')
27831
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$56, [
27857
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$57, [
27832
27858
  vue$1.createVNode(_component_CnFieldPicker, {
27833
27859
  value: $data.bucket.field,
27834
27860
  label: $options.t('nextcloud-vue', 'Date field'),
@@ -27844,7 +27870,7 @@ function render$8u(_ctx, _cache, $props, $setup, $data, $options) {
27844
27870
  "onUpdate:modelValue": _cache[5] || (_cache[5] = $event => ($options.updateBucket('interval', $event)))
27845
27871
  }, null, 8 /* PROPS */, ["modelValue", "options", "inputLabel"])
27846
27872
  ]))
27847
- : (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_7$4E, [
27873
+ : (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_7$4F, [
27848
27874
  vue$1.createVNode(_component_CnFieldPicker, {
27849
27875
  value: $data.group.field,
27850
27876
  label: $options.t('nextcloud-vue', 'Group by field'),
@@ -27866,7 +27892,7 @@ function render$8u(_ctx, _cache, $props, $setup, $data, $options) {
27866
27892
  "onUpdate:modelValue": _cache[8] || (_cache[8] = $event => ($options.updateGroup('limit', Number($event) || 0)))
27867
27893
  }, null, 8 /* PROPS */, ["modelValue", "label"])
27868
27894
  ])),
27869
- vue$1.createElementVNode("div", _hoisted_8$4c, [
27895
+ vue$1.createElementVNode("div", _hoisted_8$4d, [
27870
27896
  vue$1.createVNode(_component_NcSelect, {
27871
27897
  modelValue: $data.metric,
27872
27898
  options: $options.metricOptions,
@@ -29259,9 +29285,9 @@ const _hoisted_5$5x = {
29259
29285
  key: 0,
29260
29286
  class: "cn-quick-filter-bar__label"
29261
29287
  };
29262
- const _hoisted_6$55 = ["role", "aria-label"];
29263
- const _hoisted_7$4D = ["role", "aria-selected", "aria-pressed", "onClick"];
29264
- const _hoisted_8$4b = { class: "cn-quick-filter-bar__label" };
29288
+ const _hoisted_6$56 = ["role", "aria-label"];
29289
+ const _hoisted_7$4E = ["role", "aria-selected", "aria-pressed", "onClick"];
29290
+ const _hoisted_8$4c = { class: "cn-quick-filter-bar__label" };
29265
29291
  const _hoisted_9$3S = {
29266
29292
  key: 1,
29267
29293
  class: "cn-quick-filter-bar__count",
@@ -29360,13 +29386,13 @@ function render$8r(_ctx, _cache, $props, $setup, $data, $options) {
29360
29386
  class: "cn-quick-filter-bar__icon"
29361
29387
  }, null, 8 /* PROPS */, ["name"]))
29362
29388
  : vue$1.createCommentVNode("v-if", true),
29363
- vue$1.createElementVNode("span", _hoisted_8$4b, vue$1.toDisplayString($options.tl(entry.tab.label)), 1 /* TEXT */),
29389
+ vue$1.createElementVNode("span", _hoisted_8$4c, vue$1.toDisplayString($options.tl(entry.tab.label)), 1 /* TEXT */),
29364
29390
  ($options.countOf(entry) !== null)
29365
29391
  ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_9$3S, vue$1.toDisplayString(' ' + $options.countOf(entry)), 1 /* TEXT */))
29366
29392
  : vue$1.createCommentVNode("v-if", true)
29367
- ], 10 /* CLASS, PROPS */, _hoisted_7$4D))
29393
+ ], 10 /* CLASS, PROPS */, _hoisted_7$4E))
29368
29394
  }), 128 /* KEYED_FRAGMENT */))
29369
- ], 8 /* PROPS */, _hoisted_6$55),
29395
+ ], 8 /* PROPS */, _hoisted_6$56),
29370
29396
  ($options.overflowEntries.length > 0)
29371
29397
  ? (vue$1.openBlock(), vue$1.createBlock(_component_NcPopover, {
29372
29398
  key: 1,
@@ -29890,18 +29916,18 @@ const _hoisted_5$5w = {
29890
29916
  key: 1,
29891
29917
  class: "cn-conversation-thread__header-actions"
29892
29918
  };
29893
- const _hoisted_6$54 = {
29919
+ const _hoisted_6$55 = {
29894
29920
  key: 2,
29895
29921
  class: "cn-conversation-thread__empty",
29896
29922
  role: "status",
29897
29923
  "data-testid": "cn-conversation-loading"
29898
29924
  };
29899
- const _hoisted_7$4C = {
29925
+ const _hoisted_7$4D = {
29900
29926
  key: 3,
29901
29927
  class: "cn-conversation-thread__empty",
29902
29928
  "data-testid": "cn-conversation-empty"
29903
29929
  };
29904
- const _hoisted_8$4a = {
29930
+ const _hoisted_8$4b = {
29905
29931
  key: 4,
29906
29932
  class: "cn-conversation-thread__empty",
29907
29933
  "data-testid": "cn-conversation-channel-empty"
@@ -30011,11 +30037,11 @@ function render$8q(_ctx, _cache, $props, $setup, $data, $options) {
30011
30037
  }, null, 8 /* PROPS */, ["tabs", "activeIndex", "onUpdate:activeIndex"]))
30012
30038
  : vue$1.createCommentVNode("v-if", true),
30013
30039
  ($props.loading && $options.rows.length === 0)
30014
- ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_6$54, vue$1.toDisplayString($options.loadingText), 1 /* TEXT */))
30040
+ ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_6$55, vue$1.toDisplayString($options.loadingText), 1 /* TEXT */))
30015
30041
  : ($options.rows.length === 0)
30016
- ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_7$4C, vue$1.toDisplayString($props.emptyText), 1 /* TEXT */))
30042
+ ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_7$4D, vue$1.toDisplayString($props.emptyText), 1 /* TEXT */))
30017
30043
  : ($options.shownRows.length === 0)
30018
- ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_8$4a, vue$1.toDisplayString($props.emptyText), 1 /* TEXT */))
30044
+ ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_8$4b, vue$1.toDisplayString($props.emptyText), 1 /* TEXT */))
30019
30045
  : (vue$1.openBlock(), vue$1.createElementBlock("ol", _hoisted_9$3R, [
30020
30046
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.shownRows, (row) => {
30021
30047
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
@@ -32306,9 +32332,9 @@ const _hoisted_5$5u = {
32306
32332
  key: 2,
32307
32333
  class: "cn-document-review-list__rows"
32308
32334
  };
32309
- const _hoisted_6$53 = { class: "cn-document-review-list__text" };
32310
- const _hoisted_7$4B = ["href"];
32311
- const _hoisted_8$49 = {
32335
+ const _hoisted_6$54 = { class: "cn-document-review-list__text" };
32336
+ const _hoisted_7$4C = ["href"];
32337
+ const _hoisted_8$4a = {
32312
32338
  key: 1,
32313
32339
  class: "cn-document-review-list__name"
32314
32340
  };
@@ -32361,14 +32387,14 @@ function render$8k(_ctx, _cache, $props, $setup, $data, $options) {
32361
32387
  size: 22,
32362
32388
  "aria-hidden": "true"
32363
32389
  }),
32364
- vue$1.createElementVNode("span", _hoisted_6$53, [
32390
+ vue$1.createElementVNode("span", _hoisted_6$54, [
32365
32391
  (row.href)
32366
32392
  ? (vue$1.openBlock(), vue$1.createElementBlock("a", {
32367
32393
  key: 0,
32368
32394
  class: "cn-document-review-list__name",
32369
32395
  href: row.href
32370
- }, vue$1.toDisplayString(row.name), 9 /* TEXT, PROPS */, _hoisted_7$4B))
32371
- : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$49, vue$1.toDisplayString(row.name), 1 /* TEXT */)),
32396
+ }, vue$1.toDisplayString(row.name), 9 /* TEXT, PROPS */, _hoisted_7$4C))
32397
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$4a, vue$1.toDisplayString(row.name), 1 /* TEXT */)),
32372
32398
  (row.meta)
32373
32399
  ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_9$3Q, vue$1.toDisplayString(row.meta), 1 /* TEXT */))
32374
32400
  : vue$1.createCommentVNode("v-if", true)
@@ -37010,9 +37036,9 @@ const _hoisted_5$5t = {
37010
37036
  key: 2,
37011
37037
  class: "cn-calendar-event-picker__calendar-list"
37012
37038
  };
37013
- const _hoisted_6$52 = ["onClick", "onKeyup"];
37014
- const _hoisted_7$4A = { class: "cn-calendar-event-picker__calendar-name" };
37015
- const _hoisted_8$48 = {
37039
+ const _hoisted_6$53 = ["onClick", "onKeyup"];
37040
+ const _hoisted_7$4B = { class: "cn-calendar-event-picker__calendar-name" };
37041
+ const _hoisted_8$49 = {
37016
37042
  key: 3,
37017
37043
  class: "cn-calendar-event-picker__empty"
37018
37044
  };
@@ -37107,11 +37133,11 @@ function render$8h(_ctx, _cache, $props, $setup, $data, $options) {
37107
37133
  class: "cn-calendar-event-picker__color-swatch",
37108
37134
  style: vue$1.normalizeStyle({ backgroundColor: cal.color || 'var(--color-primary-element)' })
37109
37135
  }, null, 4 /* STYLE */),
37110
- vue$1.createElementVNode("span", _hoisted_7$4A, vue$1.toDisplayString(cal.displayName), 1 /* TEXT */)
37111
- ], 40 /* PROPS, NEED_HYDRATION */, _hoisted_6$52))
37136
+ vue$1.createElementVNode("span", _hoisted_7$4B, vue$1.toDisplayString(cal.displayName), 1 /* TEXT */)
37137
+ ], 40 /* PROPS, NEED_HYDRATION */, _hoisted_6$53))
37112
37138
  }), 128 /* KEYED_FRAGMENT */))
37113
37139
  ]))
37114
- : (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$48, vue$1.toDisplayString($props.noCalendarsLabel), 1 /* TEXT */))
37140
+ : (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$49, vue$1.toDisplayString($props.noCalendarsLabel), 1 /* TEXT */))
37115
37141
  ]))
37116
37142
  : ($data.step === 'events')
37117
37143
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_9$3P, [
@@ -37550,16 +37576,16 @@ const _hoisted_3$6Q = {
37550
37576
  };
37551
37577
  const _hoisted_4$69 = { class: "cn-events-card__summary" };
37552
37578
  const _hoisted_5$5s = { class: "cn-events-card__when" };
37553
- const _hoisted_6$51 = {
37579
+ const _hoisted_6$52 = {
37554
37580
  key: 0,
37555
37581
  class: "cn-events-card__where"
37556
37582
  };
37557
- const _hoisted_7$4z = {
37583
+ const _hoisted_7$4A = {
37558
37584
  key: 3,
37559
37585
  class: "cn-events-card__muted",
37560
37586
  "data-testid": "cn-events-card-empty"
37561
37587
  };
37562
- const _hoisted_8$47 = {
37588
+ const _hoisted_8$48 = {
37563
37589
  key: 4,
37564
37590
  class: "cn-events-card__muted",
37565
37591
  role: "alert",
@@ -37590,14 +37616,14 @@ function render$8g(_ctx, _cache, $props, $setup, $data, $options) {
37590
37616
  vue$1.createElementVNode("span", _hoisted_4$69, vue$1.toDisplayString($options.summaryOf(event)), 1 /* TEXT */),
37591
37617
  vue$1.createElementVNode("span", _hoisted_5$5s, vue$1.toDisplayString($options.whenOf(event)), 1 /* TEXT */),
37592
37618
  (event.location)
37593
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_6$51, vue$1.toDisplayString(event.location), 1 /* TEXT */))
37619
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_6$52, vue$1.toDisplayString(event.location), 1 /* TEXT */))
37594
37620
  : vue$1.createCommentVNode("v-if", true)
37595
37621
  ]))
37596
37622
  }), 128 /* KEYED_FRAGMENT */))
37597
37623
  ]))
37598
- : (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_7$4z, vue$1.toDisplayString($options.emptyText), 1 /* TEXT */)),
37624
+ : (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_7$4A, vue$1.toDisplayString($options.emptyText), 1 /* TEXT */)),
37599
37625
  ($data.linkError)
37600
- ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_8$47, vue$1.toDisplayString($data.linkError), 1 /* TEXT */))
37626
+ ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_8$48, vue$1.toDisplayString($data.linkError), 1 /* TEXT */))
37601
37627
  : vue$1.createCommentVNode("v-if", true),
37602
37628
  ($data.showPicker)
37603
37629
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnCalendarEventPicker, {
@@ -37916,9 +37942,9 @@ const _hoisted_5$5r = {
37916
37942
  key: 3,
37917
37943
  class: "cn-macros-widget__list"
37918
37944
  };
37919
- const _hoisted_6$50 = ["data-testid"];
37920
- const _hoisted_7$4y = { class: "cn-macros-widget__text" };
37921
- const _hoisted_8$46 = { class: "cn-macros-widget__name" };
37945
+ const _hoisted_6$51 = ["data-testid"];
37946
+ const _hoisted_7$4z = { class: "cn-macros-widget__text" };
37947
+ const _hoisted_8$47 = { class: "cn-macros-widget__name" };
37922
37948
  const _hoisted_9$3O = {
37923
37949
  key: 0,
37924
37950
  class: "cn-macros-widget__hint"
@@ -37943,8 +37969,8 @@ function render$8f(_ctx, _cache, $props, $setup, $data, $options) {
37943
37969
  class: "cn-macros-widget__row",
37944
37970
  "data-testid": `cn-macros-widget-row-${macro.key}`
37945
37971
  }, [
37946
- vue$1.createElementVNode("div", _hoisted_7$4y, [
37947
- vue$1.createElementVNode("span", _hoisted_8$46, vue$1.toDisplayString($options.tr(macro.name)), 1 /* TEXT */),
37972
+ vue$1.createElementVNode("div", _hoisted_7$4z, [
37973
+ vue$1.createElementVNode("span", _hoisted_8$47, vue$1.toDisplayString($options.tr(macro.name)), 1 /* TEXT */),
37948
37974
  (macro.description)
37949
37975
  ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_9$3O, vue$1.toDisplayString($options.tr(macro.description)), 1 /* TEXT */))
37950
37976
  : vue$1.createCommentVNode("v-if", true)
@@ -37959,7 +37985,7 @@ function render$8f(_ctx, _cache, $props, $setup, $data, $options) {
37959
37985
  ]),
37960
37986
  _: 2 /* DYNAMIC */
37961
37987
  }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["disabled", "data-testid", "onClick"])
37962
- ], 8 /* PROPS */, _hoisted_6$50))
37988
+ ], 8 /* PROPS */, _hoisted_6$51))
37963
37989
  }), 128 /* KEYED_FRAGMENT */))
37964
37990
  ])),
37965
37991
  ($data.error)
@@ -39929,7 +39955,7 @@ const _hoisted_5$5q = {
39929
39955
  class: "cn-map-widget__note",
39930
39956
  "data-testid": "cn-map-unplotted"
39931
39957
  };
39932
- const _hoisted_6$4$ = {
39958
+ const _hoisted_6$50 = {
39933
39959
  key: 4,
39934
39960
  class: "cn-map-widget__legend"
39935
39961
  };
@@ -39965,7 +39991,7 @@ function render$8e(_ctx, _cache, $props, $setup, $data, $options) {
39965
39991
  ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_5$5q, vue$1.toDisplayString($options.unplottedLabel), 1 /* TEXT */))
39966
39992
  : vue$1.createCommentVNode("v-if", true),
39967
39993
  (_ctx.$slots.legend || _ctx.$slots.legend)
39968
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$4$, [
39994
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$50, [
39969
39995
  vue$1.renderSlot(_ctx.$slots, "legend", {
39970
39996
  layers: $options.cfg.layers,
39971
39997
  markers: $options.cfg.markers
@@ -40182,7 +40208,7 @@ const _hoisted_2$7A = {
40182
40208
  const _hoisted_3$6N = { class: "cn-map-widget-form__field" };
40183
40209
  const _hoisted_4$66 = { class: "cn-map-widget-form__label" };
40184
40210
  const _hoisted_5$5p = ["value"];
40185
- const _hoisted_6$4_ = { class: "cn-map-widget-form__row" };
40211
+ const _hoisted_6$4$ = { class: "cn-map-widget-form__row" };
40186
40212
 
40187
40213
  function render$8d(_ctx, _cache, $props, $setup, $data, $options) {
40188
40214
  const _component_CnRegisterSchemaSelect = vue$1.resolveComponent("CnRegisterSchemaSelect");
@@ -40229,7 +40255,7 @@ function render$8d(_ctx, _cache, $props, $setup, $data, $options) {
40229
40255
  placeholder: "400px",
40230
40256
  "onUpdate:modelValue": _cache[4] || (_cache[4] = $event => ($data.height = $event))
40231
40257
  }, null, 8 /* PROPS */, ["modelValue", "label"]),
40232
- vue$1.createElementVNode("div", _hoisted_6$4_, [
40258
+ vue$1.createElementVNode("div", _hoisted_6$4$, [
40233
40259
  vue$1.createVNode(_component_NcTextField, {
40234
40260
  modelValue: String($data.center[0]),
40235
40261
  type: "number",
@@ -40680,12 +40706,12 @@ const _hoisted_4$65 = {
40680
40706
  "aria-hidden": "true"
40681
40707
  };
40682
40708
  const _hoisted_5$5o = { class: "cn-next-step-card__label" };
40683
- const _hoisted_6$4Z = {
40709
+ const _hoisted_6$4_ = {
40684
40710
  key: 0,
40685
40711
  class: "cn-next-step-card__hint"
40686
40712
  };
40687
- const _hoisted_7$4x = { class: "cn-next-step-card__state" };
40688
- const _hoisted_8$45 = {
40713
+ const _hoisted_7$4y = { class: "cn-next-step-card__state" };
40714
+ const _hoisted_8$46 = {
40689
40715
  key: 0,
40690
40716
  class: "cn-next-step-card__side"
40691
40717
  };
@@ -40739,15 +40765,15 @@ function render$8a(_ctx, _cache, $props, $setup, $data, $options) {
40739
40765
  ]),
40740
40766
  vue$1.createElementVNode("span", _hoisted_5$5o, vue$1.toDisplayString(item.label), 1 /* TEXT */),
40741
40767
  (item.hint)
40742
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_6$4Z, vue$1.toDisplayString(item.hint), 1 /* TEXT */))
40768
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_6$4_, vue$1.toDisplayString(item.hint), 1 /* TEXT */))
40743
40769
  : vue$1.createCommentVNode("v-if", true),
40744
- vue$1.createElementVNode("span", _hoisted_7$4x, vue$1.toDisplayString(item.done ? $props.doneLabel : $props.todoLabel), 1 /* TEXT */)
40770
+ vue$1.createElementVNode("span", _hoisted_7$4y, vue$1.toDisplayString(item.done ? $props.doneLabel : $props.todoLabel), 1 /* TEXT */)
40745
40771
  ], 2 /* CLASS */))
40746
40772
  }), 128 /* KEYED_FRAGMENT */))
40747
40773
  ])
40748
40774
  ]),
40749
40775
  ($props.actionLabel || _ctx.$slots.action || $props.after)
40750
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$45, [
40776
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$46, [
40751
40777
  vue$1.renderSlot(_ctx.$slots, "action", {}, () => [
40752
40778
  ($props.actionLabel)
40753
40779
  ? (vue$1.openBlock(), vue$1.createBlock(_component_NcButton, {
@@ -42040,12 +42066,12 @@ const _hoisted_5$5n = {
42040
42066
  "aria-disabled": "true",
42041
42067
  "data-testid": "cn-pagination-next"
42042
42068
  };
42043
- const _hoisted_6$4Y = {
42069
+ const _hoisted_6$4Z = {
42044
42070
  key: 1,
42045
42071
  class: "cn-pagination__info"
42046
42072
  };
42047
- const _hoisted_7$4w = { class: "cn-pagination__page-info" };
42048
- const _hoisted_8$44 = {
42073
+ const _hoisted_7$4x = { class: "cn-pagination__page-info" };
42074
+ const _hoisted_8$45 = {
42049
42075
  key: 2,
42050
42076
  class: "cn-pagination__nav cn-pagination__nav--compact"
42051
42077
  };
@@ -42118,12 +42144,12 @@ function render$88(_ctx, _cache, $props, $setup, $data, $options) {
42118
42144
  ], 64 /* STABLE_FRAGMENT */))
42119
42145
  : vue$1.createCommentVNode("v-if", true),
42120
42146
  (!$options.isBoardVariant)
42121
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$4Y, [
42122
- vue$1.createElementVNode("span", _hoisted_7$4w, vue$1.toDisplayString($options.pageInfoText), 1 /* TEXT */)
42147
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$4Z, [
42148
+ vue$1.createElementVNode("span", _hoisted_7$4x, vue$1.toDisplayString($options.pageInfoText), 1 /* TEXT */)
42123
42149
  ]))
42124
42150
  : vue$1.createCommentVNode("v-if", true),
42125
42151
  (!$options.isBoardVariant && $props.compact && $props.totalPages > 1)
42126
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$44, [
42152
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$45, [
42127
42153
  vue$1.createVNode(_component_NcButton, {
42128
42154
  "aria-label": $props.previousLabel,
42129
42155
  disabled: $props.currentPage === 1,
@@ -42539,13 +42565,13 @@ const _hoisted_5$5m = {
42539
42565
  class: "cn-column-filter__hint",
42540
42566
  role: "status"
42541
42567
  };
42542
- const _hoisted_6$4X = {
42568
+ const _hoisted_6$4Y = {
42543
42569
  key: 2,
42544
42570
  class: "cn-column-filter__hint",
42545
42571
  role: "status"
42546
42572
  };
42547
- const _hoisted_7$4v = { class: "cn-column-filter__options" };
42548
- const _hoisted_8$43 = { class: "cn-column-filter__sr-only" };
42573
+ const _hoisted_7$4w = { class: "cn-column-filter__options" };
42574
+ const _hoisted_8$44 = { class: "cn-column-filter__sr-only" };
42549
42575
  const _hoisted_9$3L = ["value", "checked", "onChange"];
42550
42576
  const _hoisted_10$3l = {
42551
42577
  key: 0,
@@ -42614,10 +42640,10 @@ function render$87(_ctx, _cache, $props, $setup, $data, $options) {
42614
42640
  ($props.def.kind === 'reference' && $data.referenceLoading)
42615
42641
  ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_5$5m, vue$1.toDisplayString($options.loadingLabel), 1 /* TEXT */))
42616
42642
  : ($props.def.kind === 'reference' && $data.referenceError)
42617
- ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_6$4X, vue$1.toDisplayString($data.referenceError), 1 /* TEXT */))
42643
+ ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_6$4Y, vue$1.toDisplayString($data.referenceError), 1 /* TEXT */))
42618
42644
  : vue$1.createCommentVNode("v-if", true),
42619
- vue$1.createElementVNode("fieldset", _hoisted_7$4v, [
42620
- vue$1.createElementVNode("legend", _hoisted_8$43, vue$1.toDisplayString($options.headingText), 1 /* TEXT */),
42645
+ vue$1.createElementVNode("fieldset", _hoisted_7$4w, [
42646
+ vue$1.createElementVNode("legend", _hoisted_8$44, vue$1.toDisplayString($options.headingText), 1 /* TEXT */),
42621
42647
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.listOptions, (option) => {
42622
42648
  return (vue$1.openBlock(), vue$1.createElementBlock("label", {
42623
42649
  key: option.value,
@@ -44569,7 +44595,7 @@ var script$85 = {
44569
44595
  * type-aware rendering, so a manifest column can opt into currency or a
44570
44596
  * colour swatch without registering a function.
44571
44597
  *
44572
- * @type {{style?: 'currency'|'number'|'percent'|'duration'|'swatch', currency?: string, decimals?: number, unit?: 'milliseconds'|'seconds'|'minutes'|'hours', prefix?: string, suffix?: string, colorField?: string}}
44598
+ * @type {{style?: 'currency'|'number'|'decimal'|'percent'|'duration'|'swatch', currency?: string, decimals?: number, unit?: 'milliseconds'|'seconds'|'minutes'|'hours', prefix?: string, suffix?: string, colorField?: string}}
44573
44599
  */
44574
44600
  format: {
44575
44601
  type: Object,
@@ -45639,9 +45665,9 @@ var script$85 = {
45639
45665
  return typeof s === 'string' ? s : null
45640
45666
  },
45641
45667
 
45642
- /** True when a built-in NUMERIC format (currency/number/percent/duration) applies. */
45668
+ /** True when a built-in NUMERIC format (currency/number/decimal/percent/duration) applies. */
45643
45669
  hasBuiltinFormat() {
45644
- return ['currency', 'number', 'percent', 'duration'].includes(this.formatStyle)
45670
+ return ['currency', 'number', 'decimal', 'percent', 'duration'].includes(this.formatStyle)
45645
45671
  },
45646
45672
 
45647
45673
  /** True when this cell renders as a colour swatch (`format.style:"swatch"`). */
@@ -45846,9 +45872,11 @@ var script$85 = {
45846
45872
  if (!Number.isFinite(num)) {
45847
45873
  return formatValue$1(this.value, this.property, { truncate: this.truncate })
45848
45874
  }
45875
+ // `decimal` defaults to one fraction digit, as formatMetricValue does.
45876
+ const defaultDecimals = { currency: 2, decimal: 1 };
45849
45877
  const decimals = Number.isFinite(fmt.decimals)
45850
45878
  ? fmt.decimals
45851
- : (fmt.style === 'currency' ? 2 : 0);
45879
+ : (defaultDecimals[fmt.style] ?? 0);
45852
45880
  let body;
45853
45881
  if (fmt.style === 'currency') {
45854
45882
  // `format.currencyField` reads the code from the row's own field.
@@ -45931,13 +45959,13 @@ const _hoisted_4$62 = {
45931
45959
  class: "cn-cell-renderer__groups"
45932
45960
  };
45933
45961
  const _hoisted_5$5l = { key: 0 };
45934
- const _hoisted_6$4W = {
45962
+ const _hoisted_6$4X = {
45935
45963
  key: 3,
45936
45964
  class: "cn-cell-renderer__actions",
45937
45965
  "data-testid": "cn-cell-actions"
45938
45966
  };
45939
- const _hoisted_7$4u = ["title"];
45940
- const _hoisted_8$42 = {
45967
+ const _hoisted_7$4v = ["title"];
45968
+ const _hoisted_8$43 = {
45941
45969
  key: 1,
45942
45970
  class: "cn-cell-renderer__dash"
45943
45971
  };
@@ -46080,7 +46108,7 @@ const _hoisted_60$4 = {
46080
46108
  key: 0,
46081
46109
  class: "cn-cell-renderer__dash"
46082
46110
  };
46083
- const _hoisted_61$3 = ["title"];
46111
+ const _hoisted_61$4 = ["title"];
46084
46112
  const _hoisted_62$3 = ["title"];
46085
46113
 
46086
46114
  function render$84(_ctx, _cache, $props, $setup, $data, $options) {
@@ -46137,7 +46165,7 @@ function render$84(_ctx, _cache, $props, $setup, $data, $options) {
46137
46165
  ]))
46138
46166
  ], 64 /* STABLE_FRAGMENT */))
46139
46167
  : ($props.widget === 'actions')
46140
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_6$4W, [
46168
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_6$4X, [
46141
46169
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.actionItems, (item) => {
46142
46170
  return (vue$1.openBlock(), vue$1.createBlock(_component_NcButton, {
46143
46171
  key: item.key,
@@ -46160,8 +46188,8 @@ function render$84(_ctx, _cache, $props, $setup, $data, $options) {
46160
46188
  ? (vue$1.openBlock(), vue$1.createElementBlock("span", {
46161
46189
  key: 0,
46162
46190
  title: $options.rawTitle
46163
- }, vue$1.toDisplayString($options.labelledValue), 9 /* TEXT, PROPS */, _hoisted_7$4u))
46164
- : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$42, "—"))
46191
+ }, vue$1.toDisplayString($options.labelledValue), 9 /* TEXT, PROPS */, _hoisted_7$4v))
46192
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$43, "—"))
46165
46193
  ], 64 /* STABLE_FRAGMENT */))
46166
46194
  : ($props.widget === 'badge')
46167
46195
  ? (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 5 }, [
@@ -46568,7 +46596,7 @@ function render$84(_ctx, _cache, $props, $setup, $data, $options) {
46568
46596
  : (vue$1.openBlock(), vue$1.createElementBlock("span", {
46569
46597
  key: 1,
46570
46598
  title: Array.isArray($props.value) ? $props.value.join(', ') : ''
46571
- }, vue$1.toDisplayString($options.formattedValue), 9 /* TEXT, PROPS */, _hoisted_61$3))
46599
+ }, vue$1.toDisplayString($options.formattedValue), 9 /* TEXT, PROPS */, _hoisted_61$4))
46572
46600
  ], 64 /* STABLE_FRAGMENT */))
46573
46601
  : (vue$1.openBlock(), vue$1.createElementBlock("span", {
46574
46602
  key: 26,
@@ -46578,7 +46606,7 @@ function render$84(_ctx, _cache, $props, $setup, $data, $options) {
46578
46606
  }
46579
46607
 
46580
46608
  script$85.render = render$84;
46581
- script$85.__scopeId = "data-v-178f1a90";
46609
+ script$85.__scopeId = "data-v-5e132788";
46582
46610
  const __sfc_main$7$ = script$85;
46583
46611
 
46584
46612
  /**
@@ -49030,13 +49058,13 @@ const _hoisted_3$6H = {
49030
49058
  };
49031
49059
  const _hoisted_4$61 = ["aria-label"];
49032
49060
  const _hoisted_5$5k = ["aria-label", "onClick"];
49033
- const _hoisted_6$4V = {
49061
+ const _hoisted_6$4W = {
49034
49062
  key: 3,
49035
49063
  class: "cn-table-loading",
49036
49064
  "data-testid": "cn-object-list-loading"
49037
49065
  };
49038
- const _hoisted_7$4t = ["tabindex", "role", "aria-label"];
49039
- const _hoisted_8$41 = {
49066
+ const _hoisted_7$4u = ["tabindex", "role", "aria-label"];
49067
+ const _hoisted_8$42 = {
49040
49068
  key: 0,
49041
49069
  class: "cn-data-table__hidden-head"
49042
49070
  };
@@ -49207,7 +49235,7 @@ function render$81(_ctx, _cache, $props, $setup, $data, $options) {
49207
49235
  }, null, 8 /* PROPS */, ["def", "state", "label", "anchorRect", "register", "onClose"]))
49208
49236
  : vue$1.createCommentVNode("v-if", true),
49209
49237
  ($options.isLoading)
49210
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$4V, [
49238
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_6$4W, [
49211
49239
  vue$1.createVNode(_component_NcLoadingIcon, {
49212
49240
  size: 32,
49213
49241
  "aria-hidden": "true"
@@ -49227,7 +49255,7 @@ function render$81(_ctx, _cache, $props, $setup, $data, $options) {
49227
49255
  "data-testid": "cn-object-list-table"
49228
49256
  }, [
49229
49257
  ($props.hideHeader)
49230
- ? (vue$1.openBlock(), vue$1.createElementBlock("thead", _hoisted_8$41, [
49258
+ ? (vue$1.openBlock(), vue$1.createElementBlock("thead", _hoisted_8$42, [
49231
49259
  vue$1.createElementVNode("tr", null, [
49232
49260
  ($props.selectable)
49233
49261
  ? (vue$1.openBlock(), vue$1.createElementBlock("th", _hoisted_9$3J))
@@ -49540,7 +49568,7 @@ function render$81(_ctx, _cache, $props, $setup, $data, $options) {
49540
49568
  }), 128 /* KEYED_FRAGMENT */))
49541
49569
  ])
49542
49570
  ], 2 /* CLASS */)
49543
- ], 8 /* PROPS */, _hoisted_7$4t)),
49571
+ ], 8 /* PROPS */, _hoisted_7$4u)),
49544
49572
  (_ctx.$slots.footer || ($props.viewAllRoute && $options.totalRowCount > $options.effectiveRows.length))
49545
49573
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_39$g, [
49546
49574
  vue$1.renderSlot(_ctx.$slots, "footer", {
@@ -50146,9 +50174,9 @@ const _hoisted_5$5j = {
50146
50174
  key: 0,
50147
50175
  scope: "col"
50148
50176
  };
50149
- const _hoisted_6$4U = { class: "cn-child-records-field__sr" };
50150
- const _hoisted_7$4s = { key: 0 };
50151
- const _hoisted_8$40 = ["colspan"];
50177
+ const _hoisted_6$4V = { class: "cn-child-records-field__sr" };
50178
+ const _hoisted_7$4t = { key: 0 };
50179
+ const _hoisted_8$41 = ["colspan"];
50152
50180
  const _hoisted_9$3I = { key: 1 };
50153
50181
  const _hoisted_10$3i = {
50154
50182
  key: 0,
@@ -50204,18 +50232,18 @@ function render$7$(_ctx, _cache, $props, $setup, $data, $options) {
50204
50232
  }), 128 /* KEYED_FRAGMENT */)),
50205
50233
  (!$props.disabled)
50206
50234
  ? (vue$1.openBlock(), vue$1.createElementBlock("th", _hoisted_5$5j, [
50207
- vue$1.createElementVNode("span", _hoisted_6$4U, vue$1.toDisplayString($options.t('nextcloud-vue', 'Row actions')), 1 /* TEXT */)
50235
+ vue$1.createElementVNode("span", _hoisted_6$4V, vue$1.toDisplayString($options.t('nextcloud-vue', 'Row actions')), 1 /* TEXT */)
50208
50236
  ]))
50209
50237
  : vue$1.createCommentVNode("v-if", true)
50210
50238
  ])
50211
50239
  ]),
50212
50240
  vue$1.createElementVNode("tbody", null, [
50213
50241
  ($options.list.length === 0)
50214
- ? (vue$1.openBlock(), vue$1.createElementBlock("tr", _hoisted_7$4s, [
50242
+ ? (vue$1.openBlock(), vue$1.createElementBlock("tr", _hoisted_7$4t, [
50215
50243
  vue$1.createElementVNode("td", {
50216
50244
  colspan: $options.columns.length + 1,
50217
50245
  class: "cn-child-records-field__empty"
50218
- }, vue$1.toDisplayString($options.t('nextcloud-vue', 'No rows yet.')), 9 /* TEXT, PROPS */, _hoisted_8$40)
50246
+ }, vue$1.toDisplayString($options.t('nextcloud-vue', 'No rows yet.')), 9 /* TEXT, PROPS */, _hoisted_8$41)
50219
50247
  ]))
50220
50248
  : vue$1.createCommentVNode("v-if", true),
50221
50249
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.list, (row, index) => {
@@ -51930,13 +51958,13 @@ const _hoisted_5$5g = {
51930
51958
  key: 0,
51931
51959
  class: "cn-file-field__hint"
51932
51960
  };
51933
- const _hoisted_6$4T = {
51961
+ const _hoisted_6$4U = {
51934
51962
  key: 2,
51935
51963
  class: "cn-file-field__list",
51936
51964
  "data-testid": "cn-file-field-list"
51937
51965
  };
51938
- const _hoisted_7$4r = { class: "cn-file-field__item-name" };
51939
- const _hoisted_8$3$ = {
51966
+ const _hoisted_7$4s = { class: "cn-file-field__item-name" };
51967
+ const _hoisted_8$40 = {
51940
51968
  key: 0,
51941
51969
  class: "cn-file-field__item-size"
51942
51970
  };
@@ -52039,16 +52067,16 @@ function render$7V(_ctx, _cache, $props, $setup, $data, $options) {
52039
52067
  }, null, 8 /* PROPS */, ["facing", "onCapture"]))
52040
52068
  : vue$1.createCommentVNode("v-if", true),
52041
52069
  ($props.multiple && $options.items.length > 0)
52042
- ? (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_6$4T, [
52070
+ ? (vue$1.openBlock(), vue$1.createElementBlock("ul", _hoisted_6$4U, [
52043
52071
  (vue$1.openBlock(true), vue$1.createElementBlock(vue$1.Fragment, null, vue$1.renderList($options.items, (item, index) => {
52044
52072
  return (vue$1.openBlock(), vue$1.createElementBlock("li", {
52045
52073
  key: index,
52046
52074
  class: "cn-file-field__item",
52047
52075
  "data-testid": "cn-file-field-item"
52048
52076
  }, [
52049
- vue$1.createElementVNode("span", _hoisted_7$4r, vue$1.toDisplayString(item.name), 1 /* TEXT */),
52077
+ vue$1.createElementVNode("span", _hoisted_7$4s, vue$1.toDisplayString(item.name), 1 /* TEXT */),
52050
52078
  (item.size)
52051
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$3$, vue$1.toDisplayString($options.formatSize(item.size)), 1 /* TEXT */))
52079
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_8$40, vue$1.toDisplayString($options.formatSize(item.size)), 1 /* TEXT */))
52052
52080
  : vue$1.createCommentVNode("v-if", true),
52053
52081
  (item.held)
52054
52082
  ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_9$3H, vue$1.toDisplayString($options.t('nextcloud-vue', 'Uploads when saved')), 1 /* TEXT */))
@@ -52132,7 +52160,7 @@ const _hoisted_3$6A = {
52132
52160
  };
52133
52161
  const _hoisted_4$5Y = ["id"];
52134
52162
  const _hoisted_5$5f = { class: "cn-form-field__error-text" };
52135
- const _hoisted_6$4S = { class: "cn-form-field__sr" };
52163
+ const _hoisted_6$4T = { class: "cn-form-field__sr" };
52136
52164
 
52137
52165
  function render$7U(_ctx, _cache, $props, $setup, $data, $options) {
52138
52166
  const _component_AlertCircleOutline = vue$1.resolveComponent("AlertCircleOutline");
@@ -52160,7 +52188,7 @@ function render$7U(_ctx, _cache, $props, $setup, $data, $options) {
52160
52188
  "aria-hidden": "true"
52161
52189
  }),
52162
52190
  vue$1.createElementVNode("span", _hoisted_5$5f, [
52163
- vue$1.createElementVNode("span", _hoisted_6$4S, vue$1.toDisplayString($props.errorPrefix), 1 /* TEXT */),
52191
+ vue$1.createElementVNode("span", _hoisted_6$4T, vue$1.toDisplayString($props.errorPrefix), 1 /* TEXT */),
52164
52192
  vue$1.createTextVNode(vue$1.toDisplayString($props.error), 1 /* TEXT */)
52165
52193
  ])
52166
52194
  ], 8 /* PROPS */, _hoisted_4$5Y))
@@ -85163,9 +85191,9 @@ const _hoisted_5$5e = {
85163
85191
  class: "cn-icon-browser-panel__preview-svg",
85164
85192
  viewBox: "0 0 24 24"
85165
85193
  };
85166
- const _hoisted_6$4R = ["d"];
85167
- const _hoisted_7$4q = { class: "cn-icon-browser-panel__preview-label" };
85168
- const _hoisted_8$3_ = ["title", "aria-label"];
85194
+ const _hoisted_6$4S = ["d"];
85195
+ const _hoisted_7$4r = { class: "cn-icon-browser-panel__preview-label" };
85196
+ const _hoisted_8$3$ = ["title", "aria-label"];
85169
85197
  const _hoisted_9$3G = ["aria-label"];
85170
85198
  const _hoisted_10$3g = ["id", "aria-selected", "aria-controls", "tabindex", "onClick", "onKeydown"];
85171
85199
  const _hoisted_11$2W = ["id", "role", "aria-labelledby"];
@@ -85259,11 +85287,11 @@ function render$7S(_ctx, _cache, $props, $setup, $data, $options) {
85259
85287
  }))
85260
85288
  : ($options.currentPath)
85261
85289
  ? (vue$1.openBlock(), vue$1.createElementBlock("svg", _hoisted_5$5e, [
85262
- vue$1.createElementVNode("path", { d: $options.currentPath }, null, 8 /* PROPS */, _hoisted_6$4R)
85290
+ vue$1.createElementVNode("path", { d: $options.currentPath }, null, 8 /* PROPS */, _hoisted_6$4S)
85263
85291
  ]))
85264
85292
  : vue$1.createCommentVNode("v-if", true)
85265
85293
  ]),
85266
- vue$1.createElementVNode("span", _hoisted_7$4q, vue$1.toDisplayString($options.selectedLabel || $options.t('nextcloud-vue', 'No icon selected')), 1 /* TEXT */),
85294
+ vue$1.createElementVNode("span", _hoisted_7$4r, vue$1.toDisplayString($options.selectedLabel || $options.t('nextcloud-vue', 'No icon selected')), 1 /* TEXT */),
85267
85295
  ($props.clearable && $props.value)
85268
85296
  ? (vue$1.openBlock(), vue$1.createElementBlock("button", {
85269
85297
  key: 0,
@@ -85274,7 +85302,7 @@ function render$7S(_ctx, _cache, $props, $setup, $data, $options) {
85274
85302
  onClick: _cache[0] || (_cache[0] = (...args) => ($options.clearIcon && $options.clearIcon(...args)))
85275
85303
  }, [
85276
85304
  vue$1.createVNode(_component_Cancel, { size: 16 })
85277
- ], 8 /* PROPS */, _hoisted_8$3_))
85305
+ ], 8 /* PROPS */, _hoisted_8$3$))
85278
85306
  : vue$1.createCommentVNode("v-if", true)
85279
85307
  ]),
85280
85308
  ($options.tabs.length > 1)
@@ -87695,11 +87723,11 @@ const _hoisted_4$5W = {
87695
87723
  viewBox: "0 0 24 24"
87696
87724
  };
87697
87725
  const _hoisted_5$5d = ["d"];
87698
- const _hoisted_6$4Q = {
87726
+ const _hoisted_6$4R = {
87699
87727
  key: 3,
87700
87728
  class: "cn-icon-browser__trigger-placeholder"
87701
87729
  };
87702
- const _hoisted_7$4p = ["aria-label"];
87730
+ const _hoisted_7$4q = ["aria-label"];
87703
87731
 
87704
87732
  function render$7R(_ctx, _cache, $props, $setup, $data, $options) {
87705
87733
  const _component_CnIconBrowserPanel = vue$1.resolveComponent("CnIconBrowserPanel");
@@ -87764,7 +87792,7 @@ function render$7R(_ctx, _cache, $props, $setup, $data, $options) {
87764
87792
  ? (vue$1.openBlock(), vue$1.createElementBlock("svg", _hoisted_4$5W, [
87765
87793
  vue$1.createElementVNode("path", { d: $options.currentPath }, null, 8 /* PROPS */, _hoisted_5$5d)
87766
87794
  ]))
87767
- : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_6$4Q, vue$1.toDisplayString($options.t('nextcloud-vue', 'Icon')), 1 /* TEXT */))
87795
+ : (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_6$4R, vue$1.toDisplayString($options.t('nextcloud-vue', 'Icon')), 1 /* TEXT */))
87768
87796
  ], 16 /* FULL_PROPS */, _hoisted_2$7h)
87769
87797
  ])
87770
87798
  ]),
@@ -87782,7 +87810,7 @@ function render$7R(_ctx, _cache, $props, $setup, $data, $options) {
87782
87810
  ]),
87783
87811
  _: 3 /* FORWARDED */
87784
87812
  }, 16 /* FULL_PROPS */)
87785
- ], 8 /* PROPS */, _hoisted_7$4p)
87813
+ ], 8 /* PROPS */, _hoisted_7$4q)
87786
87814
  ]),
87787
87815
  _: 3 /* FORWARDED */
87788
87816
  }, 8 /* PROPS */, ["shown"]))
@@ -94785,6 +94813,12 @@ var script$7L = {
94785
94813
  default: '',
94786
94814
  },
94787
94815
 
94816
+ /** A muted line under the title, as given (translate before passing). */
94817
+ subtitle: {
94818
+ type: String,
94819
+ default: '',
94820
+ },
94821
+
94788
94822
  /** Optional MDI icon component for the header */
94789
94823
  icon: {
94790
94824
  type: [Object, Function],
@@ -94849,10 +94883,22 @@ var script$7L = {
94849
94883
  };
94850
94884
 
94851
94885
  const _hoisted_1$7o = { class: "cn-detail-card__header-left" };
94852
- const _hoisted_2$7a = { class: "cn-detail-card__title" };
94853
- const _hoisted_3$6u = { class: "cn-detail-card__header-right" };
94854
- const _hoisted_4$5T = ["aria-label"];
94886
+ const _hoisted_2$7a = {
94887
+ key: 0,
94888
+ class: "cn-detail-card__heading"
94889
+ };
94890
+ const _hoisted_3$6u = { class: "cn-detail-card__title" };
94891
+ const _hoisted_4$5T = {
94892
+ class: "cn-detail-card__subtitle",
94893
+ "data-testid": "cn-detail-card-subtitle"
94894
+ };
94855
94895
  const _hoisted_5$5c = {
94896
+ key: 1,
94897
+ class: "cn-detail-card__title"
94898
+ };
94899
+ const _hoisted_6$4Q = { class: "cn-detail-card__header-right" };
94900
+ const _hoisted_7$4p = ["aria-label"];
94901
+ const _hoisted_8$3_ = {
94856
94902
  key: 1,
94857
94903
  class: "cn-detail-card__footer"
94858
94904
  };
@@ -94880,9 +94926,14 @@ function render$7K(_ctx, _cache, $props, $setup, $data, $options) {
94880
94926
  }))
94881
94927
  : vue$1.createCommentVNode("v-if", true)
94882
94928
  ]),
94883
- vue$1.createElementVNode("h3", _hoisted_2$7a, vue$1.toDisplayString($props.title), 1 /* TEXT */)
94929
+ ($props.subtitle)
94930
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_2$7a, [
94931
+ vue$1.createElementVNode("h3", _hoisted_3$6u, vue$1.toDisplayString($props.title), 1 /* TEXT */),
94932
+ vue$1.createElementVNode("span", _hoisted_4$5T, vue$1.toDisplayString($props.subtitle), 1 /* TEXT */)
94933
+ ]))
94934
+ : (vue$1.openBlock(), vue$1.createElementBlock("h3", _hoisted_5$5c, vue$1.toDisplayString($props.title), 1 /* TEXT */))
94884
94935
  ]),
94885
- vue$1.createElementVNode("div", _hoisted_3$6u, [
94936
+ vue$1.createElementVNode("div", _hoisted_6$4Q, [
94886
94937
  ($options.declaredHeaderActions.length > 0)
94887
94938
  ? (vue$1.openBlock(), vue$1.createBlock(_component_CnWidgetHeaderActionButtons, {
94888
94939
  key: 0,
@@ -94900,7 +94951,7 @@ function render$7K(_ctx, _cache, $props, $setup, $data, $options) {
94900
94951
  size: 20,
94901
94952
  class: vue$1.normalizeClass({ 'cn-detail-card__chevron--rotated': $data.isCollapsed })
94902
94953
  }, null, 8 /* PROPS */, ["class"])
94903
- ], 8 /* PROPS */, _hoisted_4$5T))
94954
+ ], 8 /* PROPS */, _hoisted_7$4p))
94904
94955
  : vue$1.createCommentVNode("v-if", true)
94905
94956
  ])
94906
94957
  ], 2 /* CLASS */))
@@ -94913,7 +94964,7 @@ function render$7K(_ctx, _cache, $props, $setup, $data, $options) {
94913
94964
  [vue$1.vShow, !$data.isCollapsed]
94914
94965
  ]),
94915
94966
  (_ctx.$slots.footer)
94916
- ? vue$1.withDirectives((vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_5$5c, [
94967
+ ? vue$1.withDirectives((vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_8$3_, [
94917
94968
  vue$1.renderSlot(_ctx.$slots, "footer")
94918
94969
  ], 512 /* NEED_PATCH */)), [
94919
94970
  [vue$1.vShow, !$data.isCollapsed]
@@ -94923,7 +94974,7 @@ function render$7K(_ctx, _cache, $props, $setup, $data, $options) {
94923
94974
  }
94924
94975
 
94925
94976
  script$7L.render = render$7K;
94926
- script$7L.__scopeId = "data-v-01384e36";
94977
+ script$7L.__scopeId = "data-v-26edbe9e";
94927
94978
  const __sfc_main$7F = script$7L;
94928
94979
 
94929
94980
  /**
@@ -116478,6 +116529,21 @@ var script$71 = {
116478
116529
  default: '',
116479
116530
  },
116480
116531
 
116532
+ /**
116533
+ * The second line as a list of fields joined with " · ", a field
116534
+ * without a value left out: the `nameSecondary` tokens without their
116535
+ * braces (`["type", "size", "modified|date"]`, a row-data field such as
116536
+ * `"senderName"`). Or a list of variants `{ when, fields }`: the first
116537
+ * whose `when` is `true`, or that has no `when`, is used (a case type
116538
+ * flag read through `@context`). Takes precedence over `nameSecondary`.
116539
+ *
116540
+ * @spec openspec/changes/files-second-line-fields/specs/files-second-line-fields/spec.md#requirement-a-files-second-line-is-a-list-of-fields
116541
+ */
116542
+ secondLine: {
116543
+ type: Array,
116544
+ default: null,
116545
+ },
116546
+
116481
116547
  /** The line `dropHint` shows. */
116482
116548
  dropHintLabel: {
116483
116549
  type: String,
@@ -116876,6 +116942,26 @@ var script$71 = {
116876
116942
  *
116877
116943
  * @return {Array<object>} The file nodes.
116878
116944
  */
116945
+ /**
116946
+ * The fields `secondLine` names for this browser: the list itself, or
116947
+ * the fields of its first variant whose `when` is `true` or absent.
116948
+ * Null without `secondLine` or a matching variant.
116949
+ *
116950
+ * @return {Array<string>|null}
116951
+ * @spec openspec/changes/files-second-line-fields/specs/files-second-line-fields/spec.md#requirement-a-files-second-line-is-a-list-of-fields
116952
+ */
116953
+ secondLineFields() {
116954
+ const list = Array.isArray(this.secondLine) ? this.secondLine : [];
116955
+ if (list.length === 0) {
116956
+ return null
116957
+ }
116958
+ if (list.every((item) => typeof item === 'string')) {
116959
+ return list
116960
+ }
116961
+ const variant = list.find((item) => item && typeof item === 'object' && Array.isArray(item.fields) && (!('when' in item) || item.when === true));
116962
+ return variant ? variant.fields.filter((field) => typeof field === 'string') : null
116963
+ },
116964
+
116879
116965
  /**
116880
116966
  * The bulk bar's count text.
116881
116967
  *
@@ -117429,7 +117515,8 @@ var script$71 = {
117429
117515
  * @return {string}
117430
117516
  */
117431
117517
  nameSecondaryOf(node) {
117432
- if (!this.nameSecondary || this.isFolder(node)) {
117518
+ const fields = this.secondLineFields;
117519
+ if ((!this.nameSecondary && fields === null) || this.isFolder(node)) {
117433
117520
  return ''
117434
117521
  }
117435
117522
  const byId = this.resolvedRowData && typeof this.resolvedRowData === 'object' ? this.resolvedRowData : {};
@@ -117443,6 +117530,12 @@ var script$71 = {
117443
117530
  type: this.typeLabelOf(node),
117444
117531
  ...(owner ? { owner } : {}),
117445
117532
  };
117533
+ if (fields !== null) {
117534
+ return fields
117535
+ .map((field) => fillTemplate(`{${field}}`, object))
117536
+ .filter((text) => text !== '')
117537
+ .join(' · ')
117538
+ }
117446
117539
  return fillTemplate(this.cnTranslate(this.nameSecondary), object)
117447
117540
  },
117448
117541
 
@@ -119618,7 +119711,7 @@ function render$70(_ctx, _cache, $props, $setup, $data, $options) {
119618
119711
  }
119619
119712
 
119620
119713
  script$71.render = render$70;
119621
- script$71.__scopeId = "data-v-541e44c4";
119714
+ script$71.__scopeId = "data-v-7ce558e7";
119622
119715
  const __sfc_main$6X = script$71;
119623
119716
 
119624
119717
  /**
@@ -120053,6 +120146,8 @@ var script$70 = {
120053
120146
  footnote: { type: String, default: '' },
120054
120147
  /** Forwarded to CnFilesBrowser: the second line under each file's name. */
120055
120148
  nameSecondary: { type: String, default: '' },
120149
+ /** Forwarded to CnFilesBrowser: the second line as a list of fields, or variants. */
120150
+ secondLine: { type: Array, default: null },
120056
120151
  /** A dotted path to the list of records in the `rowDataUrl` answer; empty reads the answer itself. */
120057
120152
  rowDataPath: { type: String, default: '' },
120058
120153
  /** The record field that holds the Nextcloud file id. */
@@ -120757,6 +120852,7 @@ function render$6$(_ctx, _cache, $props, $setup, $data, $options) {
120757
120852
  reviewSummary: $props.reviewSummary,
120758
120853
  footnote: $props.footnote,
120759
120854
  nameSecondary: $props.nameSecondary,
120855
+ secondLine: $props.secondLine,
120760
120856
  linkedItems: $data.linkedItems,
120761
120857
  columns: $props.columns,
120762
120858
  rowData: $options.rowDataSource,
@@ -120771,7 +120867,7 @@ function render$6$(_ctx, _cache, $props, $setup, $data, $options) {
120771
120867
  groupBy: $props.groupBy,
120772
120868
  facets: $props.facets,
120773
120869
  onChanged: $options.onBrowserChanged
120774
- }, null, 8 /* PROPS */, ["rootPath", "rootLabel", "source", "deleteLabel", "uploadButton", "newMenu", "folderButton", "dropOverlay", "dropLabel", "dropDetail", "dropHint", "rowActions", "newActions", "headerActions", "rowButton", "reviewSummary", "footnote", "nameSecondary", "linkedItems", "columns", "rowData", "preferenceApp", "preferenceKey", "bulkActions", "selectionLabel", "selectionLabelOne", "showClearSelection", "sideCards", "sideCardsPlacement", "groupBy", "facets", "onChanged"]))
120870
+ }, null, 8 /* PROPS */, ["rootPath", "rootLabel", "source", "deleteLabel", "uploadButton", "newMenu", "folderButton", "dropOverlay", "dropLabel", "dropDetail", "dropHint", "rowActions", "newActions", "headerActions", "rowButton", "reviewSummary", "footnote", "nameSecondary", "secondLine", "linkedItems", "columns", "rowData", "preferenceApp", "preferenceKey", "bulkActions", "selectionLabel", "selectionLabelOne", "showClearSelection", "sideCards", "sideCardsPlacement", "groupBy", "facets", "onChanged"]))
120775
120871
  : (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 1 }, [
120776
120872
  ($data.uploadError)
120777
120873
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_2$6w, vue$1.toDisplayString($data.uploadError), 1 /* TEXT */))
@@ -121022,7 +121118,7 @@ function render$6$(_ctx, _cache, $props, $setup, $data, $options) {
121022
121118
  }
121023
121119
 
121024
121120
  script$70.render = render$6$;
121025
- script$70.__scopeId = "data-v-043f08e2";
121121
+ script$70.__scopeId = "data-v-89d80864";
121026
121122
  const __sfc_main$6W = script$70;
121027
121123
 
121028
121124
  /**
@@ -141943,7 +142039,7 @@ function fillRowTemplate(template, row) {
141943
142039
  * and its count (DqZoekresultaten).
141944
142040
  *
141945
142041
  * `sourceConfig.kinds` lists what is searched:
141946
- * `{ id, label, register, schema, titleField?, subtitleField?, statusField?, statusResolve?, linkedField?, linkedTemplate?, href?, limit? }`
142042
+ * `{ id, label, register, schema, titleField?, subtitleField?, subtitleTemplate?, statusField?, statusResolve?, linkedField?, linkedTemplate?, href?, limit? }`
141947
142043
  * for objects (OpenRegister's `_search`, so the reader sees what they may
141948
142044
  * read), or `{ id, label, files: true, limit? }` for the reader's files
141949
142045
  * (Nextcloud's unified search). The term is `sourceConfig.term`, else the
@@ -141957,6 +142053,8 @@ function fillRowTemplate(template, row) {
141957
142053
  * coloured by `sourceConfig.statusColorMap`. `linkedTemplate` (a field
141958
142054
  * template, "{case.title}") or `linkedField` (a path) fills the "Linked"
141959
142055
  * column, drawn when a kind declares one; `sourceConfig.linkedLabel` names it.
142056
+ * `subtitleTemplate` ("Case {identifier}", translated) fills the line under a
142057
+ * result, else `subtitleField`.
141960
142058
  * The page's title and count line can name the term as `{term}`, and the
141961
142059
  * count is the active kind's total. Kind, link and status are filterable.
141962
142060
  *
@@ -142054,6 +142152,13 @@ function searchSource(config = {}, context = {}) {
142054
142152
  return ''
142055
142153
  };
142056
142154
 
142155
+ const subtitleOf = (kind, object) => {
142156
+ if (kind.subtitleTemplate) {
142157
+ return fillTemplate(translate(kind.subtitleTemplate), object)
142158
+ }
142159
+ return kind.subtitleField ? String(readPath$8(object, kind.subtitleField) ?? '') : ''
142160
+ };
142161
+
142057
142162
  const searchObjects = async (axios, kind, term) => {
142058
142163
  const url = router.generateUrl('/apps/openregister/api/objects/{register}/{schema}', { register: kind.register, schema: kind.schema });
142059
142164
  const res = await axios.get(url, { params: { _search: term, _limit: kind.limit || 20 } });
@@ -142074,7 +142179,7 @@ function searchSource(config = {}, context = {}) {
142074
142179
  kindLabel: kind.label,
142075
142180
  kindText: kindTextOf(kind, object),
142076
142181
  title: String(readPath$8(object, kind.titleField || 'title') ?? object.name ?? id ?? ''),
142077
- subtitle: kind.subtitleField ? String(readPath$8(object, kind.subtitleField) ?? '') : '',
142182
+ subtitle: subtitleOf(kind, object),
142078
142183
  status,
142079
142184
  linked: linkedOf(kind, object),
142080
142185
  href: kind.href ? router.generateUrl(fillRowTemplate(kind.href, { ...object, id })) : '',
@@ -142261,14 +142366,24 @@ function searchSource(config = {}, context = {}) {
142261
142366
  * the pager asks for.
142262
142367
  *
142263
142368
  * @param {Array<object>} members The members, by name.
142264
- * @param {object} config `search`, `sortKey`, `sortOrder`, `limit`, `offset`.
142369
+ * @param {object} config `search`, `nameLike`, `rolesLike`, `emailLike`, `today`, `sortKey`, `sortOrder`, `limit`, `offset`.
142265
142370
  * @return {{rows: Array<object>, total: number}} The page and how many match.
142266
142371
  */
142267
142372
  function membersPage(members, config = {}) {
142373
+ const has = (member, fields, text) => fields.some((field) => String(member[field] || '').toLowerCase().includes(text));
142268
142374
  const term = String(config.search || '').trim().toLowerCase();
142269
- let rows = term === ''
142270
- ? members.slice()
142271
- : members.filter((member) => ['displayname', 'function', 'roles', 'email'].some((field) => String(member[field] || '').toLowerCase().includes(term)));
142375
+ let rows = term === '' ? members.slice() : members.filter((member) => has(member, ['displayname', 'function', 'roles', 'email'], term));
142376
+ // The table heads' filters: text contains, and the Today values picked.
142377
+ for (const [param, fields] of [['nameLike', ['displayname', 'function']], ['rolesLike', ['roles']], ['emailLike', ['email']]]) {
142378
+ const text = String(config[param] || '').trim().toLowerCase();
142379
+ if (text !== '') {
142380
+ rows = rows.filter((member) => has(member, fields, text));
142381
+ }
142382
+ }
142383
+ const today = (Array.isArray(config.today) ? config.today : (config.today ? [config.today] : [])).map(String);
142384
+ if (today.length > 0) {
142385
+ rows = rows.filter((member) => today.includes(member.today));
142386
+ }
142272
142387
  if (config.sortKey) {
142273
142388
  const sign = config.sortOrder === 'desc' ? -1 : 1;
142274
142389
  rows = rows.sort((a, b) => sign * String(a[config.sortKey] ?? '').localeCompare(String(b[config.sortKey] ?? '')));
@@ -142330,10 +142445,11 @@ function usersSource() {
142330
142445
  */
142331
142446
  load: async (config) => {
142332
142447
  const group = String((config && (config.group || config.defaultGroup)) || '');
142333
- const { search, sortKey, sortOrder, limit, offset, ...request } = config || {};
142448
+ const { search, sortKey, sortOrder, limit, offset, nameLike, rolesLike, emailLike, today, ...request } = config || {};
142334
142449
  const key = JSON.stringify({ ...request, group });
142335
- // A new page, term or order of the members already read: no request.
142336
- if (key === membersKey && (offset !== undefined || search !== undefined || sortKey !== undefined)) {
142450
+ const narrows = [offset, search, sortKey, nameLike, rolesLike, emailLike, today].some((value) => value !== undefined);
142451
+ // A new page, term, order or head filter of the members already read: no request.
142452
+ if (key === membersKey && narrows) {
142337
142453
  const page = membersPage(readMembers, config);
142338
142454
  state.rows = page.rows;
142339
142455
  state.total = page.total;
@@ -142429,8 +142545,15 @@ function usersSource() {
142429
142545
 
142430
142546
  searchFields: {
142431
142547
  group: { param: 'group', single: true },
142548
+ 'displayname[like]': { param: 'nameLike', single: true },
142549
+ 'roles[like]': { param: 'rolesLike', single: true },
142550
+ 'email[like]': { param: 'emailLike', single: true },
142551
+ today: { param: 'today' },
142432
142552
  },
142433
142553
 
142554
+ /** A filter button on every head (DqAfdelingen); the members read are narrowed here. */
142555
+ headerFilters: true,
142556
+
142434
142557
  showAdd: false,
142435
142558
  }
142436
142559
  }
@@ -164955,7 +165078,7 @@ const _hoisted_60$3 = {
164955
165078
  key: 1,
164956
165079
  class: "cn-related-objects-widget__footer-actions"
164957
165080
  };
164958
- const _hoisted_61$2 = { class: "cn-related-objects-widget__footer" };
165081
+ const _hoisted_61$3 = { class: "cn-related-objects-widget__footer" };
164959
165082
  const _hoisted_62$2 = {
164960
165083
  key: 2,
164961
165084
  class: "cn-related-objects-widget__add-error"
@@ -165444,7 +165567,7 @@ function render$64(_ctx, _cache, $props, $setup, $data, $options) {
165444
165567
  ? {
165445
165568
  name: "footer",
165446
165569
  fn: vue$1.withCtx(() => [
165447
- vue$1.createElementVNode("div", _hoisted_61$2, [
165570
+ vue$1.createElementVNode("div", _hoisted_61$3, [
165448
165571
  ($options.soleAddable && $options.soleAddable.key === 'files')
165449
165572
  ? (vue$1.openBlock(), vue$1.createBlock(_component_NcButton, {
165450
165573
  key: 0,
@@ -199856,6 +199979,7 @@ var script$5e = {
199856
199979
  objectId: this.objectId,
199857
199980
  object: this.object,
199858
199981
  config: unwrapAppConfig(this.cnAppConfig),
199982
+ context: (this.cnDetailVisibilityRows && this.cnDetailVisibilityRows.value) || null,
199859
199983
  })
199860
199984
  },
199861
199985
 
@@ -199922,6 +200046,7 @@ var script$5e = {
199922
200046
  // prints its title as given.
199923
200047
  title: this.translateLabel(this.widget?.title || ''),
199924
200048
  ...this.leafTitleLabel,
200049
+ ...(this.widgetSubtitle ? { subtitle: this.translateLabel(this.widgetSubtitle) } : {}),
199925
200050
  // A provider opting into `bareWidget` is being rendered where the
199926
200051
  // tab strip already supplies the card and the title, so tell it to
199927
200052
  // drop its own. Without this the panel gets a titled card inside
@@ -201013,7 +201138,7 @@ function render$5d(_ctx, _cache, $props, $setup, $data, $options) {
201013
201138
  }
201014
201139
 
201015
201140
  script$5e.render = render$5d;
201016
- script$5e.__scopeId = "data-v-32a82d6a";
201141
+ script$5e.__scopeId = "data-v-10c797a6";
201017
201142
  const __sfc_main$58 = script$5e;
201018
201143
 
201019
201144
  /**
@@ -242345,6 +242470,10 @@ registerDashboardWidget('mail', {
242345
242470
  displayName: 'Mail',
242346
242471
  icon: 'EmailOutline',
242347
242472
  surfaces: ['detail-page'],
242473
+ // Draws its own title row; on a card surface it stands in an untitled card.
242474
+ // @spec openspec/changes/mail-widget-card/specs/mail-widget-card/spec.md#requirement-the-mail-widget-stands-in-a-card-on-a-card-surface
242475
+ ownsTitle: true,
242476
+ chrome: 'card',
242348
242477
  });
242349
242478
 
242350
242479
  /**
@@ -251259,6 +251388,18 @@ var script$3Q = {
251259
251388
  * @return {string}
251260
251389
  * @spec openspec/changes/record-list-table-row-actions/specs/record-list-table/spec.md#requirement-a-table-row-can-carry-a-second-line-and-an-actions-menu
251261
251390
  */
251391
+ /**
251392
+ * Whether the row action is drawn as an outlined button sized to its
251393
+ * label (`rowAction.variant: "outlined"`, DqMijnTeam "Oppakken") instead
251394
+ * of the 150px pill (DcMijnActies "Stem uitbrengen").
251395
+ *
251396
+ * @return {boolean} True for the outlined variant.
251397
+ * @spec openspec/changes/board-row-action-outlined/specs/board-row-action-outlined/spec.md#requirement-a-dashboard-rows-action-is-an-outlined-button
251398
+ */
251399
+ rowActionOutlined() {
251400
+ return this.content?.rowAction?.variant === 'outlined'
251401
+ },
251402
+
251262
251403
  rowActionsHeader() {
251263
251404
  const own = this.content?.rowActionsHeader;
251264
251405
  return typeof own === 'string' && own !== '' ? this.translate(own) : l10n.translate('nextcloud-vue', 'Actions')
@@ -251301,6 +251442,10 @@ var script$3Q = {
251301
251442
  if (this.conditionalEmptyText !== '') {
251302
251443
  return this.conditionalEmptyText
251303
251444
  }
251445
+ // `emptyText: ""` says nothing on an empty list.
251446
+ if (this.content?.emptyText === '') {
251447
+ return ''
251448
+ }
251304
251449
  return this.content?.emptyText ? this.translate(this.content.emptyText) : l10n.translate('nextcloud-vue', 'Nothing here yet')
251305
251450
  },
251306
251451
 
@@ -252622,7 +252767,7 @@ const _hoisted_4$2W = {
252622
252767
  class: "cn-record-list__loading"
252623
252768
  };
252624
252769
  const _hoisted_5$2x = {
252625
- key: 4,
252770
+ key: 0,
252626
252771
  class: "cn-record-list__empty",
252627
252772
  "data-testid": "cn-record-list-empty"
252628
252773
  };
@@ -252812,7 +252957,7 @@ const _hoisted_60$2 = {
252812
252957
  class: "cn-record-list__footnote",
252813
252958
  "data-testid": "cn-record-list-footnote"
252814
252959
  };
252815
- const _hoisted_61$1 = ["href"];
252960
+ const _hoisted_61$2 = ["href"];
252816
252961
  const _hoisted_62$1 = {
252817
252962
  key: 15,
252818
252963
  class: "cn-record-list__group-head",
@@ -252862,7 +253007,11 @@ function render$3P(_ctx, _cache, $props, $setup, $data, $options) {
252862
253007
  }, null, 8 /* PROPS */, ["name"])
252863
253008
  ]))
252864
253009
  : ($data.rows.length === 0)
252865
- ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_5$2x, vue$1.toDisplayString($options.emptyLabel), 1 /* TEXT */))
253010
+ ? (vue$1.openBlock(), vue$1.createElementBlock(vue$1.Fragment, { key: 4 }, [
253011
+ ($options.emptyLabel !== '')
253012
+ ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_5$2x, vue$1.toDisplayString($options.emptyLabel), 1 /* TEXT */))
253013
+ : vue$1.createCommentVNode("v-if", true)
253014
+ ], 64 /* STABLE_FRAGMENT */))
252866
253015
  : ($options.presentation === 'notice')
252867
253016
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", {
252868
253017
  key: 5,
@@ -253172,12 +253321,14 @@ function render$3P(_ctx, _cache, $props, $setup, $data, $options) {
253172
253321
  (item.trailing)
253173
253322
  ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_31$d, vue$1.toDisplayString(item.trailing), 1 /* TEXT */))
253174
253323
  : vue$1.createCommentVNode("v-if", true),
253175
- (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent(item.action.tag), vue$1.mergeProps({ class: "cn-record-list__action" }, { ref_for: true }, item.action.attrs, { "data-testid": "cn-record-list-action" }, vue$1.toHandlers(item.action.tag === 'button' ? { click: () => $options.runRowAction(item.row) } : {})), {
253324
+ (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent(item.action.tag), vue$1.mergeProps({
253325
+ class: ["cn-record-list__action", { 'cn-record-list__action--outlined': $options.rowActionOutlined }]
253326
+ }, { ref_for: true }, item.action.attrs, { "data-testid": "cn-record-list-action" }, vue$1.toHandlers(item.action.tag === 'button' ? { click: () => $options.runRowAction(item.row) } : {})), {
253176
253327
  default: vue$1.withCtx(() => [
253177
253328
  vue$1.createTextVNode(vue$1.toDisplayString(item.action.label), 1 /* TEXT */)
253178
253329
  ]),
253179
253330
  _: 2 /* DYNAMIC */
253180
- }, 1040 /* FULL_PROPS, DYNAMIC_SLOTS */))
253331
+ }, 1040 /* FULL_PROPS, DYNAMIC_SLOTS */, ["class"]))
253181
253332
  ]))
253182
253333
  : ($options.presentation === 'rows')
253183
253334
  ? (vue$1.openBlock(), vue$1.createBlock(vue$1.resolveDynamicComponent(item.tag), vue$1.mergeProps({
@@ -253510,7 +253661,7 @@ function render$3P(_ctx, _cache, $props, $setup, $data, $options) {
253510
253661
  class: "cn-record-list__footer-link",
253511
253662
  href: $options.footerLink.href,
253512
253663
  "data-testid": "cn-record-list-footer-link"
253513
- }, vue$1.toDisplayString($options.footerLink.label), 9 /* TEXT, PROPS */, _hoisted_61$1))
253664
+ }, vue$1.toDisplayString($options.footerLink.label), 9 /* TEXT, PROPS */, _hoisted_61$2))
253514
253665
  : vue$1.createCommentVNode("v-if", true),
253515
253666
  ($options.footerGroupHead && $data.rows.length === 0 && !$data.error && !$data.loading)
253516
253667
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_62$1, [
@@ -253601,7 +253752,7 @@ function render$3P(_ctx, _cache, $props, $setup, $data, $options) {
253601
253752
  }
253602
253753
 
253603
253754
  script$3Q.render = render$3P;
253604
- script$3Q.__scopeId = "data-v-3c8e615c";
253755
+ script$3Q.__scopeId = "data-v-38566d36";
253605
253756
  const __sfc_main$3Q = script$3Q;
253606
253757
 
253607
253758
  /**
@@ -325338,6 +325489,12 @@ var script$2u = {
325338
325489
  default: '',
325339
325490
  },
325340
325491
 
325492
+ /** Keep the label for assistive technology only, when a heading above already says it. */
325493
+ hideLabel: {
325494
+ type: Boolean,
325495
+ default: false,
325496
+ },
325497
+
325341
325498
  /** The picker's label. */
325342
325499
  addLabel: {
325343
325500
  type: String,
@@ -325683,8 +325840,8 @@ function render$2t(_ctx, _cache, $props, $setup, $data, $options) {
325683
325840
  ? (vue$1.openBlock(), vue$1.createElementBlock("p", {
325684
325841
  key: 0,
325685
325842
  id: $data.labelId,
325686
- class: "cn-ordered-list-field__label"
325687
- }, vue$1.toDisplayString($props.label), 9 /* TEXT, PROPS */, _hoisted_2$2p))
325843
+ class: vue$1.normalizeClass(["cn-ordered-list-field__label", { 'hidden-visually': $props.hideLabel }])
325844
+ }, vue$1.toDisplayString($props.label), 11 /* TEXT, CLASS, PROPS */, _hoisted_2$2p))
325688
325845
  : vue$1.createCommentVNode("v-if", true),
325689
325846
  ($options.rows.length > 0)
325690
325847
  ? (vue$1.openBlock(), vue$1.createElementBlock("ol", {
@@ -325833,7 +325990,7 @@ function render$2t(_ctx, _cache, $props, $setup, $data, $options) {
325833
325990
  }
325834
325991
 
325835
325992
  script$2u.render = render$2t;
325836
- script$2u.__scopeId = "data-v-8f7a2df6";
325993
+ script$2u.__scopeId = "data-v-54034c6f";
325837
325994
  const __sfc_main$2u = script$2u;
325838
325995
 
325839
325996
  // SPDX-FileCopyrightText: 2026 Conduction B.V.
@@ -326744,6 +326901,7 @@ function render$2s(_ctx, _cache, $props, $setup, $data, $options) {
326744
326901
  modelValue: $options.values,
326745
326902
  options: $options.options,
326746
326903
  label: $options.t('nextcloud-vue', 'Views in my menu'),
326904
+ hideLabel: true,
326747
326905
  addLabel: $options.t('nextcloud-vue', 'Add view'),
326748
326906
  addPlaceholder: $options.t('nextcloud-vue', 'Pick a saved view'),
326749
326907
  addHint: $options.t('nextcloud-vue', 'You see your own views, the views shared with you and the default views. A new view goes to the bottom.'),
@@ -326757,7 +326915,7 @@ function render$2s(_ctx, _cache, $props, $setup, $data, $options) {
326757
326915
  }
326758
326916
 
326759
326917
  script$2t.render = render$2s;
326760
- script$2t.__scopeId = "data-v-dfcd17c4";
326918
+ script$2t.__scopeId = "data-v-962f985c";
326761
326919
  const __sfc_main$2t = script$2t;
326762
326920
 
326763
326921
  /**
@@ -356673,6 +356831,31 @@ var script$20 = {
356673
356831
  return l10n.translatePlural('nextcloud-vue', '%n without an address', '%n without an address', this.mapList.missing.length)
356674
356832
  },
356675
356833
 
356834
+ /**
356835
+ * The sentence on that card naming the rows without a place by the
356836
+ * list's title template, three at most and the rest counted: "A, B and
356837
+ * C have no location, so they are not on the map." Empty without a
356838
+ * title template.
356839
+ *
356840
+ * @spec openspec/changes/map-missing-card-names-the-cases/specs/map-missing-card-names-the-cases/spec.md#requirement-the-missing-address-card-names-the-cases-it-counts
356841
+ * @return {string} The sentence.
356842
+ */
356843
+ mapMissingNote() {
356844
+ const list = this.mapConfig && this.mapConfig.list;
356845
+ const template = list && typeof list.title === 'string' ? this.cnTranslate(list.title) : '';
356846
+ const missing = this.mapList.missing;
356847
+ if (template === '' || missing.length === 0) {
356848
+ return ''
356849
+ }
356850
+ const shown = missing.slice(0, 3).map((row) => fillTemplate(template, row, undefined, this.cnFormatters ? { formatters: this.cnFormatters } : null)).filter((title) => title !== '');
356851
+ if (shown.length === 0) {
356852
+ return ''
356853
+ }
356854
+ const rest = missing.length - shown.length;
356855
+ const names = listText(rest > 0 ? [...shown, l10n.translatePlural('nextcloud-vue', '%n other', '%n others', rest)] : shown, l10n.getCanonicalLocale() || undefined);
356856
+ return l10n.translatePlural('nextcloud-vue', '{names} has no location, so it is not on the map.', '{names} have no location, so they are not on the map.', missing.length, { names })
356857
+ },
356858
+
356676
356859
  /** @return {string} The link from that card to the table. */
356677
356860
  mapMissingLink() {
356678
356861
  return l10n.translate('nextcloud-vue', 'Show them in the table')
@@ -360975,10 +361158,16 @@ var script$20 = {
360975
361158
  const bucket = facet && Array.isArray(facet.values)
360976
361159
  ? facet.values.find((fv) => fv && typeof fv === 'object' && String(fv.value) === id)
360977
361160
  : null;
360978
- if (bucket && typeof bucket.label === 'string' && bucket.label !== '') {
361161
+ // A facet that only echoes the value names nothing; a group or an
361162
+ // option below may.
361163
+ if (bucket && typeof bucket.label === 'string' && bucket.label !== '' && bucket.label !== id) {
360979
361164
  return this.cnTranslate(bucket.label)
360980
361165
  }
360981
361166
  const prop = this.effectiveSchema?.properties?.[key];
361167
+ // The reader on a user filter is "me" (DqFilterInMenu "Behandelaar: ik").
361168
+ if (prop && prop.referenceType === 'nextcloud-user' && id === (auth.getCurrentUser()?.uid ?? '')) {
361169
+ return l10n.translate('nextcloud-vue', 'me')
361170
+ }
360982
361171
  if (prop && prop.referenceType === 'nextcloud-group') {
360983
361172
  const name = groupDisplayName(id);
360984
361173
  if (name === null) {
@@ -363692,35 +363881,40 @@ const _hoisted_52$1 = {
363692
363881
  "data-testid": "cn-index-map-missing"
363693
363882
  };
363694
363883
  const _hoisted_53$1 = {
363884
+ key: 0,
363885
+ class: "cn-index-page__map-missing-note",
363886
+ "data-testid": "cn-index-map-missing-note"
363887
+ };
363888
+ const _hoisted_54$1 = {
363695
363889
  key: 16,
363696
363890
  class: "cn-index-page__content-search-note",
363697
363891
  "data-testid": "cn-index-content-search-note"
363698
363892
  };
363699
- const _hoisted_54$1 = {
363893
+ const _hoisted_55$1 = {
363700
363894
  key: 17,
363701
363895
  class: "cn-index-page__map-count",
363702
363896
  "data-testid": "cn-index-map-count"
363703
363897
  };
363704
- const _hoisted_55$1 = {
363898
+ const _hoisted_56$1 = {
363705
363899
  key: 0,
363706
363900
  "data-testid": "cn-index-map-count-line"
363707
363901
  };
363708
- const _hoisted_56$1 = {
363902
+ const _hoisted_57$1 = {
363709
363903
  key: 1,
363710
363904
  class: "cn-index-page__map-cap",
363711
363905
  "data-testid": "cn-index-map-cap"
363712
363906
  };
363713
- const _hoisted_57$1 = {
363907
+ const _hoisted_58$1 = {
363714
363908
  key: 18,
363715
363909
  class: "cn-index-page__board-load",
363716
363910
  "data-testid": "cn-index-board-load"
363717
363911
  };
363718
- const _hoisted_58$1 = {
363912
+ const _hoisted_59$1 = {
363719
363913
  class: "cn-index-page__board-load-count",
363720
363914
  "data-testid": "cn-index-board-load-count"
363721
363915
  };
363722
- const _hoisted_59$1 = ["data-split-layout"];
363723
- const _hoisted_60$1 = ["href", "title"];
363916
+ const _hoisted_60$1 = ["data-split-layout"];
363917
+ const _hoisted_61$1 = ["href", "title"];
363724
363918
 
363725
363919
  function render$1$(_ctx, _cache, $props, $setup, $data, $options) {
363726
363920
  const _component_CnBuildiqEditButton = vue$1.resolveComponent("CnBuildiqEditButton");
@@ -365033,6 +365227,9 @@ function render$1$(_ctx, _cache, $props, $setup, $data, $options) {
365033
365227
  ($options.mapList.missing.length > 0)
365034
365228
  ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_52$1, [
365035
365229
  vue$1.createElementVNode("strong", null, vue$1.toDisplayString($options.mapMissingTitle), 1 /* TEXT */),
365230
+ ($options.mapMissingNote)
365231
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_53$1, vue$1.toDisplayString($options.mapMissingNote), 1 /* TEXT */))
365232
+ : vue$1.createCommentVNode("v-if", true),
365036
365233
  vue$1.createVNode(_component_NcButton, {
365037
365234
  variant: "tertiary-no-background",
365038
365235
  "data-testid": "cn-index-map-missing-table",
@@ -365272,21 +365469,21 @@ function render$1$(_ctx, _cache, $props, $setup, $data, $options) {
365272
365469
  onClose: $setup.closeContextMenu
365273
365470
  }, null, 8 /* PROPS */, ["open", "actions", "targetItem", "onAction", "onClose"]),
365274
365471
  ($props.searchInFiles && $setup.contentSearch)
365275
- ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_53$1, vue$1.toDisplayString(_ctx.t('nextcloud-vue', 'File matches are limited to the best 50.')), 1 /* TEXT */))
365472
+ ? (vue$1.openBlock(), vue$1.createElementBlock("p", _hoisted_54$1, vue$1.toDisplayString(_ctx.t('nextcloud-vue', 'File matches are limited to the best 50.')), 1 /* TEXT */))
365276
365473
  : vue$1.createCommentVNode("v-if", true),
365277
365474
  ($options.mapCountLine || $options.mapCapNote)
365278
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_54$1, [
365475
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_55$1, [
365279
365476
  ($options.mapCountLine)
365280
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_55$1, vue$1.toDisplayString($options.mapCountLine), 1 /* TEXT */))
365477
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_56$1, vue$1.toDisplayString($options.mapCountLine), 1 /* TEXT */))
365281
365478
  : vue$1.createCommentVNode("v-if", true),
365282
365479
  ($options.mapCapNote)
365283
- ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_56$1, vue$1.toDisplayString($options.mapCapNote), 1 /* TEXT */))
365480
+ ? (vue$1.openBlock(), vue$1.createElementBlock("span", _hoisted_57$1, vue$1.toDisplayString($options.mapCapNote), 1 /* TEXT */))
365284
365481
  : vue$1.createCommentVNode("v-if", true)
365285
365482
  ]))
365286
365483
  : vue$1.createCommentVNode("v-if", true),
365287
365484
  ($options.boardLoadsAll && $options.boardLoadCounts.total > 0)
365288
- ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_57$1, [
365289
- vue$1.createElementVNode("span", _hoisted_58$1, vue$1.toDisplayString(_ctx.t('nextcloud-vue', 'Showing {count} of {total}', { count: $options.boardLoadCounts.shown, total: $options.boardLoadCounts.total })), 1 /* TEXT */),
365485
+ ? (vue$1.openBlock(), vue$1.createElementBlock("div", _hoisted_58$1, [
365486
+ vue$1.createElementVNode("span", _hoisted_59$1, vue$1.toDisplayString(_ctx.t('nextcloud-vue', 'Showing {count} of {total}', { count: $options.boardLoadCounts.shown, total: $options.boardLoadCounts.total })), 1 /* TEXT */),
365290
365487
  ($options.isPaged)
365291
365488
  ? (vue$1.openBlock(), vue$1.createBlock(_component_NcButton, {
365292
365489
  key: 0,
@@ -365358,7 +365555,7 @@ function render$1$(_ctx, _cache, $props, $setup, $data, $options) {
365358
365555
  }, [
365359
365556
  vue$1.createVNode(_component_Close, { size: 16 }),
365360
365557
  vue$1.createElementVNode("span", null, vue$1.toDisplayString($options.splitCloseTitle), 1 /* TEXT */)
365361
- ], 8 /* PROPS */, _hoisted_60$1))
365558
+ ], 8 /* PROPS */, _hoisted_61$1))
365362
365559
  : vue$1.createCommentVNode("v-if", true),
365363
365560
  vue$1.renderSlot(_ctx.$slots, "split-pane", {
365364
365561
  id: $props.splitId,
@@ -365366,7 +365563,7 @@ function render$1$(_ctx, _cache, $props, $setup, $data, $options) {
365366
365563
  close: $options.closeSplitPane,
365367
365564
  saved: $options.onSplitPaneSaved
365368
365565
  })
365369
- ], 14 /* CLASS, STYLE, PROPS */, _hoisted_59$1))
365566
+ ], 14 /* CLASS, STYLE, PROPS */, _hoisted_60$1))
365370
365567
  : vue$1.createCommentVNode("v-if", true)
365371
365568
  ], 2 /* CLASS */),
365372
365569
  ($props.notice && $props.notice.text && $options.noticeOnPage)
@@ -431370,7 +431567,7 @@ function render$o(_ctx, _cache, $props, $setup, $data, $options) {
431370
431567
  }
431371
431568
 
431372
431569
  script$o.render = render$o;
431373
- script$o.__scopeId = "data-v-9a3971e2";
431570
+ script$o.__scopeId = "data-v-2743a776";
431374
431571
  const __sfc_main$o = script$o;
431375
431572
 
431376
431573
  /**
@@ -441325,7 +441522,7 @@ function render$d(_ctx, _cache, $props, $setup, $data, $options) {
441325
441522
  }
441326
441523
 
441327
441524
  script$d.render = render$d;
441328
- script$d.__scopeId = "data-v-85a3fe56";
441525
+ script$d.__scopeId = "data-v-ebb6783e";
441329
441526
  const __sfc_main$d = script$d;
441330
441527
 
441331
441528
  let titleIdCounter = 0;