@conduction/nextcloud-vue 2.135.0 → 2.137.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 (123) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +2 -1
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +65 -50
  5. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
  6. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
  7. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +9 -0
  8. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +4 -3
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  11. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +4 -1
  12. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  13. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +61 -28
  14. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  15. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
  16. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +6 -0
  17. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  18. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js +9 -1
  19. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  20. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
  21. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
  22. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +4 -11
  23. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +32 -0
  25. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  26. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +34 -26
  27. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  28. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +24 -0
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  30. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +2 -2
  31. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  32. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  33. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  34. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +2 -1
  35. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  36. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +39 -2
  37. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  38. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +6 -5
  39. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  40. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  41. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +11 -0
  42. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  43. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +10 -2
  44. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  45. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  46. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +18 -0
  47. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  48. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +38 -23
  49. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  50. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
  51. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
  52. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js +1 -0
  53. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
  54. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
  55. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
  56. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
  57. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue.js +1 -1
  58. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js +14 -4
  59. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js.map +1 -1
  60. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js.map +1 -1
  61. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
  62. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js +10 -0
  63. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
  64. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +29 -13
  65. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
  66. package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js +3 -1
  67. package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js.map +1 -1
  68. package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue.js +1 -1
  69. package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue2.js.map +1 -1
  70. package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue3.js.map +1 -1
  71. package/dist/esm/composables/indexSources.js +69 -3
  72. package/dist/esm/composables/indexSources.js.map +1 -1
  73. package/dist/esm/l10n/en.json.js +20 -20
  74. package/dist/esm/l10n/nl.json.js +21 -21
  75. package/dist/esm/library-style.js +1 -1
  76. package/dist/esm/nextcloud-vue.css +580 -324
  77. package/dist/esm/utils/contentHeaderLink.js +7 -1
  78. package/dist/esm/utils/contentHeaderLink.js.map +1 -1
  79. package/dist/esm/utils/savedViewMenu.js +4 -1
  80. package/dist/esm/utils/savedViewMenu.js.map +1 -1
  81. package/dist/esm/utils/savedViewSummary.js +11 -4
  82. package/dist/esm/utils/savedViewSummary.js.map +1 -1
  83. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  84. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  85. package/dist/esm/utils/widgetDispatch.js +3 -1
  86. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  87. package/dist/nextcloud-vue.cjs.js +1159 -812
  88. package/dist/nextcloud-vue.cjs.js.map +2 -2
  89. package/dist/nextcloud-vue.css +580 -324
  90. package/l10n/en.json +20 -20
  91. package/l10n/nl.json +21 -21
  92. package/package.json +1 -1
  93. package/src/components/CnActionDialog/CnActionDialog.vue +45 -4
  94. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +13 -1
  95. package/src/components/CnAppNav/CnAppNav.vue +28 -3
  96. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +15 -0
  97. package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +2 -10
  98. package/src/components/CnDataTable/CnDataTable.md +1 -0
  99. package/src/components/CnDataTable/CnDataTable.vue +38 -1
  100. package/src/components/CnDetailPage/CnDetailPage.md +1 -0
  101. package/src/components/CnDetailPage/CnDetailPage.vue +26 -2
  102. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +1 -0
  103. package/src/components/CnIndexPage/CnIndexPage.vue +44 -6
  104. package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -0
  105. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +21 -0
  106. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +38 -2
  107. package/src/components/CnRegisterMapping/CnRegisterMapping.vue +7 -0
  108. package/src/components/CnRetentionWidget/CnRetentionWidget.vue +13 -0
  109. package/src/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue +14 -4
  110. package/src/components/CnTimelineWidget/CnTimelineManage.vue +23 -0
  111. package/src/components/CnTimelineWidget/dashboardRegistration.js +3 -1
  112. package/src/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue +7 -0
  113. package/src/composables/indexSources.js +69 -3
  114. package/src/css/look-board-detail.css +57 -1
  115. package/src/css/look-board-index.css +76 -1
  116. package/src/css/look-board.css +51 -4
  117. package/src/css/table.css +5 -0
  118. package/src/schemas/app-manifest-v2.schema.json +4 -2
  119. package/src/utils/contentHeaderLink.js +7 -1
  120. package/src/utils/savedViewMenu.js +4 -1
  121. package/src/utils/savedViewSummary.js +11 -4
  122. package/src/utils/validateManifestV2.compiled.js +2 -2
  123. package/src/utils/widgetDispatch.js +3 -1
@@ -53,6 +53,8 @@ function contentHeaderLink(content) {
53
53
  /**
54
54
  * The header link a widget DEFINITION declares: `headerLink` on the
55
55
  * definition itself, else what its content asks for (see contentHeaderLink).
56
+ * A view-all the widget draws under its own content
57
+ * (`viewAllPlacement: "footer"`) is not a header link.
56
58
  *
57
59
  * @param {object|null|undefined} widget A widget definition.
58
60
  * @return {{label: string, route?: string, params?: object, query?: object, href?: string}|null}
@@ -65,7 +67,11 @@ function widgetHeaderLink(widget) {
65
67
  if (declared && typeof declared === 'object' && typeof declared.label === 'string' && declared.label !== '') {
66
68
  return declared
67
69
  }
68
- return contentHeaderLink(widget.content)
70
+ const content = widget.content;
71
+ if (content && content.viewAllPlacement === 'footer' && !content.headerLink) {
72
+ return null
73
+ }
74
+ return contentHeaderLink(content)
69
75
  }
70
76
 
71
77
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"contentHeaderLink.js","sources":["../../../src/utils/contentHeaderLink.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * contentHeaderLink — the text link a widget's content asks its card header\n * to carry: `content.headerLink`, or the shorter `viewAllRoute` (with an\n * optional `viewAllLabel`) that an inbox-style widget uses for its \"View all\".\n *\n * @module utils/contentHeaderLink\n */\n\nimport { resolveDeepTokens } from './resolveFilterTokens.js'\n\n/**\n * The header link a widget's `content` declares, in the shape\n * CnWidgetWrapper's `headerLink` takes, or null when it declares none.\n * The label is left as written: the wrapper translates it.\n *\n * `viewAllRoute` is a route name, or a location `{ name, params?, query? }`.\n *\n * @param {object|null|undefined} content The widget's content.\n * @return {{label: string, route?: string, params?: object, query?: object, href?: string}|null}\n */\nexport function contentHeaderLink(content) {\n\tif (!content || typeof content !== 'object') {\n\t\treturn null\n\t}\n\tconst declared = content.headerLink\n\tif (declared && typeof declared === 'object' && typeof declared.label === 'string' && declared.label !== '') {\n\t\treturn declared\n\t}\n\tconst view = content.viewAllRoute\n\tconst name = typeof view === 'string' ? view : (view && typeof view === 'object' ? view.name : '')\n\tif (typeof name !== 'string' || name === '') {\n\t\treturn null\n\t}\n\tconst link = {\n\t\tlabel: typeof content.viewAllLabel === 'string' && content.viewAllLabel !== '' ? content.viewAllLabel : 'View all',\n\t\troute: name,\n\t}\n\tif (view && typeof view === 'object') {\n\t\tif (view.params && typeof view.params === 'object') {\n\t\t\tlink.params = view.params\n\t\t}\n\t\tif (view.query && typeof view.query === 'object') {\n\t\t\tlink.query = view.query\n\t\t}\n\t}\n\treturn link\n}\n\n/**\n * The header link a widget DEFINITION declares: `headerLink` on the\n * definition itself, else what its content asks for (see contentHeaderLink).\n *\n * @param {object|null|undefined} widget A widget definition.\n * @return {{label: string, route?: string, params?: object, query?: object, href?: string}|null}\n */\nexport function widgetHeaderLink(widget) {\n\tif (!widget || typeof widget !== 'object') {\n\t\treturn null\n\t}\n\tconst declared = widget.headerLink\n\tif (declared && typeof declared === 'object' && typeof declared.label === 'string' && declared.label !== '') {\n\t\treturn declared\n\t}\n\treturn contentHeaderLink(widget.content)\n}\n\n/**\n * How to draw a header link: the tag and its attributes. A `tab` is a\n * `#<tab>` anchor that opens that tab of the same page, a `route` a\n * `router-link` (only when a router is mounted), an `href` a plain anchor.\n * An empty tag means there is nothing usable to draw.\n *\n * @spec openspec/changes/header-link-switches-tab/specs/header-link/spec.md#requirement-a-header-link-can-open-another-tab-of-the-page\n * @param {object|null|undefined} link A link `{ label, tab?, route?, params?, query?, href? }`.\n * @param {boolean} hasRouter Whether a router is mounted.\n * @return {{tag: string, attrs: object}}\n */\nexport function headerLinkTarget(link, hasRouter) {\n\tif (!link || typeof link.label !== 'string' || link.label === '') {\n\t\treturn { tag: '', attrs: {} }\n\t}\n\tif (typeof link.tab === 'string' && link.tab !== '') {\n\t\treturn { tag: 'a', attrs: { href: `#${encodeURIComponent(link.tab)}` } }\n\t}\n\tif (link.route && hasRouter) {\n\t\tconst to = { name: link.route }\n\t\tif (link.params && typeof link.params === 'object') {\n\t\t\tto.params = link.params\n\t\t}\n\t\tif (link.query && typeof link.query === 'object') {\n\t\t\tto.query = link.query\n\t\t}\n\t\treturn { tag: 'router-link', attrs: { to } }\n\t}\n\tif (typeof link.href === 'string' && link.href !== '') {\n\t\treturn { tag: 'a', attrs: { href: link.href } }\n\t}\n\treturn { tag: '', attrs: {} }\n}\n\n/**\n * A header link with the `@objectId` and `@object.<path>` tokens in its\n * `params` and `query` resolved against the record the page shows\n * (`{ route: 'WorkflowDefinitionDetail', params: { id: '@object.workflowDefinition' } }`).\n * A link whose route params do not all resolve is no link: the record does\n * not name the page it would open.\n *\n * @param {object|null|undefined} link A link `{ label, route?, params?, query?, href? }`.\n * @param {{objectId?: (string|number), object?: object}} ctx The record.\n * @return {object|null} The link with its tokens resolved, or null.\n * @spec openspec/changes/header-link-param-tokens/specs/header-link-param-tokens/spec.md#requirement-a-header-links-route-params-read-the-record\n */\nexport function resolveHeaderLink(link, ctx) {\n\tif (!link || typeof link !== 'object') {\n\t\treturn null\n\t}\n\tif (!link.params && !link.query) {\n\t\treturn link\n\t}\n\tconst out = { ...link }\n\tif (link.params && typeof link.params === 'object') {\n\t\tout.params = resolveDeepTokens(link.params, ctx || {})\n\t\tconst filled = Object.values(out.params).every((value) => value !== null && value !== undefined && value !== '' && !(typeof value === 'string' && value.startsWith('@')))\n\t\tif (!filled) {\n\t\t\treturn null\n\t\t}\n\t}\n\tif (link.query && typeof link.query === 'object') {\n\t\tout.query = resolveDeepTokens(link.query, ctx || {})\n\t}\n\treturn out\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contentHeaderLink.js","sources":["../../../src/utils/contentHeaderLink.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * contentHeaderLink — the text link a widget's content asks its card header\n * to carry: `content.headerLink`, or the shorter `viewAllRoute` (with an\n * optional `viewAllLabel`) that an inbox-style widget uses for its \"View all\".\n *\n * @module utils/contentHeaderLink\n */\n\nimport { resolveDeepTokens } from './resolveFilterTokens.js'\n\n/**\n * The header link a widget's `content` declares, in the shape\n * CnWidgetWrapper's `headerLink` takes, or null when it declares none.\n * The label is left as written: the wrapper translates it.\n *\n * `viewAllRoute` is a route name, or a location `{ name, params?, query? }`.\n *\n * @param {object|null|undefined} content The widget's content.\n * @return {{label: string, route?: string, params?: object, query?: object, href?: string}|null}\n */\nexport function contentHeaderLink(content) {\n\tif (!content || typeof content !== 'object') {\n\t\treturn null\n\t}\n\tconst declared = content.headerLink\n\tif (declared && typeof declared === 'object' && typeof declared.label === 'string' && declared.label !== '') {\n\t\treturn declared\n\t}\n\tconst view = content.viewAllRoute\n\tconst name = typeof view === 'string' ? view : (view && typeof view === 'object' ? view.name : '')\n\tif (typeof name !== 'string' || name === '') {\n\t\treturn null\n\t}\n\tconst link = {\n\t\tlabel: typeof content.viewAllLabel === 'string' && content.viewAllLabel !== '' ? content.viewAllLabel : 'View all',\n\t\troute: name,\n\t}\n\tif (view && typeof view === 'object') {\n\t\tif (view.params && typeof view.params === 'object') {\n\t\t\tlink.params = view.params\n\t\t}\n\t\tif (view.query && typeof view.query === 'object') {\n\t\t\tlink.query = view.query\n\t\t}\n\t}\n\treturn link\n}\n\n/**\n * The header link a widget DEFINITION declares: `headerLink` on the\n * definition itself, else what its content asks for (see contentHeaderLink).\n * A view-all the widget draws under its own content\n * (`viewAllPlacement: \"footer\"`) is not a header link.\n *\n * @param {object|null|undefined} widget A widget definition.\n * @return {{label: string, route?: string, params?: object, query?: object, href?: string}|null}\n */\nexport function widgetHeaderLink(widget) {\n\tif (!widget || typeof widget !== 'object') {\n\t\treturn null\n\t}\n\tconst declared = widget.headerLink\n\tif (declared && typeof declared === 'object' && typeof declared.label === 'string' && declared.label !== '') {\n\t\treturn declared\n\t}\n\tconst content = widget.content\n\tif (content && content.viewAllPlacement === 'footer' && !content.headerLink) {\n\t\treturn null\n\t}\n\treturn contentHeaderLink(content)\n}\n\n/**\n * How to draw a header link: the tag and its attributes. A `tab` is a\n * `#<tab>` anchor that opens that tab of the same page, a `route` a\n * `router-link` (only when a router is mounted), an `href` a plain anchor.\n * An empty tag means there is nothing usable to draw.\n *\n * @spec openspec/changes/header-link-switches-tab/specs/header-link/spec.md#requirement-a-header-link-can-open-another-tab-of-the-page\n * @param {object|null|undefined} link A link `{ label, tab?, route?, params?, query?, href? }`.\n * @param {boolean} hasRouter Whether a router is mounted.\n * @return {{tag: string, attrs: object}}\n */\nexport function headerLinkTarget(link, hasRouter) {\n\tif (!link || typeof link.label !== 'string' || link.label === '') {\n\t\treturn { tag: '', attrs: {} }\n\t}\n\tif (typeof link.tab === 'string' && link.tab !== '') {\n\t\treturn { tag: 'a', attrs: { href: `#${encodeURIComponent(link.tab)}` } }\n\t}\n\tif (link.route && hasRouter) {\n\t\tconst to = { name: link.route }\n\t\tif (link.params && typeof link.params === 'object') {\n\t\t\tto.params = link.params\n\t\t}\n\t\tif (link.query && typeof link.query === 'object') {\n\t\t\tto.query = link.query\n\t\t}\n\t\treturn { tag: 'router-link', attrs: { to } }\n\t}\n\tif (typeof link.href === 'string' && link.href !== '') {\n\t\treturn { tag: 'a', attrs: { href: link.href } }\n\t}\n\treturn { tag: '', attrs: {} }\n}\n\n/**\n * A header link with the `@objectId` and `@object.<path>` tokens in its\n * `params` and `query` resolved against the record the page shows\n * (`{ route: 'WorkflowDefinitionDetail', params: { id: '@object.workflowDefinition' } }`).\n * A link whose route params do not all resolve is no link: the record does\n * not name the page it would open.\n *\n * @param {object|null|undefined} link A link `{ label, route?, params?, query?, href? }`.\n * @param {{objectId?: (string|number), object?: object}} ctx The record.\n * @return {object|null} The link with its tokens resolved, or null.\n * @spec openspec/changes/header-link-param-tokens/specs/header-link-param-tokens/spec.md#requirement-a-header-links-route-params-read-the-record\n */\nexport function resolveHeaderLink(link, ctx) {\n\tif (!link || typeof link !== 'object') {\n\t\treturn null\n\t}\n\tif (!link.params && !link.query) {\n\t\treturn link\n\t}\n\tconst out = { ...link }\n\tif (link.params && typeof link.params === 'object') {\n\t\tout.params = resolveDeepTokens(link.params, ctx || {})\n\t\tconst filled = Object.values(out.params).every((value) => value !== null && value !== undefined && value !== '' && !(typeof value === 'string' && value.startsWith('@')))\n\t\tif (!filled) {\n\t\t\treturn null\n\t\t}\n\t}\n\tif (link.query && typeof link.query === 'object') {\n\t\tout.query = resolveDeepTokens(link.query, ctx || {})\n\t}\n\treturn out\n}\n"],"names":[],"mappings":"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"}
@@ -199,6 +199,9 @@ const SAVED_VIEW_MENU_EMPTY = 'saved-views-empty';
199
199
  * An entry with a badge carries it as the menu entry's `count` (and
200
200
  * `counterVariant`), which CnAppRoot fetches like any filtered menu count.
201
201
  *
202
+ * The caption carries a pencil that opens the user settings, where the views
203
+ * in the menu are reordered, removed and added.
204
+ *
202
205
  * With `showEmpty`, an app that offers saved views shows the group also while
203
206
  * the user pinned none, with one line saying how to add one, so the group can
204
207
  * be found.
@@ -216,7 +219,7 @@ function withSavedViewMenu(menu, entries, options = {}) {
216
219
  }
217
220
  const sorted = menu.map((item, index) => ({ item, index })).sort((a, b) => byOrder(a.item, b.item) || a.index - b.index).map(({ item }) => item);
218
221
  const group = [
219
- { id: SAVED_VIEW_MENU_CAPTION, type: 'caption', label: translate('nextcloud-vue', 'My views') },
222
+ { id: SAVED_VIEW_MENU_CAPTION, type: 'caption', label: translate('nextcloud-vue', 'My views'), action: 'user-settings' },
220
223
  ...(list.length > 0
221
224
  ? list.map((e) => ({
222
225
  id: `${SAVED_VIEW_MENU_PREFIX}${e.id}`,
@@ -1 +1 @@
1
- {"version":3,"file":"savedViewMenu.js","sources":["../../../src/utils/savedViewMenu.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 Conduction B.V.\n// SPDX-License-Identifier: EUPL-1.2\n\nimport { translate as t } from '@nextcloud/l10n'\n\n/**\n * Saved views a user added to the app menu.\n *\n * Per user, in the app's preferences (`cn_saved_view_menu`), as a list of\n * `{ id, page, name, icon?, description?, badge? }`: the view id (or\n * `default:<slug>`), the route name of the index page it filters, the name\n * to show, the view's icon, its description (the entry's tooltip) and the\n * count the entry shows: the number of objects the view matches, unless its\n * `overrides.badge` is `false`. The view itself is not\n * touched, so a view shared with the user can be added like an own one, and\n * removing it from the menu never deletes it.\n *\n * A menu entry links to its page with `?savedView=<id>`; the page applies\n * that view. The entries form the \"My views\" group at the bottom of the menu.\n *\n * @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-7\n */\n\n/** The preference key the list is stored under. */\nexport const SAVED_VIEW_MENU_KEY = 'cn_saved_view_menu'\n\n/** The icon a My views entry shows when its view names none. */\nexport const SAVED_VIEW_MENU_DEFAULT_ICON = 'FilterVariant'\n\n/**\n * The icons a person can give a saved view: names from the shared semantic\n * vocabulary, so each resolves in the menu without the app registering it.\n * The menu's default comes first.\n */\nexport const SAVED_VIEW_ICONS = Object.freeze([\n\tSAVED_VIEW_MENU_DEFAULT_ICON,\n\t'ClockOutline',\n\t'ClockAlertOutline',\n\t'CalendarClockOutline',\n\t'CalendarOutline',\n\t'AccountOutline',\n\t'AccountGroupOutline',\n\t'FolderOutline',\n\t'FileDocumentOutline',\n\t'AlertCircleOutline',\n\t'CheckCircleOutline',\n\t'EmailOutline',\n\t'MapMarkerOutline',\n\t'TagOutline',\n\t'BellOutline',\n\t'ScaleBalance',\n\t'BriefcaseOutline',\n\t'EyeOutline',\n\t'LockOutline',\n\t'CurrencyEur',\n])\n\n/**\n * The icon a saved view names: a default view's own `icon`, else the one a\n * person chose, kept in the view's query (`query.icon`), else ''.\n *\n * @param {object} view The view.\n * @return {string}\n */\nexport function savedViewIcon(view) {\n\tif (view && typeof view.icon === 'string' && view.icon !== '') {\n\t\treturn view.icon\n\t}\n\tconst icon = view && view.query && view.query.icon\n\treturn typeof icon === 'string' ? icon : ''\n}\n\n/** The id of the \"My views\" caption. */\nexport const SAVED_VIEW_MENU_CAPTION = 'saved-views-caption'\n\n/** The id prefix of a menu entry made from a saved view. */\nexport const SAVED_VIEW_MENU_PREFIX = 'saved-view-'\n\n/**\n * A menu badge as stored on an entry: `{ count, counterVariant? }`, where `count` is\n * a menu entry `count` (a number or `{ register, schema, filter? }`).\n *\n * @param {unknown} badge The stored value.\n * @return {{count: (number|object), counterVariant?: string}|null} The badge, or null.\n */\nfunction normalizeBadge(badge) {\n\tif (!badge || typeof badge !== 'object') {\n\t\treturn null\n\t}\n\tconst count = badge.count\n\tconst isSource = count && typeof count === 'object' && typeof count.register === 'string' && typeof count.schema === 'string'\n\tif (!isSource && !(typeof count === 'number' && count >= 0)) {\n\t\treturn null\n\t}\n\treturn badge.counterVariant === 'attention' ? { count, counterVariant: 'attention' } : { count }\n}\n\n/**\n * The stored list, cleaned: entries with an id and a page, no repeats.\n *\n * @param {unknown} entries The stored value.\n * @return {Array<{id: string, page: string, name: string, badge?: object}>} The list.\n */\nexport function normalizeSavedViewMenu(entries) {\n\tconst seen = new Set()\n\tconst out = []\n\tfor (const e of Array.isArray(entries) ? entries : []) {\n\t\tconst id = e && (typeof e.id === 'string' || typeof e.id === 'number') ? String(e.id) : ''\n\t\tconst page = e && typeof e.page === 'string' ? e.page : ''\n\t\tif (id === '' || page === '' || seen.has(`${page}|${id}`)) {\n\t\t\tcontinue\n\t\t}\n\t\tseen.add(`${page}|${id}`)\n\t\tconst entry = { id, page, name: e && typeof e.name === 'string' && e.name !== '' ? e.name : id }\n\t\tif (typeof e.icon === 'string' && e.icon !== '') {\n\t\t\tentry.icon = e.icon\n\t\t}\n\t\tif (typeof e.description === 'string' && e.description !== '') {\n\t\t\tentry.description = e.description\n\t\t}\n\t\tconst badge = normalizeBadge(e.badge)\n\t\tif (badge) {\n\t\t\tentry.badge = badge\n\t\t}\n\t\tout.push(entry)\n\t}\n\treturn out\n}\n\n/**\n * Add an entry, or remove it when it is already there.\n *\n * @param {Array<object>} entries The current list.\n * @param {{id: string, page: string, name: string, badge?: object}} entry The view.\n * @return {Array<{id: string, page: string, name: string, badge?: object}>} The new list.\n */\nexport function toggleSavedViewMenuEntry(entries, entry) {\n\tconst list = normalizeSavedViewMenu(entries)\n\tconst id = String(entry.id)\n\tconst present = list.some((e) => e.id === id && e.page === entry.page)\n\tif (present) {\n\t\treturn list.filter((e) => !(e.id === id && e.page === entry.page))\n\t}\n\treturn normalizeSavedViewMenu([...list, { id, page: entry.page, name: entry.name, icon: entry.icon, description: entry.description, badge: entry.badge }])\n}\n\n/**\n * Bring one page's entries in line with the views that page can show:\n * current names, icons and badges, and no entry for a view that was deleted or is\n * no longer shared with the user. Other pages' entries are left alone. A\n * view's badge is read from its `menuBadge` (see `withSavedViewMenu`).\n * An entry may name its view by uuid (as an example set writes it); it is\n * matched and stored under the view's id from then on.\n *\n * @param {Array<object>} entries The current list.\n * @param {string} page The page's route name.\n * @param {Array<object>} views The views the page lists (defaults included).\n * @return {Array<{id: string, page: string, name: string}>} The new list.\n */\nexport function syncSavedViewMenu(entries, page, views) {\n\tconst list = Array.isArray(views) ? views : []\n\tconst byId = new Map(list.map((v) => [String(v.id || v.slug), v]))\n\tfor (const v of list) {\n\t\tif (v && v.uuid && !byId.has(String(v.uuid))) {\n\t\t\tbyId.set(String(v.uuid), v)\n\t\t}\n\t}\n\treturn normalizeSavedViewMenu(entries)\n\t\t.filter((e) => e.page !== page || byId.has(e.id))\n\t\t.map((e) => {\n\t\t\tif (e.page !== page) {\n\t\t\t\treturn e\n\t\t\t}\n\t\t\tconst view = byId.get(e.id)\n\t\t\tconst { badge, icon, id, description, ...rest } = e\n\t\t\trest.id = String(view.id || view.slug || id)\n\t\t\tconst next = normalizeBadge(view.menuBadge)\n\t\t\tconst nextIcon = savedViewIcon(view) || icon\n\t\t\tconst nextDescription = typeof view.description === 'string' ? view.description : description\n\t\t\treturn normalizeSavedViewMenu([{ ...rest, name: view.name || e.name, ...(nextIcon ? { icon: nextIcon } : {}), ...(nextDescription ? { description: nextDescription } : {}), ...(next ? { badge: next } : {}) }])[0]\n\t\t})\n}\n\n/** The id of the line the \"My views\" group shows while it is empty. */\nexport const SAVED_VIEW_MENU_EMPTY = 'saved-views-empty'\n\n/**\n * The manifest menu with the user's saved views in it, as the standard \"My\n * views\" group at the bottom of the menu: a caption and one entry per view,\n * after every main entry and so just above the footer entries (Help,\n * Advanced), which CnAppNav draws apart. Every app gets the same group in the\n * same place (Ruben's design rule, 19 Oct); it replaces app-specific groups\n * such as dossiq's \"My case types\".\n *\n * An entry shows its view's `icon` (a registered icon name; a case type's\n * own icon, say), else the filter icon.\n *\n * An entry with a badge carries it as the menu entry's `count` (and\n * `counterVariant`), which CnAppRoot fetches like any filtered menu count.\n *\n * With `showEmpty`, an app that offers saved views shows the group also while\n * the user pinned none, with one line saying how to add one, so the group can\n * be found.\n *\n * @param {Array<object>} menu The manifest's `menu`.\n * @param {Array<object>} entries The user's list.\n * @param {{showEmpty?: boolean}} [options] Options.\n * @return {Array<object>} A new menu, in manifest order; the given one when there is nothing to add.\n * @spec openspec/changes/my-views-menu-section/specs/app-nav/spec.md#requirement-every-app-menu-ends-with-my-views\n */\nexport function withSavedViewMenu(menu, entries, options = {}) {\n\tconst list = normalizeSavedViewMenu(entries)\n\tif (!Array.isArray(menu) || (list.length === 0 && options.showEmpty !== true)) {\n\t\treturn menu\n\t}\n\tconst sorted = menu.map((item, index) => ({ item, index })).sort((a, b) => byOrder(a.item, b.item) || a.index - b.index).map(({ item }) => item)\n\tconst group = [\n\t\t{ id: SAVED_VIEW_MENU_CAPTION, type: 'caption', label: t('nextcloud-vue', 'My views') },\n\t\t...(list.length > 0\n\t\t\t? list.map((e) => ({\n\t\t\t\t\tid: `${SAVED_VIEW_MENU_PREFIX}${e.id}`,\n\t\t\t\t\tlabel: e.name,\n\t\t\t\t\troute: e.page,\n\t\t\t\t\tquery: { savedView: e.id },\n\t\t\t\t\ticon: e.icon || SAVED_VIEW_MENU_DEFAULT_ICON,\n\t\t\t\t\t...(e.description ? { description: e.description } : {}),\n\t\t\t\t\t...(e.badge || {}),\n\t\t\t\t}))\n\t\t\t: [{ id: SAVED_VIEW_MENU_EMPTY, type: 'hint', label: t('nextcloud-vue', 'Add a view to the menu from Filters') }]),\n\t]\n\t// Orders after the last ordered entry, so CnAppNav's own sort keeps the\n\t// group at the bottom.\n\tconst orders = sorted.map((item) => item && item.order).filter((order) => typeof order === 'number')\n\tif (orders.length > 0) {\n\t\tconst start = Math.max(...orders)\n\t\tgroup.forEach((item, k) => {\n\t\t\titem.order = start + k + 1\n\t\t})\n\t}\n\treturn [...sorted, ...group]\n}\n\n/**\n * Manifest menu order: entries with an `order` first, by it; the rest keep their place.\n *\n * @param {object} a First entry.\n * @param {object} b Second entry.\n * @return {number}\n */\nfunction byOrder(a, b) {\n\tconst aHas = typeof a?.order === 'number'\n\tconst bHas = typeof b?.order === 'number'\n\tif (aHas !== bHas) {\n\t\treturn aHas ? -1 : 1\n\t}\n\treturn aHas ? a.order - b.order : 0\n}\n"],"names":["t"],"mappings":"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"}
1
+ {"version":3,"file":"savedViewMenu.js","sources":["../../../src/utils/savedViewMenu.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 Conduction B.V.\n// SPDX-License-Identifier: EUPL-1.2\n\nimport { translate as t } from '@nextcloud/l10n'\n\n/**\n * Saved views a user added to the app menu.\n *\n * Per user, in the app's preferences (`cn_saved_view_menu`), as a list of\n * `{ id, page, name, icon?, description?, badge? }`: the view id (or\n * `default:<slug>`), the route name of the index page it filters, the name\n * to show, the view's icon, its description (the entry's tooltip) and the\n * count the entry shows: the number of objects the view matches, unless its\n * `overrides.badge` is `false`. The view itself is not\n * touched, so a view shared with the user can be added like an own one, and\n * removing it from the menu never deletes it.\n *\n * A menu entry links to its page with `?savedView=<id>`; the page applies\n * that view. The entries form the \"My views\" group at the bottom of the menu.\n *\n * @spec openspec/changes/saved-views-manage-and-defaults/tasks.md#task-7\n */\n\n/** The preference key the list is stored under. */\nexport const SAVED_VIEW_MENU_KEY = 'cn_saved_view_menu'\n\n/** The icon a My views entry shows when its view names none. */\nexport const SAVED_VIEW_MENU_DEFAULT_ICON = 'FilterVariant'\n\n/**\n * The icons a person can give a saved view: names from the shared semantic\n * vocabulary, so each resolves in the menu without the app registering it.\n * The menu's default comes first.\n */\nexport const SAVED_VIEW_ICONS = Object.freeze([\n\tSAVED_VIEW_MENU_DEFAULT_ICON,\n\t'ClockOutline',\n\t'ClockAlertOutline',\n\t'CalendarClockOutline',\n\t'CalendarOutline',\n\t'AccountOutline',\n\t'AccountGroupOutline',\n\t'FolderOutline',\n\t'FileDocumentOutline',\n\t'AlertCircleOutline',\n\t'CheckCircleOutline',\n\t'EmailOutline',\n\t'MapMarkerOutline',\n\t'TagOutline',\n\t'BellOutline',\n\t'ScaleBalance',\n\t'BriefcaseOutline',\n\t'EyeOutline',\n\t'LockOutline',\n\t'CurrencyEur',\n])\n\n/**\n * The icon a saved view names: a default view's own `icon`, else the one a\n * person chose, kept in the view's query (`query.icon`), else ''.\n *\n * @param {object} view The view.\n * @return {string}\n */\nexport function savedViewIcon(view) {\n\tif (view && typeof view.icon === 'string' && view.icon !== '') {\n\t\treturn view.icon\n\t}\n\tconst icon = view && view.query && view.query.icon\n\treturn typeof icon === 'string' ? icon : ''\n}\n\n/** The id of the \"My views\" caption. */\nexport const SAVED_VIEW_MENU_CAPTION = 'saved-views-caption'\n\n/** The id prefix of a menu entry made from a saved view. */\nexport const SAVED_VIEW_MENU_PREFIX = 'saved-view-'\n\n/**\n * A menu badge as stored on an entry: `{ count, counterVariant? }`, where `count` is\n * a menu entry `count` (a number or `{ register, schema, filter? }`).\n *\n * @param {unknown} badge The stored value.\n * @return {{count: (number|object), counterVariant?: string}|null} The badge, or null.\n */\nfunction normalizeBadge(badge) {\n\tif (!badge || typeof badge !== 'object') {\n\t\treturn null\n\t}\n\tconst count = badge.count\n\tconst isSource = count && typeof count === 'object' && typeof count.register === 'string' && typeof count.schema === 'string'\n\tif (!isSource && !(typeof count === 'number' && count >= 0)) {\n\t\treturn null\n\t}\n\treturn badge.counterVariant === 'attention' ? { count, counterVariant: 'attention' } : { count }\n}\n\n/**\n * The stored list, cleaned: entries with an id and a page, no repeats.\n *\n * @param {unknown} entries The stored value.\n * @return {Array<{id: string, page: string, name: string, badge?: object}>} The list.\n */\nexport function normalizeSavedViewMenu(entries) {\n\tconst seen = new Set()\n\tconst out = []\n\tfor (const e of Array.isArray(entries) ? entries : []) {\n\t\tconst id = e && (typeof e.id === 'string' || typeof e.id === 'number') ? String(e.id) : ''\n\t\tconst page = e && typeof e.page === 'string' ? e.page : ''\n\t\tif (id === '' || page === '' || seen.has(`${page}|${id}`)) {\n\t\t\tcontinue\n\t\t}\n\t\tseen.add(`${page}|${id}`)\n\t\tconst entry = { id, page, name: e && typeof e.name === 'string' && e.name !== '' ? e.name : id }\n\t\tif (typeof e.icon === 'string' && e.icon !== '') {\n\t\t\tentry.icon = e.icon\n\t\t}\n\t\tif (typeof e.description === 'string' && e.description !== '') {\n\t\t\tentry.description = e.description\n\t\t}\n\t\tconst badge = normalizeBadge(e.badge)\n\t\tif (badge) {\n\t\t\tentry.badge = badge\n\t\t}\n\t\tout.push(entry)\n\t}\n\treturn out\n}\n\n/**\n * Add an entry, or remove it when it is already there.\n *\n * @param {Array<object>} entries The current list.\n * @param {{id: string, page: string, name: string, badge?: object}} entry The view.\n * @return {Array<{id: string, page: string, name: string, badge?: object}>} The new list.\n */\nexport function toggleSavedViewMenuEntry(entries, entry) {\n\tconst list = normalizeSavedViewMenu(entries)\n\tconst id = String(entry.id)\n\tconst present = list.some((e) => e.id === id && e.page === entry.page)\n\tif (present) {\n\t\treturn list.filter((e) => !(e.id === id && e.page === entry.page))\n\t}\n\treturn normalizeSavedViewMenu([...list, { id, page: entry.page, name: entry.name, icon: entry.icon, description: entry.description, badge: entry.badge }])\n}\n\n/**\n * Bring one page's entries in line with the views that page can show:\n * current names, icons and badges, and no entry for a view that was deleted or is\n * no longer shared with the user. Other pages' entries are left alone. A\n * view's badge is read from its `menuBadge` (see `withSavedViewMenu`).\n * An entry may name its view by uuid (as an example set writes it); it is\n * matched and stored under the view's id from then on.\n *\n * @param {Array<object>} entries The current list.\n * @param {string} page The page's route name.\n * @param {Array<object>} views The views the page lists (defaults included).\n * @return {Array<{id: string, page: string, name: string}>} The new list.\n */\nexport function syncSavedViewMenu(entries, page, views) {\n\tconst list = Array.isArray(views) ? views : []\n\tconst byId = new Map(list.map((v) => [String(v.id || v.slug), v]))\n\tfor (const v of list) {\n\t\tif (v && v.uuid && !byId.has(String(v.uuid))) {\n\t\t\tbyId.set(String(v.uuid), v)\n\t\t}\n\t}\n\treturn normalizeSavedViewMenu(entries)\n\t\t.filter((e) => e.page !== page || byId.has(e.id))\n\t\t.map((e) => {\n\t\t\tif (e.page !== page) {\n\t\t\t\treturn e\n\t\t\t}\n\t\t\tconst view = byId.get(e.id)\n\t\t\tconst { badge, icon, id, description, ...rest } = e\n\t\t\trest.id = String(view.id || view.slug || id)\n\t\t\tconst next = normalizeBadge(view.menuBadge)\n\t\t\tconst nextIcon = savedViewIcon(view) || icon\n\t\t\tconst nextDescription = typeof view.description === 'string' ? view.description : description\n\t\t\treturn normalizeSavedViewMenu([{ ...rest, name: view.name || e.name, ...(nextIcon ? { icon: nextIcon } : {}), ...(nextDescription ? { description: nextDescription } : {}), ...(next ? { badge: next } : {}) }])[0]\n\t\t})\n}\n\n/** The id of the line the \"My views\" group shows while it is empty. */\nexport const SAVED_VIEW_MENU_EMPTY = 'saved-views-empty'\n\n/**\n * The manifest menu with the user's saved views in it, as the standard \"My\n * views\" group at the bottom of the menu: a caption and one entry per view,\n * after every main entry and so just above the footer entries (Help,\n * Advanced), which CnAppNav draws apart. Every app gets the same group in the\n * same place (Ruben's design rule, 19 Oct); it replaces app-specific groups\n * such as dossiq's \"My case types\".\n *\n * An entry shows its view's `icon` (a registered icon name; a case type's\n * own icon, say), else the filter icon.\n *\n * An entry with a badge carries it as the menu entry's `count` (and\n * `counterVariant`), which CnAppRoot fetches like any filtered menu count.\n *\n * The caption carries a pencil that opens the user settings, where the views\n * in the menu are reordered, removed and added.\n *\n * With `showEmpty`, an app that offers saved views shows the group also while\n * the user pinned none, with one line saying how to add one, so the group can\n * be found.\n *\n * @param {Array<object>} menu The manifest's `menu`.\n * @param {Array<object>} entries The user's list.\n * @param {{showEmpty?: boolean}} [options] Options.\n * @return {Array<object>} A new menu, in manifest order; the given one when there is nothing to add.\n * @spec openspec/changes/my-views-menu-section/specs/app-nav/spec.md#requirement-every-app-menu-ends-with-my-views\n */\nexport function withSavedViewMenu(menu, entries, options = {}) {\n\tconst list = normalizeSavedViewMenu(entries)\n\tif (!Array.isArray(menu) || (list.length === 0 && options.showEmpty !== true)) {\n\t\treturn menu\n\t}\n\tconst sorted = menu.map((item, index) => ({ item, index })).sort((a, b) => byOrder(a.item, b.item) || a.index - b.index).map(({ item }) => item)\n\tconst group = [\n\t\t{ id: SAVED_VIEW_MENU_CAPTION, type: 'caption', label: t('nextcloud-vue', 'My views'), action: 'user-settings' },\n\t\t...(list.length > 0\n\t\t\t? list.map((e) => ({\n\t\t\t\t\tid: `${SAVED_VIEW_MENU_PREFIX}${e.id}`,\n\t\t\t\t\tlabel: e.name,\n\t\t\t\t\troute: e.page,\n\t\t\t\t\tquery: { savedView: e.id },\n\t\t\t\t\ticon: e.icon || SAVED_VIEW_MENU_DEFAULT_ICON,\n\t\t\t\t\t...(e.description ? { description: e.description } : {}),\n\t\t\t\t\t...(e.badge || {}),\n\t\t\t\t}))\n\t\t\t: [{ id: SAVED_VIEW_MENU_EMPTY, type: 'hint', label: t('nextcloud-vue', 'Add a view to the menu from Filters') }]),\n\t]\n\t// Orders after the last ordered entry, so CnAppNav's own sort keeps the\n\t// group at the bottom.\n\tconst orders = sorted.map((item) => item && item.order).filter((order) => typeof order === 'number')\n\tif (orders.length > 0) {\n\t\tconst start = Math.max(...orders)\n\t\tgroup.forEach((item, k) => {\n\t\t\titem.order = start + k + 1\n\t\t})\n\t}\n\treturn [...sorted, ...group]\n}\n\n/**\n * Manifest menu order: entries with an `order` first, by it; the rest keep their place.\n *\n * @param {object} a First entry.\n * @param {object} b Second entry.\n * @return {number}\n */\nfunction byOrder(a, b) {\n\tconst aHas = typeof a?.order === 'number'\n\tconst bHas = typeof b?.order === 'number'\n\tif (aHas !== bHas) {\n\t\treturn aHas ? -1 : 1\n\t}\n\treturn aHas ? a.order - b.order : 0\n}\n"],"names":["t"],"mappings":"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"}
@@ -70,17 +70,23 @@ function summarizeViewFilters(state, options = {}) {
70
70
 
71
71
  /**
72
72
  * The ids a view's filters hold per reference property, for a label lookup.
73
+ * A filter on a value that identifies a record without being its id (a case
74
+ * type's `identifier`) is a reference too when the page's `filterLabels`
75
+ * entry names it: `reference: { register?, schema, matchField, labelField }`.
73
76
  *
74
77
  * @param {{filters?: object}} state The view's state.
75
78
  * @param {Array<object>} fields The page schema's fields (`fieldsFromSchema`).
76
- * @return {Array<{key: string, register: string, schema: string, labelField: string, ids: Array<string>}>} One entry per reference filter.
79
+ * @param {{[key: string]: {reference?: object}}} [filterLabels] The page's `config.filterLabels`.
80
+ * @return {Array<{key: string, register: string, schema: string, labelField: string, matchField?: string, ids: Array<string>}>} One entry per reference filter.
81
+ * @spec openspec/changes/saved-view-summary-match-field-labels/specs/saved-view-menu-settings/spec.md#requirement-a-filter-on-a-records-identifier-reads-as-the-records-name
77
82
  */
78
- function viewFilterReferences(state, fields) {
83
+ function viewFilterReferences(state, fields, filterLabels = {}) {
79
84
  const filters = (state && state.filters && typeof state.filters === 'object') ? state.filters : {};
80
85
  const out = [];
81
86
  for (const [key, raw] of Object.entries(filters)) {
82
87
  const field = (Array.isArray(fields) ? fields : []).find((f) => f && f.key === key);
83
- const ref = field && field.reference;
88
+ const named = filterLabels && filterLabels[key] && filterLabels[key].reference && typeof filterLabels[key].reference === 'object' ? filterLabels[key].reference : null;
89
+ const ref = (field && field.reference) || named;
84
90
  if (!ref || ref.schema === undefined || ref.schema === null) {
85
91
  continue
86
92
  }
@@ -88,7 +94,8 @@ function viewFilterReferences(state, fields) {
88
94
  .filter((id) => (typeof id === 'string' || typeof id === 'number') && id !== '' && id !== MISSING_VALUE)
89
95
  .map(String);
90
96
  if (ids.length > 0) {
91
- out.push({ key, register: ref.register || '', schema: String(ref.schema), labelField: ref.labelField || '', ids });
97
+ const matchField = ref === named && typeof ref.matchField === 'string' && ref.matchField !== '' ? { matchField: ref.matchField } : {};
98
+ out.push({ key, register: ref.register || '', schema: String(ref.schema), labelField: ref.labelField || '', ...matchField, ids });
92
99
  }
93
100
  }
94
101
  return out
@@ -1 +1 @@
1
- {"version":3,"file":"savedViewSummary.js","sources":["../../../src/utils/savedViewSummary.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 Conduction B.V.\n// SPDX-License-Identifier: EUPL-1.2\n\nimport { translate as t } from '@nextcloud/l10n'\nimport { MISSING_VALUE } from './facets.js'\n\n/**\n * A saved view's filters as one readable line: \"Case type Woo request,\n * status open\". Each filter is its field's title and its values' display\n * names, in the order the view stores them; the line is in sentence case, so\n * every field title after the first starts in lower case.\n *\n * A filter is named as the page's Active line names it: the page's\n * `filterLabels` entry first (its `label` for the field, its `values` per\n * value), then the schema. A filter whose `filterLabels` entry says\n * `hidden: true` is left out: a working-list rule such as \"not a draft\" that\n * every view carries is not what tells one view from another.\n *\n * A value's display name comes from, in order: the page's `filterLabels`\n * values, `valueLabels` (the names the caller looked up, such as the title of\n * a referenced record or a facet bucket's label), the property's `oneOf`\n * titles, its `x-enum-labels`, yes or no for a boolean, and else the value\n * itself. A range shows as \"from\" and \"up to\"; a search term as `\"term\"`.\n *\n * @param {{filters?: object, search?: string}} state The view's state (see `extractViewState`).\n * @param {object} [options] Options.\n * @param {object} [options.properties] The page schema's `properties`.\n * @param {{[key: string]: {[value: string]: string}}} [options.valueLabels] Display names per filter key and value.\n * @param {{[key: string]: {label?: string, values?: object, hidden?: boolean}}} [options.filterLabels] The page's `config.filterLabels`.\n * @param {(text: string) => string} [options.translate] The app's translate, for titles and labels the schema declares.\n * @return {string} The line, or '' for a view without filters or search.\n * @spec openspec/changes/saved-view-summary-reads-like-the-chips/specs/saved-view-menu-settings/spec.md\n * @spec openspec/changes/saved-view-menu-settings/specs/saved-view-menu-settings/spec.md#requirement-a-menu-entry-says-what-its-view-shows-and-how-many\n */\nexport function summarizeViewFilters(state, options = {}) {\n\tconst properties = (options.properties && typeof options.properties === 'object') ? options.properties : {}\n\tconst valueLabels = (options.valueLabels && typeof options.valueLabels === 'object') ? options.valueLabels : {}\n\tconst filterLabels = (options.filterLabels && typeof options.filterLabels === 'object') ? options.filterLabels : {}\n\tconst tr = typeof options.translate === 'function' ? options.translate : (text) => text\n\tconst filters = (state && state.filters && typeof state.filters === 'object') ? state.filters : {}\n\tconst parts = []\n\tfor (const [key, raw] of Object.entries(filters)) {\n\t\tconst named = (filterLabels[key] && typeof filterLabels[key] === 'object') ? filterLabels[key] : {}\n\t\tif (named.hidden === true) {\n\t\t\tcontinue\n\t\t}\n\t\tconst prop = properties[key] || {}\n\t\tconst namedValues = (named.values && typeof named.values === 'object') ? named.values : {}\n\t\tconst values = (Array.isArray(raw) ? raw : [raw])\n\t\t\t.filter((value) => value !== undefined && value !== '')\n\t\t\t.map((value) => (typeof namedValues[String(value)] === 'string' && namedValues[String(value)] !== ''\n\t\t\t\t? tr(namedValues[String(value)])\n\t\t\t\t: valueText(value, prop, valueLabels[key] || {}, tr)))\n\t\t\t.filter((text) => text !== '')\n\t\tif (values.length === 0) {\n\t\t\tcontinue\n\t\t}\n\t\tconst title = typeof named.label === 'string' && named.label !== ''\n\t\t\t? named.label\n\t\t\t: (typeof prop.title === 'string' && prop.title !== '' ? prop.title : key)\n\t\tconst field = tr(title)\n\t\tparts.push(`${field} ${values.join(` ${t('nextcloud-vue', 'or')} `)}`)\n\t}\n\tif (state && typeof state.search === 'string' && state.search.trim() !== '') {\n\t\tparts.push(`\"${state.search.trim()}\"`)\n\t}\n\treturn parts.map((part, index) => (index === 0 ? part : lowerFirst(part))).join(', ')\n}\n\n/**\n * The ids a view's filters hold per reference property, for a label lookup.\n *\n * @param {{filters?: object}} state The view's state.\n * @param {Array<object>} fields The page schema's fields (`fieldsFromSchema`).\n * @return {Array<{key: string, register: string, schema: string, labelField: string, ids: Array<string>}>} One entry per reference filter.\n */\nexport function viewFilterReferences(state, fields) {\n\tconst filters = (state && state.filters && typeof state.filters === 'object') ? state.filters : {}\n\tconst out = []\n\tfor (const [key, raw] of Object.entries(filters)) {\n\t\tconst field = (Array.isArray(fields) ? fields : []).find((f) => f && f.key === key)\n\t\tconst ref = field && field.reference\n\t\tif (!ref || ref.schema === undefined || ref.schema === null) {\n\t\t\tcontinue\n\t\t}\n\t\tconst ids = (Array.isArray(raw) ? raw : [raw])\n\t\t\t.filter((id) => (typeof id === 'string' || typeof id === 'number') && id !== '' && id !== MISSING_VALUE)\n\t\t\t.map(String)\n\t\tif (ids.length > 0) {\n\t\t\tout.push({ key, register: ref.register || '', schema: String(ref.schema), labelField: ref.labelField || '', ids })\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * One value's display name.\n *\n * @param {unknown} value The stored value.\n * @param {object} prop The property.\n * @param {{[value: string]: string}} labels Looked-up names for this key.\n * @param {(text: string) => string} tr The app's translate.\n * @return {string}\n */\nfunction valueText(value, prop, labels, tr) {\n\tif (value === null || value === MISSING_VALUE) {\n\t\treturn t('nextcloud-vue', 'no value')\n\t}\n\tif (typeof value === 'boolean' || value === 'true' || value === 'false') {\n\t\treturn (value === true || value === 'true') ? t('nextcloud-vue', 'yes') : t('nextcloud-vue', 'no')\n\t}\n\tif (typeof value === 'object') {\n\t\treturn Object.entries(value)\n\t\t\t.map(([op, operand]) => {\n\t\t\t\tif (op === 'gte' || op === 'gt') {\n\t\t\t\t\treturn t('nextcloud-vue', 'from {value}', { value: String(operand) })\n\t\t\t\t}\n\t\t\t\tif (op === 'lte' || op === 'lt') {\n\t\t\t\t\treturn t('nextcloud-vue', 'up to {value}', { value: String(operand) })\n\t\t\t\t}\n\t\t\t\treturn `${op} ${String(operand)}`\n\t\t\t})\n\t\t\t.join(' ')\n\t}\n\tconst id = String(value)\n\tif (typeof labels[id] === 'string' && labels[id] !== '') {\n\t\treturn labels[id]\n\t}\n\tconst option = (Array.isArray(prop.oneOf) ? prop.oneOf : []).find((o) => o && String(o.const) === id && typeof o.title === 'string')\n\tif (option) {\n\t\treturn tr(option.title)\n\t}\n\tconst enumLabels = prop['x-enum-labels']\n\tif (enumLabels && typeof enumLabels === 'object' && typeof enumLabels[id] === 'string') {\n\t\treturn tr(enumLabels[id])\n\t}\n\treturn id\n}\n\n/**\n * The text with its first letter in lower case, unless the first word is in\n * capitals (an abbreviation such as \"BSN\").\n *\n * @param {string} text The text.\n * @return {string}\n */\nfunction lowerFirst(text) {\n\tconst word = text.split(' ')[0]\n\tif (word.length > 1 && word === word.toUpperCase()) {\n\t\treturn text\n\t}\n\treturn text.charAt(0).toLowerCase() + text.slice(1)\n}\n\n/**\n * What a view holds, as sentences: its filters and search term\n * (`summarizeViewFilters`), then its sort, \"Sorted by deadline, descending.\"\n * The saved-view edit dialog shows it under each criteria choice\n * (DqFilterBewerken).\n *\n * @param {{filters?: object, search?: string, sortKeys?: Array<{key: string, order: string}>, sortKey?: string, sortOrder?: string}} state The view's state.\n * @param {object} [options] As for `summarizeViewFilters`.\n * @return {string} The sentences, or '' for a view with no filters, search or sort.\n * @spec openspec/changes/saved-view-edit-board-form/specs/saved-views/spec.md\n */\nexport function viewCriteriaSummary(state, options = {}) {\n\tconst properties = (options.properties && typeof options.properties === 'object') ? options.properties : {}\n\tconst tr = typeof options.translate === 'function' ? options.translate : (text) => text\n\tconst sentences = []\n\tconst filters = summarizeViewFilters(state, options)\n\tif (filters !== '') {\n\t\tsentences.push(`${filters}.`)\n\t}\n\tconst keys = state && Array.isArray(state.sortKeys) && state.sortKeys.length > 0\n\t\t? state.sortKeys\n\t\t: (state && state.sortKey ? [{ key: state.sortKey, order: state.sortOrder }] : [])\n\tconst first = keys.find((entry) => entry && typeof entry.key === 'string' && entry.key !== '')\n\tif (first) {\n\t\tconst prop = properties[first.key] || {}\n\t\tconst field = lowerFirst(tr(typeof prop.title === 'string' && prop.title !== '' ? prop.title : first.key))\n\t\tconst direction = first.order === 'desc' ? t('nextcloud-vue', 'descending') : t('nextcloud-vue', 'ascending')\n\t\tsentences.push(t('nextcloud-vue', 'Sorted by {field}, {direction}.', { field, direction }))\n\t}\n\treturn sentences.join(' ')\n}\n"],"names":["t"],"mappings":"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"}
1
+ {"version":3,"file":"savedViewSummary.js","sources":["../../../src/utils/savedViewSummary.js"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 Conduction B.V.\n// SPDX-License-Identifier: EUPL-1.2\n\nimport { translate as t } from '@nextcloud/l10n'\nimport { MISSING_VALUE } from './facets.js'\n\n/**\n * A saved view's filters as one readable line: \"Case type Woo request,\n * status open\". Each filter is its field's title and its values' display\n * names, in the order the view stores them; the line is in sentence case, so\n * every field title after the first starts in lower case.\n *\n * A filter is named as the page's Active line names it: the page's\n * `filterLabels` entry first (its `label` for the field, its `values` per\n * value), then the schema. A filter whose `filterLabels` entry says\n * `hidden: true` is left out: a working-list rule such as \"not a draft\" that\n * every view carries is not what tells one view from another.\n *\n * A value's display name comes from, in order: the page's `filterLabels`\n * values, `valueLabels` (the names the caller looked up, such as the title of\n * a referenced record or a facet bucket's label), the property's `oneOf`\n * titles, its `x-enum-labels`, yes or no for a boolean, and else the value\n * itself. A range shows as \"from\" and \"up to\"; a search term as `\"term\"`.\n *\n * @param {{filters?: object, search?: string}} state The view's state (see `extractViewState`).\n * @param {object} [options] Options.\n * @param {object} [options.properties] The page schema's `properties`.\n * @param {{[key: string]: {[value: string]: string}}} [options.valueLabels] Display names per filter key and value.\n * @param {{[key: string]: {label?: string, values?: object, hidden?: boolean}}} [options.filterLabels] The page's `config.filterLabels`.\n * @param {(text: string) => string} [options.translate] The app's translate, for titles and labels the schema declares.\n * @return {string} The line, or '' for a view without filters or search.\n * @spec openspec/changes/saved-view-summary-reads-like-the-chips/specs/saved-view-menu-settings/spec.md\n * @spec openspec/changes/saved-view-menu-settings/specs/saved-view-menu-settings/spec.md#requirement-a-menu-entry-says-what-its-view-shows-and-how-many\n */\nexport function summarizeViewFilters(state, options = {}) {\n\tconst properties = (options.properties && typeof options.properties === 'object') ? options.properties : {}\n\tconst valueLabels = (options.valueLabels && typeof options.valueLabels === 'object') ? options.valueLabels : {}\n\tconst filterLabels = (options.filterLabels && typeof options.filterLabels === 'object') ? options.filterLabels : {}\n\tconst tr = typeof options.translate === 'function' ? options.translate : (text) => text\n\tconst filters = (state && state.filters && typeof state.filters === 'object') ? state.filters : {}\n\tconst parts = []\n\tfor (const [key, raw] of Object.entries(filters)) {\n\t\tconst named = (filterLabels[key] && typeof filterLabels[key] === 'object') ? filterLabels[key] : {}\n\t\tif (named.hidden === true) {\n\t\t\tcontinue\n\t\t}\n\t\tconst prop = properties[key] || {}\n\t\tconst namedValues = (named.values && typeof named.values === 'object') ? named.values : {}\n\t\tconst values = (Array.isArray(raw) ? raw : [raw])\n\t\t\t.filter((value) => value !== undefined && value !== '')\n\t\t\t.map((value) => (typeof namedValues[String(value)] === 'string' && namedValues[String(value)] !== ''\n\t\t\t\t? tr(namedValues[String(value)])\n\t\t\t\t: valueText(value, prop, valueLabels[key] || {}, tr)))\n\t\t\t.filter((text) => text !== '')\n\t\tif (values.length === 0) {\n\t\t\tcontinue\n\t\t}\n\t\tconst title = typeof named.label === 'string' && named.label !== ''\n\t\t\t? named.label\n\t\t\t: (typeof prop.title === 'string' && prop.title !== '' ? prop.title : key)\n\t\tconst field = tr(title)\n\t\tparts.push(`${field} ${values.join(` ${t('nextcloud-vue', 'or')} `)}`)\n\t}\n\tif (state && typeof state.search === 'string' && state.search.trim() !== '') {\n\t\tparts.push(`\"${state.search.trim()}\"`)\n\t}\n\treturn parts.map((part, index) => (index === 0 ? part : lowerFirst(part))).join(', ')\n}\n\n/**\n * The ids a view's filters hold per reference property, for a label lookup.\n * A filter on a value that identifies a record without being its id (a case\n * type's `identifier`) is a reference too when the page's `filterLabels`\n * entry names it: `reference: { register?, schema, matchField, labelField }`.\n *\n * @param {{filters?: object}} state The view's state.\n * @param {Array<object>} fields The page schema's fields (`fieldsFromSchema`).\n * @param {{[key: string]: {reference?: object}}} [filterLabels] The page's `config.filterLabels`.\n * @return {Array<{key: string, register: string, schema: string, labelField: string, matchField?: string, ids: Array<string>}>} One entry per reference filter.\n * @spec openspec/changes/saved-view-summary-match-field-labels/specs/saved-view-menu-settings/spec.md#requirement-a-filter-on-a-records-identifier-reads-as-the-records-name\n */\nexport function viewFilterReferences(state, fields, filterLabels = {}) {\n\tconst filters = (state && state.filters && typeof state.filters === 'object') ? state.filters : {}\n\tconst out = []\n\tfor (const [key, raw] of Object.entries(filters)) {\n\t\tconst field = (Array.isArray(fields) ? fields : []).find((f) => f && f.key === key)\n\t\tconst named = filterLabels && filterLabels[key] && filterLabels[key].reference && typeof filterLabels[key].reference === 'object' ? filterLabels[key].reference : null\n\t\tconst ref = (field && field.reference) || named\n\t\tif (!ref || ref.schema === undefined || ref.schema === null) {\n\t\t\tcontinue\n\t\t}\n\t\tconst ids = (Array.isArray(raw) ? raw : [raw])\n\t\t\t.filter((id) => (typeof id === 'string' || typeof id === 'number') && id !== '' && id !== MISSING_VALUE)\n\t\t\t.map(String)\n\t\tif (ids.length > 0) {\n\t\t\tconst matchField = ref === named && typeof ref.matchField === 'string' && ref.matchField !== '' ? { matchField: ref.matchField } : {}\n\t\t\tout.push({ key, register: ref.register || '', schema: String(ref.schema), labelField: ref.labelField || '', ...matchField, ids })\n\t\t}\n\t}\n\treturn out\n}\n\n/**\n * One value's display name.\n *\n * @param {unknown} value The stored value.\n * @param {object} prop The property.\n * @param {{[value: string]: string}} labels Looked-up names for this key.\n * @param {(text: string) => string} tr The app's translate.\n * @return {string}\n */\nfunction valueText(value, prop, labels, tr) {\n\tif (value === null || value === MISSING_VALUE) {\n\t\treturn t('nextcloud-vue', 'no value')\n\t}\n\tif (typeof value === 'boolean' || value === 'true' || value === 'false') {\n\t\treturn (value === true || value === 'true') ? t('nextcloud-vue', 'yes') : t('nextcloud-vue', 'no')\n\t}\n\tif (typeof value === 'object') {\n\t\treturn Object.entries(value)\n\t\t\t.map(([op, operand]) => {\n\t\t\t\tif (op === 'gte' || op === 'gt') {\n\t\t\t\t\treturn t('nextcloud-vue', 'from {value}', { value: String(operand) })\n\t\t\t\t}\n\t\t\t\tif (op === 'lte' || op === 'lt') {\n\t\t\t\t\treturn t('nextcloud-vue', 'up to {value}', { value: String(operand) })\n\t\t\t\t}\n\t\t\t\treturn `${op} ${String(operand)}`\n\t\t\t})\n\t\t\t.join(' ')\n\t}\n\tconst id = String(value)\n\tif (typeof labels[id] === 'string' && labels[id] !== '') {\n\t\treturn labels[id]\n\t}\n\tconst option = (Array.isArray(prop.oneOf) ? prop.oneOf : []).find((o) => o && String(o.const) === id && typeof o.title === 'string')\n\tif (option) {\n\t\treturn tr(option.title)\n\t}\n\tconst enumLabels = prop['x-enum-labels']\n\tif (enumLabels && typeof enumLabels === 'object' && typeof enumLabels[id] === 'string') {\n\t\treturn tr(enumLabels[id])\n\t}\n\treturn id\n}\n\n/**\n * The text with its first letter in lower case, unless the first word is in\n * capitals (an abbreviation such as \"BSN\").\n *\n * @param {string} text The text.\n * @return {string}\n */\nfunction lowerFirst(text) {\n\tconst word = text.split(' ')[0]\n\tif (word.length > 1 && word === word.toUpperCase()) {\n\t\treturn text\n\t}\n\treturn text.charAt(0).toLowerCase() + text.slice(1)\n}\n\n/**\n * What a view holds, as sentences: its filters and search term\n * (`summarizeViewFilters`), then its sort, \"Sorted by deadline, descending.\"\n * The saved-view edit dialog shows it under each criteria choice\n * (DqFilterBewerken).\n *\n * @param {{filters?: object, search?: string, sortKeys?: Array<{key: string, order: string}>, sortKey?: string, sortOrder?: string}} state The view's state.\n * @param {object} [options] As for `summarizeViewFilters`.\n * @return {string} The sentences, or '' for a view with no filters, search or sort.\n * @spec openspec/changes/saved-view-edit-board-form/specs/saved-views/spec.md\n */\nexport function viewCriteriaSummary(state, options = {}) {\n\tconst properties = (options.properties && typeof options.properties === 'object') ? options.properties : {}\n\tconst tr = typeof options.translate === 'function' ? options.translate : (text) => text\n\tconst sentences = []\n\tconst filters = summarizeViewFilters(state, options)\n\tif (filters !== '') {\n\t\tsentences.push(`${filters}.`)\n\t}\n\tconst keys = state && Array.isArray(state.sortKeys) && state.sortKeys.length > 0\n\t\t? state.sortKeys\n\t\t: (state && state.sortKey ? [{ key: state.sortKey, order: state.sortOrder }] : [])\n\tconst first = keys.find((entry) => entry && typeof entry.key === 'string' && entry.key !== '')\n\tif (first) {\n\t\tconst prop = properties[first.key] || {}\n\t\tconst field = lowerFirst(tr(typeof prop.title === 'string' && prop.title !== '' ? prop.title : first.key))\n\t\tconst direction = first.order === 'desc' ? t('nextcloud-vue', 'descending') : t('nextcloud-vue', 'ascending')\n\t\tsentences.push(t('nextcloud-vue', 'Sorted by {field}, {direction}.', { field, direction }))\n\t}\n\treturn sentences.join(' ')\n}\n"],"names":["t"],"mappings":"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"}