@conduction/nextcloud-vue 2.105.0 → 2.106.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 (153) hide show
  1. package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
  2. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +18 -0
  3. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  4. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +3 -1
  5. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  6. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
  7. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +18 -0
  8. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  9. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +1 -1
  10. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  11. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +53 -4
  12. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  13. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  14. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +9 -0
  15. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js.map +1 -0
  16. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js +24 -0
  17. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -0
  18. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js +49 -0
  19. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -0
  20. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  21. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +36 -18
  22. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +17 -38
  24. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  25. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
  26. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  27. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  28. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  29. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +53 -2
  30. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  31. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +119 -111
  32. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  33. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
  34. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +62 -1
  35. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  36. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  37. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +159 -50
  38. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  39. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +121 -98
  40. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  41. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
  42. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +24 -0
  43. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
  44. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +20 -4
  45. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
  46. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +22 -4
  47. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  48. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +112 -1
  49. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  50. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +100 -44
  51. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  52. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
  53. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +67 -4
  54. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
  55. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +1 -1
  56. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
  57. package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
  58. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +295 -12
  59. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  60. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +267 -144
  61. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  62. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
  63. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +4 -0
  64. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  65. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +3 -1
  66. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  67. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  68. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +93 -1
  69. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  70. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +322 -246
  71. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  72. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue.js +1 -1
  73. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +122 -7
  74. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
  75. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js +189 -93
  76. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
  77. package/dist/esm/components/CnTabs/CnTabs.vue.js +1 -1
  78. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  79. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  80. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  81. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +42 -0
  82. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  83. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +38 -19
  84. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  85. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js +9 -0
  86. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js.map +1 -0
  87. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js +258 -0
  88. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js.map +1 -0
  89. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js +69 -0
  90. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js.map +1 -0
  91. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
  92. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  93. package/dist/esm/index.js +1 -0
  94. package/dist/esm/index.js.map +1 -1
  95. package/dist/esm/l10n/en.json.js +21 -1
  96. package/dist/esm/l10n/en.json.js.map +1 -1
  97. package/dist/esm/l10n/nl.json.js +21 -1
  98. package/dist/esm/l10n/nl.json.js.map +1 -1
  99. package/dist/esm/library-style.js +1 -1
  100. package/dist/esm/nextcloud-vue.css +803 -453
  101. package/dist/esm/utils/dueText.js +18 -3
  102. package/dist/esm/utils/dueText.js.map +1 -1
  103. package/dist/esm/utils/libraryWidgetKeys.js +1 -0
  104. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  105. package/dist/esm/utils/sortOrder.js +11 -1
  106. package/dist/esm/utils/sortOrder.js.map +1 -1
  107. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  108. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  109. package/dist/nextcloud-vue.cjs.js +8281 -6350
  110. package/dist/nextcloud-vue.cjs.js.map +2 -2
  111. package/dist/nextcloud-vue.css +803 -453
  112. package/l10n/en.json +21 -1
  113. package/l10n/nl.json +21 -1
  114. package/package.json +1 -1
  115. package/src/components/CnCardGrid/CnCardGrid.md +2 -0
  116. package/src/components/CnCardGrid/CnCardGrid.vue +20 -0
  117. package/src/components/CnCellRenderer/CnCellRenderer.vue +19 -1
  118. package/src/components/CnDetailPage/CnDetailPage.md +2 -2
  119. package/src/components/CnDetailPage/CnDetailPage.vue +53 -4
  120. package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +60 -0
  121. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +36 -29
  122. package/src/components/CnFactsWidget/CnFactsWidget.vue +4 -0
  123. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +70 -4
  124. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +62 -1
  125. package/src/components/CnIndexPage/CnIndexPage.md +7 -5
  126. package/src/components/CnIndexPage/CnIndexPage.vue +187 -58
  127. package/src/components/CnIndexPage/CnIndexPageWidgets.vue +36 -1
  128. package/src/components/CnIndexPage/useSelfFetchList.js +22 -4
  129. package/src/components/CnIndexSidebar/CnIndexSidebar.md +2 -0
  130. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +148 -1
  131. package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +68 -5
  132. package/src/components/CnObjectCard/CnObjectCard.md +1 -0
  133. package/src/components/CnObjectCard/CnObjectCard.vue +354 -13
  134. package/src/components/CnObjectSidebar/CnFilesTab.vue +6 -0
  135. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +190 -4
  136. package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +209 -9
  137. package/src/components/CnTabs/CnTabs.vue +11 -0
  138. package/src/components/CnTabsWidget/CnTabsWidget.vue +91 -18
  139. package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.md +11 -0
  140. package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue +382 -0
  141. package/src/components/CnTeamWorkloadWidget/index.js +14 -0
  142. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
  143. package/src/components/index.js +1 -0
  144. package/src/css/index-page.css +14 -2
  145. package/src/css/look-board-detail.css +48 -4
  146. package/src/css/look-board-index.css +64 -2
  147. package/src/css/look-board.css +25 -2
  148. package/src/index.js +1 -1
  149. package/src/schemas/app-manifest-v2.schema.json +75 -6
  150. package/src/utils/dueText.js +18 -3
  151. package/src/utils/libraryWidgetKeys.js +1 -0
  152. package/src/utils/sortOrder.js +10 -0
  153. package/src/utils/validateManifestV2.compiled.js +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"CnIndexSidebar.vue3.js","sources":["../../../../src/components/CnIndexSidebar/CnIndexSidebar.vue?vue&type=template&id=0899fc58&lang.js"],"sourcesContent":["<template>\n\t<NcAppSidebar\n\t\tv-model:open=\"internalOpen\"\n\t\t:name=\"resolvedName\"\n\t\t:title=\"resolvedName\"\n\t\t:subname=\"resolvedSubname\"\n\t\t:active=\"internalActiveTab\"\n\t\t:compact=\"!!resolvedIcon\"\n\t\t@close=\"$emit('update:open', false)\"\n\t\t@update:active=\"onTabChange\">\n\t\t<!-- Schema icon in sidebar header -->\n\t\t<template v-if=\"resolvedIcon\" #header>\n\t\t\t<div class=\"cn-index-sidebar__header-icon\">\n\t\t\t\t<CnIcon :name=\"resolvedIcon\" :size=\"32\" />\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- Search Tab -->\n\t\t<NcAppSidebarTab\n\t\t\tid=\"search-tab\"\n\t\t\t:name=\"searchTabLabel\"\n\t\t\t:order=\"1\">\n\t\t\t<template #icon>\n\t\t\t\t<FilterOutline :size=\"20\" />\n\t\t\t</template>\n\n\t\t\t<div class=\"cn-index-sidebar__tab-content\">\n\t\t\t\t<div v-if=\"$slots['search-above']\" class=\"cn-index-sidebar__section\">\n\t\t\t\t\t<slot name=\"search-above\" />\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"cn-index-sidebar__section\">\n\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t:modelValue=\"searchValue || ''\"\n\t\t\t\t\t\t:placeholder=\"searchPlaceholder\"\n\t\t\t\t\t\t:label=\"searchLabel\"\n\t\t\t\t\t\t@update:modelValue=\"$emit('search', $event)\" />\n\t\t\t\t</div>\n\n\t\t\t\t<div v-if=\"hasActiveFilters\" class=\"cn-index-sidebar__section\">\n\t\t\t\t\t<NcButton variant=\"tertiary\" @click=\"onClearAll\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<FilterRemoveOutline :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ clearAllLabel }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\n\t\t\t\t<div v-if=\"schemaFilters.length > 0\" class=\"cn-index-sidebar__section\">\n\t\t\t\t\t<h3>{{ filtersLabel }}</h3>\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-for=\"filter in schemaFilters\"\n\t\t\t\t\t\t:key=\"filter.key\"\n\t\t\t\t\t\tclass=\"cn-index-sidebar__filter-group\">\n\t\t\t\t\t\t<div class=\"cn-index-sidebar__filter-header\">\n\t\t\t\t\t\t\t<span class=\"cn-index-sidebar__filter-label\">{{ filter.label }}</span>\n\t\t\t\t\t\t\t<NcPopover v-if=\"filter.description\" popupRole=\"dialog\">\n\t\t\t\t\t\t\t\t<template #trigger>\n\t\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\t\t\t\t\t\t:aria-label=\"filter.label + ' info'\"\n\t\t\t\t\t\t\t\t\t\tclass=\"cn-index-sidebar__info-btn\">\n\t\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t\t<InformationOutline :size=\"16\" />\n\t\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<p class=\"cn-index-sidebar__filter-description\">\n\t\t\t\t\t\t\t\t\t{{ filter.description }}\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</NcPopover>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- A window, not a list of values: two bounds and a\n\t\t\t\t\t\t preset, emitted as the `{ from, to }` the range\n\t\t\t\t\t\t filters upstream are already spelled in. -->\n\t\t\t\t\t\t<CnDateRangePicker\n\t\t\t\t\t\t\tv-if=\"filter.type === 'date-range'\"\n\t\t\t\t\t\t\tclass=\"cn-index-sidebar__date-range\"\n\t\t\t\t\t\t\t:modelValue=\"getRangeValue(filter)\"\n\t\t\t\t\t\t\t:presets=\"filter.presets || rangePresets\"\n\t\t\t\t\t\t\t:fromLabel=\"filter.fromLabel || fromLabel\"\n\t\t\t\t\t\t\t:toLabel=\"filter.toLabel || toLabel\"\n\t\t\t\t\t\t\t:presetLabel=\"filter.label\"\n\t\t\t\t\t\t\t@update:modelValue=\"onRangeChange(filter.key, $event)\" />\n\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\tv-else-if=\"filter.type === 'text'\"\n\t\t\t\t\t\t\tclass=\"cn-index-sidebar__filter-text\"\n\t\t\t\t\t\t\t:modelValue=\"getTextValue(filter)\"\n\t\t\t\t\t\t\t:label=\"filter.label\"\n\t\t\t\t\t\t\t:placeholder=\"filter.label\"\n\t\t\t\t\t\t\t@update:modelValue=\"onTextChange(filter.key, $event)\" />\n\t\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\tclass=\"cn-index-sidebar__select\"\n\t\t\t\t\t\t\t:modelValue=\"getSelectedFilterOptions(filter)\"\n\t\t\t\t\t\t\t:options=\"getFilterOptions(filter)\"\n\t\t\t\t\t\t\t:loading=\"isLoadingOptions(filter)\"\n\t\t\t\t\t\t\tplaceholder=\"Select...\"\n\t\t\t\t\t\t\t:inputLabel=\"filter.label\"\n\t\t\t\t\t\t\t:multiple=\"filter.multiple !== false\"\n\t\t\t\t\t\t\t:keepOpen=\"filter.multiple !== false\"\n\t\t\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\t\t\t@update:modelValue=\"onFilterChange(filter.key, $event)\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t<slot name=\"search-extra\" />\n\t\t\t</div>\n\t\t</NcAppSidebarTab>\n\n\t\t<!-- Columns Tab -->\n\t\t<NcAppSidebarTab\n\t\t\tid=\"columns-tab\"\n\t\t\t:name=\"columnsTabLabel\"\n\t\t\t:order=\"2\">\n\t\t\t<template #icon>\n\t\t\t\t<ViewColumnOutline :size=\"20\" />\n\t\t\t</template>\n\n\t\t\t<div class=\"cn-index-sidebar__tab-content\">\n\t\t\t\t<div class=\"cn-sidebar-columns\">\n\t\t\t\t\t<h3>{{ columnsHeading }}</h3>\n\t\t\t\t\t<p class=\"cn-sidebar-columns__description\">\n\t\t\t\t\t\t{{ columnsDescription }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<!-- Order and pin the visible columns. Drag and the Move buttons\n\t\t\t\t\t call the same method (moveColumn); the table header is not a drag target. -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-if=\"personalColumns && orderedVisible.length > 0\"\n\t\t\t\t\t\tclass=\"cn-sidebar-columns__order\"\n\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-order\">\n\t\t\t\t\t\t<h4>{{ t('nextcloud-vue', 'Order and pin') }}</h4>\n\t\t\t\t\t\t<ol class=\"cn-sidebar-columns__order-list\">\n\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\tv-for=\"(item, index) in orderedVisible\"\n\t\t\t\t\t\t\t\t:key=\"item.key\"\n\t\t\t\t\t\t\t\tclass=\"cn-sidebar-columns__order-item\"\n\t\t\t\t\t\t\t\t:class=\"{ 'cn-sidebar-columns__order-item--pinned': index < pinnedCount }\"\n\t\t\t\t\t\t\t\tdraggable=\"true\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-order-item\"\n\t\t\t\t\t\t\t\t@dragstart=\"dragFrom = index\"\n\t\t\t\t\t\t\t\t@dragover.prevent\n\t\t\t\t\t\t\t\t@drop.prevent=\"onDropColumn(index)\">\n\t\t\t\t\t\t\t\t<DragVertical :size=\"18\" class=\"cn-sidebar-columns__handle\" aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t<span class=\"cn-sidebar-columns__order-label\">{{ item.label }}</span>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\t\t:disabled=\"index === 0 || index === pinnedCount\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Move {column} up', { column: item.label })\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-up\"\n\t\t\t\t\t\t\t\t\t@click=\"moveColumn(index, index - 1)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<ChevronUp :size=\"18\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\t\t:disabled=\"index === orderedVisible.length - 1 || index === pinnedCount - 1\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Move {column} down', { column: item.label })\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-down\"\n\t\t\t\t\t\t\t\t\t@click=\"moveColumn(index, index + 1)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<ChevronDown :size=\"18\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\t\t:aria-pressed=\"String(index < pinnedCount)\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"index < pinnedCount ? t('nextcloud-vue', 'Unpin {column}', { column: item.label }) : t('nextcloud-vue', 'Pin {column}', { column: item.label })\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-pin\"\n\t\t\t\t\t\t\t\t\t@click=\"togglePin(index)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<Pin v-if=\"index < pinnedCount\" :size=\"18\" />\n\t\t\t\t\t\t\t\t\t\t<PinOutline v-else :size=\"18\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ol>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-reset\"\n\t\t\t\t\t\t\t@click=\"$emit('columns-reset')\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Reset columns') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<template v-if=\"allColumns.length > 0 || allGroups.length > 0\">\n\t\t\t\t\t\t<!-- Schema properties group (collapsible) -->\n\t\t\t\t\t\t<div v-if=\"allColumns.length > 0\" class=\"cn-sidebar-columns__group cn-sidebar-columns__group--collapsible\">\n\t\t\t\t\t\t\t<div class=\"cn-sidebar-columns__group-header\" @click=\"propertiesExpanded = !propertiesExpanded\">\n\t\t\t\t\t\t\t\t<ChevronDown v-if=\"propertiesExpanded\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<ChevronRight v-else :size=\"20\" />\n\t\t\t\t\t\t\t\t<h4>{{ resolvedPropertiesLabel }}</h4>\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\t:modelValue=\"isGroupAllVisible(allColumns)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-sidebar-columns__select-all\"\n\t\t\t\t\t\t\t\t\t@click.stop\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"toggleGroupAll(allColumns)\">\n\t\t\t\t\t\t\t\t\tAll\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div v-if=\"propertiesExpanded\" class=\"cn-sidebar-columns__group-content\">\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\tv-for=\"col in allColumns\"\n\t\t\t\t\t\t\t\t\t:key=\"col.key\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"isColumnVisible(col.key)\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"toggleColumn(col.key)\">\n\t\t\t\t\t\t\t\t\t{{ col.label }}\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t<!-- Extra column groups (built-in Metadata + external) -->\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tv-for=\"group in allGroups\"\n\t\t\t\t\t\t\t:key=\"group.id\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-columns__group cn-sidebar-columns__group--collapsible\">\n\t\t\t\t\t\t\t<div class=\"cn-sidebar-columns__group-header\" @click=\"toggleGroup(group.id)\">\n\t\t\t\t\t\t\t\t<ChevronDown v-if=\"expandedGroups[group.id]\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<ChevronRight v-else :size=\"20\" />\n\t\t\t\t\t\t\t\t<h4 :lang=\"langOf(group.label)\">\n\t\t\t\t\t\t\t\t\t{{ shown(group.label) }}\n\t\t\t\t\t\t\t\t</h4>\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\t:modelValue=\"isGroupAllVisible(group.columns)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-sidebar-columns__select-all\"\n\t\t\t\t\t\t\t\t\t@click.stop\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"toggleGroupAll(group.columns)\">\n\t\t\t\t\t\t\t\t\tAll\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div v-if=\"expandedGroups[group.id]\" class=\"cn-sidebar-columns__group-content\">\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\tv-for=\"col in group.columns\"\n\t\t\t\t\t\t\t\t\t:key=\"col.key\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"isColumnVisible(col.key)\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"toggleColumn(col.key)\">\n\t\t\t\t\t\t\t\t\t{{ shown(col.label) }}\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</template>\n\n\t\t\t\t\t<p v-else class=\"cn-sidebar-columns__empty\">\n\t\t\t\t\t\tNo columns available. Provide a schema to auto-generate columns.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\n\t\t\t\t<slot name=\"columns-extra\" />\n\t\t\t</div>\n\t\t</NcAppSidebarTab>\n\n\t\t<!-- Extra tabs injected by the consumer -->\n\t\t<slot name=\"tabs\" />\n\t</NcAppSidebar>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAppSidebar, NcAppSidebarTab, NcButton, NcCheckboxRadioSwitch, NcPopover, NcSelect, NcTextField } from '@nextcloud/vue'\nimport ChevronDown from 'vue-material-design-icons/ChevronDown.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport ChevronUp from 'vue-material-design-icons/ChevronUp.vue'\nimport DragVertical from 'vue-material-design-icons/DragVertical.vue'\nimport FilterOutline from 'vue-material-design-icons/FilterOutline.vue'\nimport FilterRemoveOutline from 'vue-material-design-icons/FilterRemoveOutline.vue'\nimport InformationOutline from 'vue-material-design-icons/InformationOutline.vue'\nimport Pin from 'vue-material-design-icons/Pin.vue'\nimport PinOutline from 'vue-material-design-icons/PinOutline.vue'\nimport ViewColumnOutline from 'vue-material-design-icons/ViewColumnOutline.vue'\nimport { METADATA_COLUMNS } from '../../constants/metadata.js'\nimport { facetOptions } from '../../utils/facets.js'\nimport { labelLang } from '../../utils/manifestTranslate.js'\nimport { columnsFromSchema, filtersFromSchema } from '../../utils/schema.js'\nimport { CnDateRangePicker, DEFAULT_DATE_RANGE_PRESETS } from '../CnDateRangePicker/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\n\n/**\n * CnIndexSidebar — Reusable NcAppSidebar wrapper with Search + Columns tabs.\n *\n * Designed to be schema-driven: pass a schema and the sidebar auto-generates\n * search filters, column visibility controls, and the standard Metadata group.\n * Title and properties group label are derived from schema.title by default.\n *\n * Must be rendered at the App.vue level as a sibling of NcAppContent.\n * Use provide/inject to connect it to page components.\n *\n * @slot search-above - Content rendered above the search field in the Search tab (e.g. hints, quick actions).\n * @slot search-extra - Content rendered below the search field and filters in the Search tab (e.g. saved searches).\n */\nexport default {\n\tname: 'CnIndexSidebar',\n\n\tcomponents: {\n\t\tNcAppSidebar,\n\t\tNcAppSidebarTab,\n\t\tNcTextField,\n\t\tNcSelect,\n\t\tCnDateRangePicker,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcPopover,\n\t\tNcButton,\n\t\tCnIcon,\n\t\tFilterOutline,\n\t\tFilterRemoveOutline,\n\t\tViewColumnOutline,\n\t\tChevronDown,\n\t\tChevronRight,\n\t\tChevronUp,\n\t\tDragVertical,\n\t\tPin,\n\t\tPinOutline,\n\t\tInformationOutline,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Consumer translation function, provided by CnAppRoot as\n\t\t * `cnTranslate: this.translate` (bound to the host app's id). Column and\n\t\t * filter labels come from schema property titles, authored in English as\n\t\t * the canonical source; the visible label is resolved through this\n\t\t * function so it follows the user's language. Defaults to identity when\n\t\t * used standalone (no CnAppRoot ancestor).\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Sidebar title. Defaults to schema.title when not set. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** MDI icon name or emoji. Defaults to schema.icon when not set. */\n\t\ticon: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Schema object for auto-generating filters, columns, and labels */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Array of currently visible column keys */\n\t\tvisibleColumns: {\n\t\t\ttype: Array,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Show the Order and pin controls in the Columns tab, and Reset columns.\n\t\t * Off keeps show and hide only.\n\t\t */\n\t\tpersonalColumns: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** How many of the first visible columns are pinned to the start of the table. */\n\t\tpinnedCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\n\t\t/** Current search term */\n\t\tsearchValue: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether sidebar is open */\n\t\topen: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Current active facet filters: { fieldName: [values] } */\n\t\tactiveFilters: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Live facet data from the API: `{ fieldName: { values: [{ value, count?, label? }] } }` */\n\t\tfacetData: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Additional column groups beyond schema properties and the built-in Metadata.\n\t\t * Each group: { id: string, label: string, columns: Array<{key, label}>, expanded?: boolean }\n\t\t */\n\t\tcolumnGroups: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether to include the built-in Metadata column group */\n\t\tshowMetadata: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Search input placeholder */\n\t\tsearchPlaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Type to search…'),\n\t\t},\n\n\t\t/** Search tab label */\n\t\tsearchTabLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Search'),\n\t\t},\n\n\t\t/** Columns tab label */\n\t\tcolumnsTabLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Columns'),\n\t\t},\n\n\t\t/** Search section heading */\n\t\tsearchLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Search'),\n\t\t},\n\n\t\t/** Filters section heading */\n\t\tfiltersLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Filters'),\n\t\t},\n\n\t\t/** \"Clear all\" button label, shown when search or a filter is active */\n\t\tclearAllLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Clear all'),\n\t\t},\n\n\t\t/**\n\t\t * Filter declarations for a page with no schema of its own: `{ name: declaration }`, the same shape a schema property has. Wins over `schema`, and feeds the Search tab only.\n\t\t *\n\t\t * 🔑 A FILTER IS NOT A COLUMN, which is the whole reason this is its\n\t\t * own prop rather than a synthetic `schema`. The schema feeds BOTH\n\t\t * tabs, so a page that declared its filters there would also offer\n\t\t * them in the Columns tab: the toggle would tick and no column would\n\t\t * appear, because the table's columns come from somewhere else\n\t\t * entirely. These reach the Search tab and nothing else.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tfilterFields: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Start-of-window label on a date-range filter. */\n\t\tfromLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'From'),\n\t\t},\n\n\t\t/** End-of-window label on a date-range filter. */\n\t\ttoLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'To'),\n\t\t},\n\n\t\t/** Columns section heading */\n\t\tcolumnsHeading: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Column visibility'),\n\t\t},\n\n\t\t/** Columns section description */\n\t\tcolumnsDescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Select which columns to display in the table'),\n\t\t},\n\n\t\t/** Override label for the schema properties group. Defaults to schema.title. */\n\t\tpropertiesGroupLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * ID of the tab that should be active when the sidebar opens.\n\t\t * Built-in IDs are 'search-tab' and 'columns-tab'.\n\t\t * Use the id you set on your custom NcAppSidebarTab for custom tabs.\n\t\t */\n\t\tdefaultTab: {\n\t\t\ttype: String,\n\t\t\tdefault: 'search-tab',\n\t\t},\n\n\t\t/**\n\t\t * Whether the current user is an admin.\n\t\t * When false, schema properties with `adminOnly: true` are hidden from filters.\n\t\t */\n\t\tuserIsAdmin: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t},\n\n\temits: ['clear-filters', 'columns-change', 'columns-reorder', 'columns-reset', 'pin-change', 'filter-change', 'search', 'tab-change', 'update:open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tinternalOpen: this.open,\n\t\t\tinternalActiveTab: this.defaultTab,\n\t\t\t/** Index of the column being dragged in the Order and pin list, or -1. */\n\t\t\tdragFrom: -1,\n\t\t\tpropertiesExpanded: true,\n\t\t\texpandedGroups: {},\n\t\t\t/**\n\t\t\t * Options loaded for a `reference` filter, keyed by field.\n\t\t\t *\n\t\t\t * A reference picker lists rows from ANOTHER list (the cases a\n\t\t\t * task can hang off, say), and neither the schema nor a facet\n\t\t\t * bucket carries them. Loaded once per field and cached, because\n\t\t\t * the sidebar re-renders on every keystroke in the search box.\n\t\t\t *\n\t\t\t * @type {Record<string, Array<{id: string, label: string}>>}\n\t\t\t */\n\t\t\treferenceOptions: {},\n\t\t\t/** @type {Record<string, boolean>} Which reference loads are in flight. */\n\t\t\treferenceLoading: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** Resolved icon — explicit prop overrides schema.icon */\n\t\tresolvedIcon() {\n\t\t\treturn this.icon || this.schema?.icon || ''\n\t\t},\n\n\t\t/** Sidebar name — schema title, shown as the h2 header */\n\t\tresolvedName() {\n\t\t\tif (this.title) {\n\t\t\t\treturn this.shown(this.title)\n\t\t\t}\n\t\t\treturn this.schema?.title || 'Search'\n\t\t},\n\n\t\t/** Sidebar subname — schema description, shown below the name */\n\t\tresolvedSubname() {\n\t\t\treturn this.schema?.description || ''\n\t\t},\n\n\t\t/** Properties group label — derived from schema.title if not explicitly set */\n\t\tresolvedPropertiesLabel() {\n\t\t\tif (this.propertiesGroupLabel) {\n\t\t\t\treturn this.propertiesGroupLabel\n\t\t\t}\n\t\t\treturn this.schema?.title || 'Properties'\n\t\t},\n\n\t\t/** All available columns from schema */\n\t\tallColumns() {\n\t\t\tif (!this.schema) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn columnsFromSchema(this.schema, { translate: this.cnTranslate })\n\t\t},\n\n\t\t/** Filter definitions from schema (facetable properties, respecting RBAC) */\n\t\tschemaFilters() {\n\t\t\t// An explicitly declared filter set wins: it is the page saying\n\t\t\t// \"these are the questions\", where a schema only says \"these are\n\t\t\t// the properties\" and the sidebar has to guess which of them are\n\t\t\t// worth asking about.\n\t\t\tif (this.filterFields && Object.keys(this.filterFields).length > 0) {\n\t\t\t\treturn filtersFromSchema(\n\t\t\t\t\t{ properties: this.filterFields },\n\t\t\t\t\t{ isAdmin: this.userIsAdmin, translate: this.cnTranslate },\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (!this.schema) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn filtersFromSchema(this.schema, { isAdmin: this.userIsAdmin, translate: this.cnTranslate })\n\t\t},\n\n\t\t/** Whether a search term or any facet filter is currently active. */\n\t\thasActiveFilters() {\n\t\t\tif ((this.searchValue || '').length > 0) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn Object.values(this.activeFilters || {}).some((v) => (Array.isArray(v) ? v.length > 0 : !!v))\n\t\t},\n\n\t\t/** Combined column groups: built-in Metadata + external groups */\n\t\tallGroups() {\n\t\t\tconst groups = []\n\t\t\tif (this.showMetadata && this.schema) {\n\t\t\t\tgroups.push({\n\t\t\t\t\tid: 'metadata',\n\t\t\t\t\tlabel: 'Metadata',\n\t\t\t\t\tcolumns: METADATA_COLUMNS,\n\t\t\t\t\texpanded: true,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn [...groups, ...this.columnGroups]\n\t\t},\n\n\t\t/** Label of each column key, from the schema properties and the groups. */\n\t\tcolumnLabels() {\n\t\t\tconst map = {}\n\t\t\tthis.allColumns.forEach((c) => {\n\t\t\t\tmap[c.key] = c.label\n\t\t\t})\n\t\t\tthis.allGroups.forEach((g) => g.columns.forEach((c) => {\n\t\t\t\tmap[c.key] = c.label\n\t\t\t}))\n\t\t\treturn map\n\t\t},\n\n\t\t/** The visible columns in their order, with labels (all columns when none were chosen). */\n\t\torderedVisible() {\n\t\t\tconst keys = this.visibleColumns === null ? this.allColumnKeys : this.visibleColumns\n\t\t\treturn keys.filter((k) => this.columnLabels[k] !== undefined).map((key) => ({ key, label: this.columnLabels[key] }))\n\t\t},\n\n\t\t/** All column keys across schema properties and all groups */\n\t\tallColumnKeys() {\n\t\t\treturn [\n\t\t\t\t...this.allColumns.map((c) => c.key),\n\t\t\t\t...this.allGroups.flatMap((g) => g.columns.map((c) => c.key)),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * The presets a date-range filter offers when it declares none.\n\t\t *\n\t\t * Just `custom`. Every shipped preset rolls BACKWARDS from today\n\t\t * (\"Last 30 days\"), and a sidebar filter is as often a forward window\n\t\t * (\"due next week\") as a backward one. Offering a preset that answers\n\t\t * the wrong direction is worse than offering none: it is one click and\n\t\t * it looks deliberate.\n\t\t *\n\t\t * @return {Array<object>} The preset list.\n\t\t */\n\t\trangePresets() {\n\t\t\t// Taken FROM the picker's own list rather than written out again, so\n\t\t\t// the one preset a filter offers carries the same id and the same\n\t\t\t// label as everywhere else it appears.\n\t\t\treturn DEFAULT_DATE_RANGE_PRESETS\n\t\t\t\t.filter((preset) => preset.id === 'custom')\n\t\t\t\t.map((preset) => ({ ...preset }))\n\t\t},\n\t},\n\n\twatch: {\n\t\topen(val) {\n\t\t\tthis.internalOpen = val\n\t\t},\n\n\t\tinternalOpen(val) {\n\t\t\tthis.$emit('update:open', val)\n\t\t},\n\n\t\tdefaultTab(val) {\n\t\t\tthis.internalActiveTab = val\n\t\t},\n\n\t\tallGroups: {\n\t\t\timmediate: true,\n\t\t\thandler(groups) {\n\t\t\t\tfor (const group of groups) {\n\t\t\t\t\tif (!(group.id in this.expandedGroups)) {\n\t\t\t\t\t\tthis.expandedGroups[group.id] = group.expanded !== false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\t// A reference picker's rows load once the schema naming them arrives,\n\t\t// which on a manifest page is after mount. Watching the FILTERS rather\n\t\t// than calling from `mounted()` covers both orders.\n\t\tschemaFilters: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.loadReferenceOptions()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\n\t\t/**\n\t\t * A manifest label through the injected lookup, or as written.\n\t\t *\n\t\t * @param {string} text The label as written.\n\t\t * @return {string} The label in the user's language.\n\t\t */\n\t\tshown(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' && typeof text === 'string' && text !== '' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The `lang` of a label that fell back to its written text in another language.\n\t\t *\n\t\t * @param {string} text The label as written.\n\t\t * @return {string|undefined} The source language, or undefined.\n\t\t */\n\t\tlangOf(text) {\n\t\t\treturn labelLang(this.cnTranslate, text) || undefined\n\t\t},\n\n\t\t/**\n\t\t * Handle tab change from NcAppSidebar\n\t\t *\n\t\t * @param {string} tabId Tab identifier\n\t\t */\n\t\tonTabChange(tabId) {\n\t\t\tthis.internalActiveTab = tabId\n\t\t\tthis.$emit('tab-change', tabId)\n\t\t},\n\n\t\t/**\n\t\t * Check if a column is currently visible\n\t\t *\n\t\t * @param {string} key Column key\n\t\t */\n\t\tisColumnVisible(key) {\n\t\t\tif (this.visibleColumns === null) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn this.visibleColumns.includes(key)\n\t\t},\n\n\t\t/**\n\t\t * Check if all columns in a group are visible\n\t\t *\n\t\t * @param {string[]} columns Array of column keys\n\t\t */\n\t\tisGroupAllVisible(columns) {\n\t\t\treturn columns.every((col) => this.isColumnVisible(col.key))\n\t\t},\n\n\t\t/**\n\t\t * Toggle a single column's visibility\n\t\t *\n\t\t * @param {string} key Column key\n\t\t */\n\t\ttoggleColumn(key) {\n\t\t\tlet newVisible\n\t\t\tif (this.visibleColumns === null) {\n\t\t\t\tnewVisible = this.allColumnKeys.filter((k) => k !== key)\n\t\t\t} else if (this.isColumnVisible(key)) {\n\t\t\t\tnewVisible = this.visibleColumns.filter((k) => k !== key)\n\t\t\t} else {\n\t\t\t\tnewVisible = [...this.visibleColumns, key]\n\t\t\t}\n\t\t\tthis.$emit('columns-change', newVisible)\n\t\t},\n\n\t\t/**\n\t\t * Select or deselect all columns in a group\n\t\t *\n\t\t * @param {string[]} columns Array of column keys\n\t\t */\n\t\ttoggleGroupAll(columns) {\n\t\t\tconst groupKeys = columns.map((c) => c.key)\n\t\t\tconst allVisible = this.isGroupAllVisible(columns)\n\n\t\t\tlet newVisible\n\t\t\tif (this.visibleColumns === null) {\n\t\t\t\t// Currently all visible — deselect this group\n\t\t\t\tnewVisible = this.allColumnKeys.filter((k) => !groupKeys.includes(k))\n\t\t\t} else if (allVisible) {\n\t\t\t\t// All in group visible — deselect them\n\t\t\t\tnewVisible = this.visibleColumns.filter((k) => !groupKeys.includes(k))\n\t\t\t} else {\n\t\t\t\t// Not all visible — select them all\n\t\t\t\tconst current = new Set(this.visibleColumns)\n\t\t\t\tgroupKeys.forEach((k) => current.add(k))\n\t\t\t\tnewVisible = [...current]\n\t\t\t}\n\t\t\tthis.$emit('columns-change', newVisible)\n\t\t},\n\n\t\t/**\n\t\t * Move a visible column to another place in the order. The drag and the\n\t\t * Move buttons both call this. A column stays inside its block: pinned\n\t\t * columns move among the pinned, the rest among the rest.\n\t\t *\n\t\t * @param {number} from Current index.\n\t\t * @param {number} to Target index.\n\t\t * @return {void}\n\t\t */\n\t\tmoveColumn(from, to) {\n\t\t\tconst list = this.orderedVisible.map((c) => c.key)\n\t\t\tconst lo = from < this.pinnedCount ? 0 : this.pinnedCount\n\t\t\tconst hi = from < this.pinnedCount ? this.pinnedCount - 1 : list.length - 1\n\t\t\tconst target = Math.min(hi, Math.max(lo, to))\n\t\t\tif (from < 0 || from >= list.length || target === from) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [moved] = list.splice(from, 1)\n\t\t\tlist.splice(target, 0, moved)\n\t\t\t/**\n\t\t\t * @event columns-reorder Emitted when the user moves a column. Payload: the visible column keys in their new order.\n\t\t\t * @type {string[]}\n\t\t\t */\n\t\t\tthis.$emit('columns-reorder', list)\n\t\t},\n\n\t\t/**\n\t\t * Dropping a dragged column on another row.\n\t\t *\n\t\t * @param {number} index Index of the row it was dropped on.\n\t\t * @return {void}\n\t\t */\n\t\tonDropColumn(index) {\n\t\t\tconst from = this.dragFrom\n\t\t\tthis.dragFrom = -1\n\t\t\tif (from >= 0) {\n\t\t\t\tthis.moveColumn(from, index)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Pin a column (it joins the pinned block at the start) or unpin it (it\n\t\t * leaves that block, to the first place after it).\n\t\t *\n\t\t * @param {number} index Index of the column.\n\t\t * @return {void}\n\t\t */\n\t\ttogglePin(index) {\n\t\t\tconst list = this.orderedVisible.map((c) => c.key)\n\t\t\tconst [moved] = list.splice(index, 1)\n\t\t\tlet count = this.pinnedCount\n\t\t\tif (index < count) {\n\t\t\t\tcount -= 1\n\t\t\t\tlist.splice(count, 0, moved)\n\t\t\t} else {\n\t\t\t\tlist.splice(count, 0, moved)\n\t\t\t\tcount += 1\n\t\t\t}\n\t\t\tthis.$emit('columns-reorder', list)\n\t\t\t/**\n\t\t\t * @event pin-change Emitted when a column is pinned or unpinned. Payload: the new number of pinned columns.\n\t\t\t * @type {number}\n\t\t\t */\n\t\t\tthis.$emit('pin-change', count)\n\t\t},\n\n\t\t/**\n\t\t * Toggle a group's expanded state\n\t\t *\n\t\t * @param {string} groupId Filter group identifier\n\t\t */\n\t\ttoggleGroup(groupId) {\n\t\t\tthis.expandedGroups[groupId] = !this.expandedGroups[groupId]\n\t\t},\n\n\t\t/**\n\t\t * Get filter options for a filter definition\n\t\t *\n\t\t * @param {object} filter Filter object\n\t\t */\n\t\tgetFilterOptions(filter) {\n\t\t\tconst live = facetOptions(\n\t\t\t\tthis.facetData[filter.key],\n\t\t\t\t(count) => t('nextcloud-vue', 'No value ({count})', { count }),\n\t\t\t)\n\t\t\tif (live !== null) {\n\t\t\t\treturn live\n\t\t\t}\n\t\t\t// A reference picker's rows come from another list, and neither a\n\t\t\t// schema enum nor a facet bucket can carry them.\n\t\t\tif (filter.type === 'reference') {\n\t\t\t\treturn this.referenceOptions[filter.key] || []\n\t\t\t}\n\t\t\treturn filter.options || []\n\t\t},\n\n\t\t/**\n\t\t * Whether a reference filter is still fetching its rows.\n\t\t *\n\t\t * Shown rather than hidden: an empty picker that is still loading and\n\t\t * one that genuinely has nothing to pick look identical, and only one\n\t\t * of them means the person should stop waiting.\n\t\t *\n\t\t * @param {object} filter The filter definition.\n\t\t *\n\t\t * @return {boolean} True while the load is in flight.\n\t\t */\n\t\tisLoadingOptions(filter) {\n\t\t\treturn this.referenceLoading[filter.key] === true\n\t\t},\n\n\t\t/**\n\t\t * The `{ from, to }` window a date-range filter currently holds.\n\t\t *\n\t\t * @param {object} filter The filter definition.\n\t\t *\n\t\t * @return {object|null} The window, or null when none is set.\n\t\t */\n\t\tgetRangeValue(filter) {\n\t\t\tconst value = this.activeFilters[filter.key]\n\t\t\tif (value && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * A date-range filter changed.\n\t\t *\n\t\t * Emitted in the SAME `filter-change` shape every other control uses,\n\t\t * with the window as the payload's `values`, so a consumer has one\n\t\t * event to listen to and not two.\n\t\t *\n\t\t * @param {string} key The filter key.\n\t\t * @param {object|null} window The `{ from, to, preset }` value.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonRangeChange(key, window) {\n\t\t\tconst from = (window && window.from) || ''\n\t\t\tconst to = (window && window.to) || ''\n\t\t\tif (from === '' && to === '') {\n\t\t\t\tthis.$emit('filter-change', { key, values: [] })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('filter-change', { key, values: { from, to } })\n\t\t},\n\n\t\t/**\n\t\t * The text a `text` filter currently holds.\n\t\t *\n\t\t * @param {object} filter The filter definition.\n\t\t *\n\t\t * @return {string} The current value.\n\t\t */\n\t\tgetTextValue(filter) {\n\t\t\tconst value = this.activeFilters[filter.key]\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.length > 0 ? String(value[0]) : ''\n\t\t\t}\n\t\t\treturn (value === undefined || value === null) ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * A text filter changed.\n\t\t *\n\t\t * @param {string} key The filter key.\n\t\t * @param {string} value The typed value.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonTextChange(key, value) {\n\t\t\tconst text = String(value ?? '').trim()\n\t\t\tthis.$emit('filter-change', { key, values: text === '' ? [] : [text] })\n\t\t},\n\n\t\t/**\n\t\t * Load the rows a `reference` filter picks from.\n\t\t *\n\t\t * Reads `optionsSource` off the schema property:\n\t\t * `{ register, schema, labelField, valueField, limit }`. The VALUE is\n\t\t * the referenced object's uuid, because that is what the server\n\t\t * filters on; the label is only what the person reads.\n\t\t *\n\t\t * Failures are logged and leave the picker empty rather than throwing:\n\t\t * one unreachable list must not take the whole sidebar with it.\n\t\t *\n\t\t * @return {Promise<void>} Resolves when every reference filter settled.\n\t\t */\n\t\tasync loadReferenceOptions() {\n\t\t\tconst pending = this.schemaFilters.filter((filter) => filter.type === 'reference'\n\t\t\t\t&& filter.optionsSource\n\t\t\t\t&& this.referenceOptions[filter.key] === undefined\n\t\t\t\t&& this.referenceLoading[filter.key] !== true)\n\t\t\tif (pending.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\timport('@nextcloud/router'),\n\t\t\t])\n\n\t\t\tawait Promise.all(pending.map(async (filter) => {\n\t\t\t\tconst source = filter.optionsSource\n\t\t\t\tif (!source.register || !source.schema) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.referenceLoading = { ...this.referenceLoading, [filter.key]: true }\n\t\t\t\ttry {\n\t\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', {\n\t\t\t\t\t\tregister: source.register,\n\t\t\t\t\t\tschema: source.schema,\n\t\t\t\t\t})\n\t\t\t\t\tconst response = await axios.get(url, { params: { _limit: source.limit || 200 } })\n\t\t\t\t\tconst rows = response?.data?.results || response?.data || []\n\t\t\t\t\tconst valueField = source.valueField || '@self.uuid'\n\t\t\t\t\tconst labelField = source.labelField || 'title'\n\t\t\t\t\tconst options = rows\n\t\t\t\t\t\t.map((row) => ({\n\t\t\t\t\t\t\tid: this.readPath(row, valueField),\n\t\t\t\t\t\t\tlabel: String(this.readPath(row, labelField) ?? this.readPath(row, valueField) ?? ''),\n\t\t\t\t\t\t}))\n\t\t\t\t\t\t.filter((option) => option.id !== null && option.id !== undefined && option.id !== '')\n\t\t\t\t\t\t.sort((a, b) => a.label.localeCompare(b.label))\n\t\t\t\t\tthis.referenceOptions = { ...this.referenceOptions, [filter.key]: options }\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.error(`[CnIndexSidebar] the reference filter \"${filter.key}\" could not load its options`, error)\n\t\t\t\t\tthis.referenceOptions = { ...this.referenceOptions, [filter.key]: [] }\n\t\t\t\t} finally {\n\t\t\t\t\tthis.referenceLoading = { ...this.referenceLoading, [filter.key]: false }\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Read a dotted path off a row (`@self.uuid`, `title`).\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {string} path The dotted path.\n\t\t *\n\t\t * @return {unknown} The value, or undefined.\n\t\t */\n\t\treadPath(row, path) {\n\t\t\treturn String(path).split('.').reduce((acc, part) => ((acc === null || acc === undefined) ? acc : acc[part]), row)\n\t\t},\n\n\t\t/**\n\t\t * Get currently selected options for a filter\n\t\t *\n\t\t * @param {object} filter Filter object\n\t\t */\n\t\tgetSelectedFilterOptions(filter) {\n\t\t\tconst value = this.activeFilters[filter.key]\n\t\t\tif (!value) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst values = Array.isArray(value) ? value : [value]\n\t\t\tconst options = this.getFilterOptions(filter)\n\t\t\treturn values.map((v) => options.find((o) => o.id === v) || { id: v, label: String(v) })\n\t\t},\n\n\t\t/**\n\t\t * Handle filter select change\n\t\t *\n\t\t * @param {string} key Filter key\n\t\t * @param {Array} selected Selected values\n\t\t */\n\t\tonFilterChange(key, selected) {\n\t\t\t// 🔴 A SINGLE-VALUED SELECT EMITS AN OBJECT, NOT AN ARRAY. NcSelect\n\t\t\t// changes the SHAPE of its payload with `multiple`, and `.map` on\n\t\t\t// the object shape throws inside an event handler, where Vue logs\n\t\t\t// it and carries on: the picker looks inert and the console says\n\t\t\t// why in a place nobody is looking.\n\t\t\tconst chosen = Array.isArray(selected) ? selected : (selected ? [selected] : [])\n\t\t\tconst values = chosen.map((o) => ((o && typeof o === 'object' && 'id' in o) ? o.id : o))\n\t\t\tthis.$emit('filter-change', { key, values })\n\t\t},\n\n\t\t/**\n\t\t * \"Clear all\" click: reset search and every active facet filter in\n\t\t * one shot, so the parent does one fetch instead of one per field.\n\t\t */\n\t\tonClearAll() {\n\t\t\t/**\n\t\t\t * @event clear-filters \"Clear all\" clicked; reset search and every active filter.\n\t\t\t */\n\t\t\tthis.$emit('clear-filters')\n\t\t},\n\t},\n}\n</script>\n\n<!-- Styles in css/index-sidebar.css -->\n"],"names":["_createBlock","_createVNode","_createElementVNode","_openBlock","_createElementBlock","_renderSlot","_createTextVNode","_Fragment","_renderList","_toDisplayString","_normalizeClass","_withModifiers"],"mappings":"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"}
1
+ {"version":3,"file":"CnIndexSidebar.vue3.js","sources":["../../../../src/components/CnIndexSidebar/CnIndexSidebar.vue?vue&type=template&id=53b53306&lang.js"],"sourcesContent":["<template>\n\t<NcAppSidebar\n\t\tv-model:open=\"internalOpen\"\n\t\t:name=\"resolvedName\"\n\t\t:title=\"resolvedName\"\n\t\t:subname=\"resolvedSubname\"\n\t\t:active=\"internalActiveTab\"\n\t\t:compact=\"!!resolvedIcon\"\n\t\t@close=\"$emit('update:open', false)\"\n\t\t@update:active=\"onTabChange\">\n\t\t<!-- Schema icon in sidebar header -->\n\t\t<template v-if=\"resolvedIcon\" #header>\n\t\t\t<div class=\"cn-index-sidebar__header-icon\">\n\t\t\t\t<CnIcon :name=\"resolvedIcon\" :size=\"32\" />\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- Search Tab -->\n\t\t<NcAppSidebarTab\n\t\t\tid=\"search-tab\"\n\t\t\t:name=\"searchTabLabel\"\n\t\t\t:order=\"1\">\n\t\t\t<template #icon>\n\t\t\t\t<FilterOutline :size=\"20\" />\n\t\t\t</template>\n\n\t\t\t<div class=\"cn-index-sidebar__tab-content\">\n\t\t\t\t<div v-if=\"$slots['search-above']\" class=\"cn-index-sidebar__section\">\n\t\t\t\t\t<slot name=\"search-above\" />\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"cn-index-sidebar__section\">\n\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t:modelValue=\"searchValue || ''\"\n\t\t\t\t\t\t:placeholder=\"searchPlaceholder\"\n\t\t\t\t\t\t:label=\"searchLabel\"\n\t\t\t\t\t\t@update:modelValue=\"$emit('search', $event)\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Sort (list, card and map views; the table sorts by its headers):\n\t\t\t\t the field, the direction and the order the list has now. -->\n\t\t\t\t<div v-if=\"sortOptions.length > 0\" class=\"cn-index-sidebar__section cn-index-sidebar__sort\" data-testid=\"cn-index-sidebar-sort\">\n\t\t\t\t\t<h3>{{ t('nextcloud-vue', 'Sort') }}</h3>\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:modelValue=\"sortSelected\"\n\t\t\t\t\t\t:options=\"sortOptions\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\t:clearable=\"false\"\n\t\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Sort by')\"\n\t\t\t\t\t\t@update:modelValue=\"onSortField\" />\n\t\t\t\t\t<div class=\"cn-index-sidebar__sort-direction\" role=\"radiogroup\" :aria-label=\"t('nextcloud-vue', 'Direction')\">\n\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t\t\tname=\"cn-index-sidebar-sort-direction\"\n\t\t\t\t\t\t\tvalue=\"asc\"\n\t\t\t\t\t\t\t:modelValue=\"sortDirection\"\n\t\t\t\t\t\t\t:disabled=\"!sortSelected\"\n\t\t\t\t\t\t\t@update:modelValue=\"onSortDirection\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Ascending') }}\n\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\ttype=\"radio\"\n\t\t\t\t\t\t\tname=\"cn-index-sidebar-sort-direction\"\n\t\t\t\t\t\t\tvalue=\"desc\"\n\t\t\t\t\t\t\t:modelValue=\"sortDirection\"\n\t\t\t\t\t\t\t:disabled=\"!sortSelected\"\n\t\t\t\t\t\t\t@update:modelValue=\"onSortDirection\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Descending') }}\n\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t</div>\n\t\t\t\t\t<p class=\"cn-index-sidebar__sort-current\" data-testid=\"cn-index-sidebar-sort-current\">\n\t\t\t\t\t\t{{ currentSortText }}\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\n\t\t\t\t<div v-if=\"hasActiveFilters\" class=\"cn-index-sidebar__section\">\n\t\t\t\t\t<NcButton variant=\"tertiary\" @click=\"onClearAll\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<FilterRemoveOutline :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ clearAllLabel }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t</div>\n\n\t\t\t\t<div v-if=\"schemaFilters.length > 0\" class=\"cn-index-sidebar__section\">\n\t\t\t\t\t<h3>{{ filtersLabel }}</h3>\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-for=\"filter in schemaFilters\"\n\t\t\t\t\t\t:key=\"filter.key\"\n\t\t\t\t\t\tclass=\"cn-index-sidebar__filter-group\">\n\t\t\t\t\t\t<div class=\"cn-index-sidebar__filter-header\">\n\t\t\t\t\t\t\t<span class=\"cn-index-sidebar__filter-label\">{{ filter.label }}</span>\n\t\t\t\t\t\t\t<NcPopover v-if=\"filter.description\" popupRole=\"dialog\">\n\t\t\t\t\t\t\t\t<template #trigger>\n\t\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t\t\t\t\t\t\t\t:aria-label=\"filter.label + ' info'\"\n\t\t\t\t\t\t\t\t\t\tclass=\"cn-index-sidebar__info-btn\">\n\t\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t\t<InformationOutline :size=\"16\" />\n\t\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<p class=\"cn-index-sidebar__filter-description\">\n\t\t\t\t\t\t\t\t\t{{ filter.description }}\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</NcPopover>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- A window, not a list of values: two bounds and a\n\t\t\t\t\t\t preset, emitted as the `{ from, to }` the range\n\t\t\t\t\t\t filters upstream are already spelled in. -->\n\t\t\t\t\t\t<CnDateRangePicker\n\t\t\t\t\t\t\tv-if=\"filter.type === 'date-range'\"\n\t\t\t\t\t\t\tclass=\"cn-index-sidebar__date-range\"\n\t\t\t\t\t\t\t:modelValue=\"getRangeValue(filter)\"\n\t\t\t\t\t\t\t:presets=\"filter.presets || rangePresets\"\n\t\t\t\t\t\t\t:fromLabel=\"filter.fromLabel || fromLabel\"\n\t\t\t\t\t\t\t:toLabel=\"filter.toLabel || toLabel\"\n\t\t\t\t\t\t\t:presetLabel=\"filter.label\"\n\t\t\t\t\t\t\t@update:modelValue=\"onRangeChange(filter.key, $event)\" />\n\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\tv-else-if=\"filter.type === 'text'\"\n\t\t\t\t\t\t\tclass=\"cn-index-sidebar__filter-text\"\n\t\t\t\t\t\t\t:modelValue=\"getTextValue(filter)\"\n\t\t\t\t\t\t\t:label=\"filter.label\"\n\t\t\t\t\t\t\t:placeholder=\"filter.label\"\n\t\t\t\t\t\t\t@update:modelValue=\"onTextChange(filter.key, $event)\" />\n\t\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\tclass=\"cn-index-sidebar__select\"\n\t\t\t\t\t\t\t:modelValue=\"getSelectedFilterOptions(filter)\"\n\t\t\t\t\t\t\t:options=\"getFilterOptions(filter)\"\n\t\t\t\t\t\t\t:loading=\"isLoadingOptions(filter)\"\n\t\t\t\t\t\t\tplaceholder=\"Select...\"\n\t\t\t\t\t\t\t:inputLabel=\"filter.label\"\n\t\t\t\t\t\t\t:multiple=\"filter.multiple !== false\"\n\t\t\t\t\t\t\t:keepOpen=\"filter.multiple !== false\"\n\t\t\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\t\t\t@update:modelValue=\"onFilterChange(filter.key, $event)\" />\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\n\t\t\t\t<slot name=\"search-extra\" />\n\t\t\t</div>\n\t\t</NcAppSidebarTab>\n\n\t\t<!-- Columns Tab -->\n\t\t<NcAppSidebarTab\n\t\t\tid=\"columns-tab\"\n\t\t\t:name=\"columnsTabLabel\"\n\t\t\t:order=\"2\">\n\t\t\t<template #icon>\n\t\t\t\t<ViewColumnOutline :size=\"20\" />\n\t\t\t</template>\n\n\t\t\t<div class=\"cn-index-sidebar__tab-content\">\n\t\t\t\t<div class=\"cn-sidebar-columns\">\n\t\t\t\t\t<h3>{{ columnsHeading }}</h3>\n\t\t\t\t\t<p class=\"cn-sidebar-columns__description\">\n\t\t\t\t\t\t{{ columnsDescription }}\n\t\t\t\t\t</p>\n\n\t\t\t\t\t<!-- Order and pin the visible columns. Drag and the Move buttons\n\t\t\t\t\t call the same method (moveColumn); the table header is not a drag target. -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tv-if=\"personalColumns && orderedVisible.length > 0\"\n\t\t\t\t\t\tclass=\"cn-sidebar-columns__order\"\n\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-order\">\n\t\t\t\t\t\t<h4>{{ t('nextcloud-vue', 'Order and pin') }}</h4>\n\t\t\t\t\t\t<ol class=\"cn-sidebar-columns__order-list\">\n\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\tv-for=\"(item, index) in orderedVisible\"\n\t\t\t\t\t\t\t\t:key=\"item.key\"\n\t\t\t\t\t\t\t\tclass=\"cn-sidebar-columns__order-item\"\n\t\t\t\t\t\t\t\t:class=\"{ 'cn-sidebar-columns__order-item--pinned': index < pinnedCount }\"\n\t\t\t\t\t\t\t\tdraggable=\"true\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-order-item\"\n\t\t\t\t\t\t\t\t@dragstart=\"dragFrom = index\"\n\t\t\t\t\t\t\t\t@dragover.prevent\n\t\t\t\t\t\t\t\t@drop.prevent=\"onDropColumn(index)\">\n\t\t\t\t\t\t\t\t<DragVertical :size=\"18\" class=\"cn-sidebar-columns__handle\" aria-hidden=\"true\" />\n\t\t\t\t\t\t\t\t<span class=\"cn-sidebar-columns__order-label\">{{ item.label }}</span>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\t\t:disabled=\"index === 0 || index === pinnedCount\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Move {column} up', { column: item.label })\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-up\"\n\t\t\t\t\t\t\t\t\t@click=\"moveColumn(index, index - 1)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<ChevronUp :size=\"18\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\t\t:disabled=\"index === orderedVisible.length - 1 || index === pinnedCount - 1\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Move {column} down', { column: item.label })\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-down\"\n\t\t\t\t\t\t\t\t\t@click=\"moveColumn(index, index + 1)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<ChevronDown :size=\"18\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t\t\t:aria-pressed=\"String(index < pinnedCount)\"\n\t\t\t\t\t\t\t\t\t:aria-label=\"index < pinnedCount ? t('nextcloud-vue', 'Unpin {column}', { column: item.label }) : t('nextcloud-vue', 'Pin {column}', { column: item.label })\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-pin\"\n\t\t\t\t\t\t\t\t\t@click=\"togglePin(index)\">\n\t\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t\t<Pin v-if=\"index < pinnedCount\" :size=\"18\" />\n\t\t\t\t\t\t\t\t\t\t<PinOutline v-else :size=\"18\" />\n\t\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t</ol>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\tdata-testid=\"cn-sidebar-columns-reset\"\n\t\t\t\t\t\t\t@click=\"$emit('columns-reset')\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Reset columns') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<template v-if=\"allColumns.length > 0 || allGroups.length > 0\">\n\t\t\t\t\t\t<!-- Schema properties group (collapsible) -->\n\t\t\t\t\t\t<div v-if=\"allColumns.length > 0\" class=\"cn-sidebar-columns__group cn-sidebar-columns__group--collapsible\">\n\t\t\t\t\t\t\t<div class=\"cn-sidebar-columns__group-header\" @click=\"propertiesExpanded = !propertiesExpanded\">\n\t\t\t\t\t\t\t\t<ChevronDown v-if=\"propertiesExpanded\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<ChevronRight v-else :size=\"20\" />\n\t\t\t\t\t\t\t\t<h4>{{ resolvedPropertiesLabel }}</h4>\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\t:modelValue=\"isGroupAllVisible(allColumns)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-sidebar-columns__select-all\"\n\t\t\t\t\t\t\t\t\t@click.stop\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"toggleGroupAll(allColumns)\">\n\t\t\t\t\t\t\t\t\tAll\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div v-if=\"propertiesExpanded\" class=\"cn-sidebar-columns__group-content\">\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\tv-for=\"col in allColumns\"\n\t\t\t\t\t\t\t\t\t:key=\"col.key\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"isColumnVisible(col.key)\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"toggleColumn(col.key)\">\n\t\t\t\t\t\t\t\t\t{{ col.label }}\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t<!-- Extra column groups (built-in Metadata + external) -->\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tv-for=\"group in allGroups\"\n\t\t\t\t\t\t\t:key=\"group.id\"\n\t\t\t\t\t\t\tclass=\"cn-sidebar-columns__group cn-sidebar-columns__group--collapsible\">\n\t\t\t\t\t\t\t<div class=\"cn-sidebar-columns__group-header\" @click=\"toggleGroup(group.id)\">\n\t\t\t\t\t\t\t\t<ChevronDown v-if=\"expandedGroups[group.id]\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<ChevronRight v-else :size=\"20\" />\n\t\t\t\t\t\t\t\t<h4 :lang=\"langOf(group.label)\">\n\t\t\t\t\t\t\t\t\t{{ shown(group.label) }}\n\t\t\t\t\t\t\t\t</h4>\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\t:modelValue=\"isGroupAllVisible(group.columns)\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-sidebar-columns__select-all\"\n\t\t\t\t\t\t\t\t\t@click.stop\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"toggleGroupAll(group.columns)\">\n\t\t\t\t\t\t\t\t\tAll\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div v-if=\"expandedGroups[group.id]\" class=\"cn-sidebar-columns__group-content\">\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\tv-for=\"col in group.columns\"\n\t\t\t\t\t\t\t\t\t:key=\"col.key\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"isColumnVisible(col.key)\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"toggleColumn(col.key)\">\n\t\t\t\t\t\t\t\t\t{{ shown(col.label) }}\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</template>\n\n\t\t\t\t\t<p v-else class=\"cn-sidebar-columns__empty\">\n\t\t\t\t\t\tNo columns available. Provide a schema to auto-generate columns.\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\n\t\t\t\t<slot name=\"columns-extra\" />\n\t\t\t</div>\n\t\t</NcAppSidebarTab>\n\n\t\t<!-- Extra tabs injected by the consumer -->\n\t\t<slot name=\"tabs\" />\n\t</NcAppSidebar>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAppSidebar, NcAppSidebarTab, NcButton, NcCheckboxRadioSwitch, NcPopover, NcSelect, NcTextField } from '@nextcloud/vue'\nimport ChevronDown from 'vue-material-design-icons/ChevronDown.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport ChevronUp from 'vue-material-design-icons/ChevronUp.vue'\nimport DragVertical from 'vue-material-design-icons/DragVertical.vue'\nimport FilterOutline from 'vue-material-design-icons/FilterOutline.vue'\nimport FilterRemoveOutline from 'vue-material-design-icons/FilterRemoveOutline.vue'\nimport InformationOutline from 'vue-material-design-icons/InformationOutline.vue'\nimport Pin from 'vue-material-design-icons/Pin.vue'\nimport PinOutline from 'vue-material-design-icons/PinOutline.vue'\nimport ViewColumnOutline from 'vue-material-design-icons/ViewColumnOutline.vue'\nimport { METADATA_COLUMNS } from '../../constants/metadata.js'\nimport { facetOptions } from '../../utils/facets.js'\nimport { labelLang } from '../../utils/manifestTranslate.js'\nimport { columnsFromSchema, filtersFromSchema } from '../../utils/schema.js'\nimport { reverseSortKeys, sameSortKeys } from '../../utils/sortOrder.js'\nimport { CnDateRangePicker, DEFAULT_DATE_RANGE_PRESETS } from '../CnDateRangePicker/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\n\n/**\n * CnIndexSidebar — Reusable NcAppSidebar wrapper with Search + Columns tabs.\n *\n * Designed to be schema-driven: pass a schema and the sidebar auto-generates\n * search filters, column visibility controls, and the standard Metadata group.\n * Title and properties group label are derived from schema.title by default.\n *\n * Must be rendered at the App.vue level as a sibling of NcAppContent.\n * Use provide/inject to connect it to page components.\n *\n * @slot search-above - Content rendered above the search field in the Search tab (e.g. hints, quick actions).\n * @slot search-extra - Content rendered below the search field and filters in the Search tab (e.g. saved searches).\n */\nexport default {\n\tname: 'CnIndexSidebar',\n\n\tcomponents: {\n\t\tNcAppSidebar,\n\t\tNcAppSidebarTab,\n\t\tNcTextField,\n\t\tNcSelect,\n\t\tCnDateRangePicker,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcPopover,\n\t\tNcButton,\n\t\tCnIcon,\n\t\tFilterOutline,\n\t\tFilterRemoveOutline,\n\t\tViewColumnOutline,\n\t\tChevronDown,\n\t\tChevronRight,\n\t\tChevronUp,\n\t\tDragVertical,\n\t\tPin,\n\t\tPinOutline,\n\t\tInformationOutline,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Consumer translation function, provided by CnAppRoot as\n\t\t * `cnTranslate: this.translate` (bound to the host app's id). Column and\n\t\t * filter labels come from schema property titles, authored in English as\n\t\t * the canonical source; the visible label is resolved through this\n\t\t * function so it follows the user's language. Defaults to identity when\n\t\t * used standalone (no CnAppRoot ancestor).\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Sidebar title. Defaults to schema.title when not set. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** MDI icon name or emoji. Defaults to schema.icon when not set. */\n\t\ticon: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Schema object for auto-generating filters, columns, and labels */\n\t\tschema: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Array of currently visible column keys */\n\t\tvisibleColumns: {\n\t\t\ttype: Array,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Show the Order and pin controls in the Columns tab, and Reset columns.\n\t\t * Off keeps show and hide only.\n\t\t */\n\t\tpersonalColumns: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** How many of the first visible columns are pinned to the start of the table. */\n\t\tpinnedCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\n\t\t/**\n\t\t * The orders the Sort section offers, `[{ value, label, keys }]`, each\n\t\t * `keys` a `[{ key, order }]` list read as its ascending form. Empty\n\t\t * draws no Sort section (the table view sorts by its headers).\n\t\t */\n\t\tsortOptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** The list's current order, `[{ key, order }]`. */\n\t\tcurrentSort: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Current search term */\n\t\tsearchValue: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether sidebar is open */\n\t\topen: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Current active facet filters: { fieldName: [values] } */\n\t\tactiveFilters: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** Live facet data from the API: `{ fieldName: { values: [{ value, count?, label? }] } }` */\n\t\tfacetData: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Additional column groups beyond schema properties and the built-in Metadata.\n\t\t * Each group: { id: string, label: string, columns: Array<{key, label}>, expanded?: boolean }\n\t\t */\n\t\tcolumnGroups: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether to include the built-in Metadata column group */\n\t\tshowMetadata: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Search input placeholder */\n\t\tsearchPlaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Type to search…'),\n\t\t},\n\n\t\t/** Search tab label */\n\t\tsearchTabLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Search'),\n\t\t},\n\n\t\t/** Columns tab label */\n\t\tcolumnsTabLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Columns'),\n\t\t},\n\n\t\t/** Search section heading */\n\t\tsearchLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Search'),\n\t\t},\n\n\t\t/** Filters section heading */\n\t\tfiltersLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Filters'),\n\t\t},\n\n\t\t/** \"Clear all\" button label, shown when search or a filter is active */\n\t\tclearAllLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Clear all'),\n\t\t},\n\n\t\t/**\n\t\t * Filter declarations for a page with no schema of its own: `{ name: declaration }`, the same shape a schema property has. Wins over `schema`, and feeds the Search tab only.\n\t\t *\n\t\t * 🔑 A FILTER IS NOT A COLUMN, which is the whole reason this is its\n\t\t * own prop rather than a synthetic `schema`. The schema feeds BOTH\n\t\t * tabs, so a page that declared its filters there would also offer\n\t\t * them in the Columns tab: the toggle would tick and no column would\n\t\t * appear, because the table's columns come from somewhere else\n\t\t * entirely. These reach the Search tab and nothing else.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tfilterFields: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Start-of-window label on a date-range filter. */\n\t\tfromLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'From'),\n\t\t},\n\n\t\t/** End-of-window label on a date-range filter. */\n\t\ttoLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'To'),\n\t\t},\n\n\t\t/** Columns section heading */\n\t\tcolumnsHeading: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Column visibility'),\n\t\t},\n\n\t\t/** Columns section description */\n\t\tcolumnsDescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Select which columns to display in the table'),\n\t\t},\n\n\t\t/** Override label for the schema properties group. Defaults to schema.title. */\n\t\tpropertiesGroupLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * ID of the tab that should be active when the sidebar opens.\n\t\t * Built-in IDs are 'search-tab' and 'columns-tab'.\n\t\t * Use the id you set on your custom NcAppSidebarTab for custom tabs.\n\t\t */\n\t\tdefaultTab: {\n\t\t\ttype: String,\n\t\t\tdefault: 'search-tab',\n\t\t},\n\n\t\t/**\n\t\t * Whether the current user is an admin.\n\t\t * When false, schema properties with `adminOnly: true` are hidden from filters.\n\t\t */\n\t\tuserIsAdmin: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\t},\n\n\temits: ['clear-filters', 'columns-change', 'columns-reorder', 'columns-reset', 'pin-change', 'filter-change', 'search', 'sort-change', 'tab-change', 'update:open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tinternalOpen: this.open,\n\t\t\tinternalActiveTab: this.defaultTab,\n\t\t\t/** Index of the column being dragged in the Order and pin list, or -1. */\n\t\t\tdragFrom: -1,\n\t\t\tpropertiesExpanded: true,\n\t\t\texpandedGroups: {},\n\t\t\t/**\n\t\t\t * Options loaded for a `reference` filter, keyed by field.\n\t\t\t *\n\t\t\t * A reference picker lists rows from ANOTHER list (the cases a\n\t\t\t * task can hang off, say), and neither the schema nor a facet\n\t\t\t * bucket carries them. Loaded once per field and cached, because\n\t\t\t * the sidebar re-renders on every keystroke in the search box.\n\t\t\t *\n\t\t\t * @type {Record<string, Array<{id: string, label: string}>>}\n\t\t\t */\n\t\t\treferenceOptions: {},\n\t\t\t/** @type {Record<string, boolean>} Which reference loads are in flight. */\n\t\t\treferenceLoading: {},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The Sort option the current order matches, as declared or reversed.\n\t\t *\n\t\t * @return {{option: object, direction: string}|null} The match, or null.\n\t\t */\n\t\tsortMatch() {\n\t\t\tconst current = Array.isArray(this.currentSort) ? this.currentSort : []\n\t\t\tfor (const option of this.sortOptions) {\n\t\t\t\tconst keys = Array.isArray(option.keys) ? option.keys : []\n\t\t\t\tif (sameSortKeys(keys, current)) {\n\t\t\t\t\treturn { option, direction: 'asc' }\n\t\t\t\t}\n\t\t\t\tif (sameSortKeys(reverseSortKeys(keys), current)) {\n\t\t\t\t\treturn { option, direction: 'desc' }\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/** @return {object|null} The Sort option shown as chosen. */\n\t\tsortSelected() {\n\t\t\treturn this.sortMatch ? this.sortMatch.option : null\n\t\t},\n\n\t\t/** @return {string} The chosen direction, `asc` or `desc`. */\n\t\tsortDirection() {\n\t\t\treturn this.sortMatch ? this.sortMatch.direction : 'asc'\n\t\t},\n\n\t\t/**\n\t\t * The order the list has now, in words: \"Current order: Created,\n\t\t * descending\", or that it is not sorted.\n\t\t *\n\t\t * @return {string} The sentence.\n\t\t */\n\t\tcurrentSortText() {\n\t\t\tconst current = Array.isArray(this.currentSort) ? this.currentSort : []\n\t\t\tif (current.length === 0) {\n\t\t\t\treturn t('nextcloud-vue', 'Not sorted')\n\t\t\t}\n\t\t\tconst labelOf = (key) => {\n\t\t\t\tconst single = this.sortOptions.find((o) => Array.isArray(o.keys) && o.keys.length === 1 && o.keys[0].key === key)\n\t\t\t\treturn single ? single.label : key\n\t\t\t}\n\t\t\tconst order = this.sortMatch && this.sortMatch.option.keys.length > 1\n\t\t\t\t? `${this.sortMatch.option.label}, ${this.sortDirection === 'desc' ? t('nextcloud-vue', 'descending') : t('nextcloud-vue', 'ascending')}`\n\t\t\t\t: current.map((entry) => `${labelOf(entry.key)}, ${entry.order === 'desc' ? t('nextcloud-vue', 'descending') : t('nextcloud-vue', 'ascending')}`).join('; ')\n\t\t\treturn t('nextcloud-vue', 'Current order: {order}', { order })\n\t\t},\n\n\t\t/** Resolved icon — explicit prop overrides schema.icon */\n\t\tresolvedIcon() {\n\t\t\treturn this.icon || this.schema?.icon || ''\n\t\t},\n\n\t\t/** Sidebar name — schema title, shown as the h2 header */\n\t\tresolvedName() {\n\t\t\tif (this.title) {\n\t\t\t\treturn this.shown(this.title)\n\t\t\t}\n\t\t\treturn this.schema?.title || 'Search'\n\t\t},\n\n\t\t/** Sidebar subname — schema description, shown below the name */\n\t\tresolvedSubname() {\n\t\t\treturn this.schema?.description || ''\n\t\t},\n\n\t\t/** Properties group label — derived from schema.title if not explicitly set */\n\t\tresolvedPropertiesLabel() {\n\t\t\tif (this.propertiesGroupLabel) {\n\t\t\t\treturn this.propertiesGroupLabel\n\t\t\t}\n\t\t\treturn this.schema?.title || 'Properties'\n\t\t},\n\n\t\t/** All available columns from schema */\n\t\tallColumns() {\n\t\t\tif (!this.schema) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn columnsFromSchema(this.schema, { translate: this.cnTranslate })\n\t\t},\n\n\t\t/** Filter definitions from schema (facetable properties, respecting RBAC) */\n\t\tschemaFilters() {\n\t\t\t// An explicitly declared filter set wins: it is the page saying\n\t\t\t// \"these are the questions\", where a schema only says \"these are\n\t\t\t// the properties\" and the sidebar has to guess which of them are\n\t\t\t// worth asking about.\n\t\t\tif (this.filterFields && Object.keys(this.filterFields).length > 0) {\n\t\t\t\treturn filtersFromSchema(\n\t\t\t\t\t{ properties: this.filterFields },\n\t\t\t\t\t{ isAdmin: this.userIsAdmin, translate: this.cnTranslate },\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (!this.schema) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn filtersFromSchema(this.schema, { isAdmin: this.userIsAdmin, translate: this.cnTranslate })\n\t\t},\n\n\t\t/** Whether a search term or any facet filter is currently active. */\n\t\thasActiveFilters() {\n\t\t\tif ((this.searchValue || '').length > 0) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn Object.values(this.activeFilters || {}).some((v) => (Array.isArray(v) ? v.length > 0 : !!v))\n\t\t},\n\n\t\t/** Combined column groups: built-in Metadata + external groups */\n\t\tallGroups() {\n\t\t\tconst groups = []\n\t\t\tif (this.showMetadata && this.schema) {\n\t\t\t\tgroups.push({\n\t\t\t\t\tid: 'metadata',\n\t\t\t\t\tlabel: 'Metadata',\n\t\t\t\t\tcolumns: METADATA_COLUMNS,\n\t\t\t\t\texpanded: true,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn [...groups, ...this.columnGroups]\n\t\t},\n\n\t\t/** Label of each column key, from the schema properties and the groups. */\n\t\tcolumnLabels() {\n\t\t\tconst map = {}\n\t\t\tthis.allColumns.forEach((c) => {\n\t\t\t\tmap[c.key] = c.label\n\t\t\t})\n\t\t\tthis.allGroups.forEach((g) => g.columns.forEach((c) => {\n\t\t\t\tmap[c.key] = c.label\n\t\t\t}))\n\t\t\treturn map\n\t\t},\n\n\t\t/** The visible columns in their order, with labels (all columns when none were chosen). */\n\t\torderedVisible() {\n\t\t\tconst keys = this.visibleColumns === null ? this.allColumnKeys : this.visibleColumns\n\t\t\treturn keys.filter((k) => this.columnLabels[k] !== undefined).map((key) => ({ key, label: this.columnLabels[key] }))\n\t\t},\n\n\t\t/** All column keys across schema properties and all groups */\n\t\tallColumnKeys() {\n\t\t\treturn [\n\t\t\t\t...this.allColumns.map((c) => c.key),\n\t\t\t\t...this.allGroups.flatMap((g) => g.columns.map((c) => c.key)),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * The presets a date-range filter offers when it declares none.\n\t\t *\n\t\t * Just `custom`. Every shipped preset rolls BACKWARDS from today\n\t\t * (\"Last 30 days\"), and a sidebar filter is as often a forward window\n\t\t * (\"due next week\") as a backward one. Offering a preset that answers\n\t\t * the wrong direction is worse than offering none: it is one click and\n\t\t * it looks deliberate.\n\t\t *\n\t\t * @return {Array<object>} The preset list.\n\t\t */\n\t\trangePresets() {\n\t\t\t// Taken FROM the picker's own list rather than written out again, so\n\t\t\t// the one preset a filter offers carries the same id and the same\n\t\t\t// label as everywhere else it appears.\n\t\t\treturn DEFAULT_DATE_RANGE_PRESETS\n\t\t\t\t.filter((preset) => preset.id === 'custom')\n\t\t\t\t.map((preset) => ({ ...preset }))\n\t\t},\n\t},\n\n\twatch: {\n\t\topen(val) {\n\t\t\tthis.internalOpen = val\n\t\t},\n\n\t\tinternalOpen(val) {\n\t\t\tthis.$emit('update:open', val)\n\t\t},\n\n\t\tdefaultTab(val) {\n\t\t\tthis.internalActiveTab = val\n\t\t},\n\n\t\tallGroups: {\n\t\t\timmediate: true,\n\t\t\thandler(groups) {\n\t\t\t\tfor (const group of groups) {\n\t\t\t\t\tif (!(group.id in this.expandedGroups)) {\n\t\t\t\t\t\tthis.expandedGroups[group.id] = group.expanded !== false\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\t// A reference picker's rows load once the schema naming them arrives,\n\t\t// which on a manifest page is after mount. Watching the FILTERS rather\n\t\t// than calling from `mounted()` covers both orders.\n\t\tschemaFilters: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.loadReferenceOptions()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * A field chosen in the Sort section: its order, in the direction\n\t\t * already chosen.\n\t\t *\n\t\t * @param {object|null} option The chosen option.\n\t\t * @return {void}\n\t\t */\n\t\tonSortField(option) {\n\t\t\tconst chosen = option && this.sortOptions.find((o) => o.value === option.value)\n\t\t\tif (!chosen) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.emitSort(chosen, this.sortDirection)\n\t\t},\n\n\t\t/**\n\t\t * A direction chosen in the Sort section, for the chosen field.\n\t\t *\n\t\t * @param {string} direction `asc` or `desc`.\n\t\t * @return {void}\n\t\t */\n\t\tonSortDirection(direction) {\n\t\t\tif (!this.sortSelected) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.emitSort(this.sortSelected, direction === 'desc' ? 'desc' : 'asc')\n\t\t},\n\n\t\t/**\n\t\t * Emit the order an option stands for in a direction.\n\t\t *\n\t\t * @param {object} option The Sort option.\n\t\t * @param {string} direction `asc` or `desc`.\n\t\t * @return {void}\n\t\t */\n\t\temitSort(option, direction) {\n\t\t\tconst keys = Array.isArray(option.keys) ? option.keys : []\n\t\t\t/**\n\t\t\t * @event sort-change The Sort section chose an order. Payload: `[{ key, order }]`.\n\t\t\t */\n\t\t\tthis.$emit('sort-change', direction === 'desc' ? reverseSortKeys(keys) : keys.map((k) => ({ key: k.key, order: k.order || 'asc' })))\n\t\t},\n\n\t\t/**\n\t\t * A manifest label through the injected lookup, or as written.\n\t\t *\n\t\t * @param {string} text The label as written.\n\t\t * @return {string} The label in the user's language.\n\t\t */\n\t\tshown(text) {\n\t\t\treturn typeof this.cnTranslate === 'function' && typeof text === 'string' && text !== '' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/**\n\t\t * The `lang` of a label that fell back to its written text in another language.\n\t\t *\n\t\t * @param {string} text The label as written.\n\t\t * @return {string|undefined} The source language, or undefined.\n\t\t */\n\t\tlangOf(text) {\n\t\t\treturn labelLang(this.cnTranslate, text) || undefined\n\t\t},\n\n\t\t/**\n\t\t * Handle tab change from NcAppSidebar\n\t\t *\n\t\t * @param {string} tabId Tab identifier\n\t\t */\n\t\tonTabChange(tabId) {\n\t\t\tthis.internalActiveTab = tabId\n\t\t\tthis.$emit('tab-change', tabId)\n\t\t},\n\n\t\t/**\n\t\t * Check if a column is currently visible\n\t\t *\n\t\t * @param {string} key Column key\n\t\t */\n\t\tisColumnVisible(key) {\n\t\t\tif (this.visibleColumns === null) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn this.visibleColumns.includes(key)\n\t\t},\n\n\t\t/**\n\t\t * Check if all columns in a group are visible\n\t\t *\n\t\t * @param {string[]} columns Array of column keys\n\t\t */\n\t\tisGroupAllVisible(columns) {\n\t\t\treturn columns.every((col) => this.isColumnVisible(col.key))\n\t\t},\n\n\t\t/**\n\t\t * Toggle a single column's visibility\n\t\t *\n\t\t * @param {string} key Column key\n\t\t */\n\t\ttoggleColumn(key) {\n\t\t\tlet newVisible\n\t\t\tif (this.visibleColumns === null) {\n\t\t\t\tnewVisible = this.allColumnKeys.filter((k) => k !== key)\n\t\t\t} else if (this.isColumnVisible(key)) {\n\t\t\t\tnewVisible = this.visibleColumns.filter((k) => k !== key)\n\t\t\t} else {\n\t\t\t\tnewVisible = [...this.visibleColumns, key]\n\t\t\t}\n\t\t\tthis.$emit('columns-change', newVisible)\n\t\t},\n\n\t\t/**\n\t\t * Select or deselect all columns in a group\n\t\t *\n\t\t * @param {string[]} columns Array of column keys\n\t\t */\n\t\ttoggleGroupAll(columns) {\n\t\t\tconst groupKeys = columns.map((c) => c.key)\n\t\t\tconst allVisible = this.isGroupAllVisible(columns)\n\n\t\t\tlet newVisible\n\t\t\tif (this.visibleColumns === null) {\n\t\t\t\t// Currently all visible — deselect this group\n\t\t\t\tnewVisible = this.allColumnKeys.filter((k) => !groupKeys.includes(k))\n\t\t\t} else if (allVisible) {\n\t\t\t\t// All in group visible — deselect them\n\t\t\t\tnewVisible = this.visibleColumns.filter((k) => !groupKeys.includes(k))\n\t\t\t} else {\n\t\t\t\t// Not all visible — select them all\n\t\t\t\tconst current = new Set(this.visibleColumns)\n\t\t\t\tgroupKeys.forEach((k) => current.add(k))\n\t\t\t\tnewVisible = [...current]\n\t\t\t}\n\t\t\tthis.$emit('columns-change', newVisible)\n\t\t},\n\n\t\t/**\n\t\t * Move a visible column to another place in the order. The drag and the\n\t\t * Move buttons both call this. A column stays inside its block: pinned\n\t\t * columns move among the pinned, the rest among the rest.\n\t\t *\n\t\t * @param {number} from Current index.\n\t\t * @param {number} to Target index.\n\t\t * @return {void}\n\t\t */\n\t\tmoveColumn(from, to) {\n\t\t\tconst list = this.orderedVisible.map((c) => c.key)\n\t\t\tconst lo = from < this.pinnedCount ? 0 : this.pinnedCount\n\t\t\tconst hi = from < this.pinnedCount ? this.pinnedCount - 1 : list.length - 1\n\t\t\tconst target = Math.min(hi, Math.max(lo, to))\n\t\t\tif (from < 0 || from >= list.length || target === from) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [moved] = list.splice(from, 1)\n\t\t\tlist.splice(target, 0, moved)\n\t\t\t/**\n\t\t\t * @event columns-reorder Emitted when the user moves a column. Payload: the visible column keys in their new order.\n\t\t\t * @type {string[]}\n\t\t\t */\n\t\t\tthis.$emit('columns-reorder', list)\n\t\t},\n\n\t\t/**\n\t\t * Dropping a dragged column on another row.\n\t\t *\n\t\t * @param {number} index Index of the row it was dropped on.\n\t\t * @return {void}\n\t\t */\n\t\tonDropColumn(index) {\n\t\t\tconst from = this.dragFrom\n\t\t\tthis.dragFrom = -1\n\t\t\tif (from >= 0) {\n\t\t\t\tthis.moveColumn(from, index)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Pin a column (it joins the pinned block at the start) or unpin it (it\n\t\t * leaves that block, to the first place after it).\n\t\t *\n\t\t * @param {number} index Index of the column.\n\t\t * @return {void}\n\t\t */\n\t\ttogglePin(index) {\n\t\t\tconst list = this.orderedVisible.map((c) => c.key)\n\t\t\tconst [moved] = list.splice(index, 1)\n\t\t\tlet count = this.pinnedCount\n\t\t\tif (index < count) {\n\t\t\t\tcount -= 1\n\t\t\t\tlist.splice(count, 0, moved)\n\t\t\t} else {\n\t\t\t\tlist.splice(count, 0, moved)\n\t\t\t\tcount += 1\n\t\t\t}\n\t\t\tthis.$emit('columns-reorder', list)\n\t\t\t/**\n\t\t\t * @event pin-change Emitted when a column is pinned or unpinned. Payload: the new number of pinned columns.\n\t\t\t * @type {number}\n\t\t\t */\n\t\t\tthis.$emit('pin-change', count)\n\t\t},\n\n\t\t/**\n\t\t * Toggle a group's expanded state\n\t\t *\n\t\t * @param {string} groupId Filter group identifier\n\t\t */\n\t\ttoggleGroup(groupId) {\n\t\t\tthis.expandedGroups[groupId] = !this.expandedGroups[groupId]\n\t\t},\n\n\t\t/**\n\t\t * Get filter options for a filter definition\n\t\t *\n\t\t * @param {object} filter Filter object\n\t\t */\n\t\tgetFilterOptions(filter) {\n\t\t\tconst live = facetOptions(\n\t\t\t\tthis.facetData[filter.key],\n\t\t\t\t(count) => t('nextcloud-vue', 'No value ({count})', { count }),\n\t\t\t)\n\t\t\tif (live !== null) {\n\t\t\t\treturn live\n\t\t\t}\n\t\t\t// A reference picker's rows come from another list, and neither a\n\t\t\t// schema enum nor a facet bucket can carry them.\n\t\t\tif (filter.type === 'reference') {\n\t\t\t\treturn this.referenceOptions[filter.key] || []\n\t\t\t}\n\t\t\treturn filter.options || []\n\t\t},\n\n\t\t/**\n\t\t * Whether a reference filter is still fetching its rows.\n\t\t *\n\t\t * Shown rather than hidden: an empty picker that is still loading and\n\t\t * one that genuinely has nothing to pick look identical, and only one\n\t\t * of them means the person should stop waiting.\n\t\t *\n\t\t * @param {object} filter The filter definition.\n\t\t *\n\t\t * @return {boolean} True while the load is in flight.\n\t\t */\n\t\tisLoadingOptions(filter) {\n\t\t\treturn this.referenceLoading[filter.key] === true\n\t\t},\n\n\t\t/**\n\t\t * The `{ from, to }` window a date-range filter currently holds.\n\t\t *\n\t\t * @param {object} filter The filter definition.\n\t\t *\n\t\t * @return {object|null} The window, or null when none is set.\n\t\t */\n\t\tgetRangeValue(filter) {\n\t\t\tconst value = this.activeFilters[filter.key]\n\t\t\tif (value && typeof value === 'object' && !Array.isArray(value)) {\n\t\t\t\treturn value\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * A date-range filter changed.\n\t\t *\n\t\t * Emitted in the SAME `filter-change` shape every other control uses,\n\t\t * with the window as the payload's `values`, so a consumer has one\n\t\t * event to listen to and not two.\n\t\t *\n\t\t * @param {string} key The filter key.\n\t\t * @param {object|null} window The `{ from, to, preset }` value.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonRangeChange(key, window) {\n\t\t\tconst from = (window && window.from) || ''\n\t\t\tconst to = (window && window.to) || ''\n\t\t\tif (from === '' && to === '') {\n\t\t\t\tthis.$emit('filter-change', { key, values: [] })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('filter-change', { key, values: { from, to } })\n\t\t},\n\n\t\t/**\n\t\t * The text a `text` filter currently holds.\n\t\t *\n\t\t * @param {object} filter The filter definition.\n\t\t *\n\t\t * @return {string} The current value.\n\t\t */\n\t\tgetTextValue(filter) {\n\t\t\tconst value = this.activeFilters[filter.key]\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.length > 0 ? String(value[0]) : ''\n\t\t\t}\n\t\t\treturn (value === undefined || value === null) ? '' : String(value)\n\t\t},\n\n\t\t/**\n\t\t * A text filter changed.\n\t\t *\n\t\t * @param {string} key The filter key.\n\t\t * @param {string} value The typed value.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonTextChange(key, value) {\n\t\t\tconst text = String(value ?? '').trim()\n\t\t\tthis.$emit('filter-change', { key, values: text === '' ? [] : [text] })\n\t\t},\n\n\t\t/**\n\t\t * Load the rows a `reference` filter picks from.\n\t\t *\n\t\t * Reads `optionsSource` off the schema property:\n\t\t * `{ register, schema, labelField, valueField, limit }`. The VALUE is\n\t\t * the referenced object's uuid, because that is what the server\n\t\t * filters on; the label is only what the person reads.\n\t\t *\n\t\t * Failures are logged and leave the picker empty rather than throwing:\n\t\t * one unreachable list must not take the whole sidebar with it.\n\t\t *\n\t\t * @return {Promise<void>} Resolves when every reference filter settled.\n\t\t */\n\t\tasync loadReferenceOptions() {\n\t\t\tconst pending = this.schemaFilters.filter((filter) => filter.type === 'reference'\n\t\t\t\t&& filter.optionsSource\n\t\t\t\t&& this.referenceOptions[filter.key] === undefined\n\t\t\t\t&& this.referenceLoading[filter.key] !== true)\n\t\t\tif (pending.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\timport('@nextcloud/router'),\n\t\t\t])\n\n\t\t\tawait Promise.all(pending.map(async (filter) => {\n\t\t\t\tconst source = filter.optionsSource\n\t\t\t\tif (!source.register || !source.schema) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tthis.referenceLoading = { ...this.referenceLoading, [filter.key]: true }\n\t\t\t\ttry {\n\t\t\t\t\tconst url = generateUrl('/apps/openregister/api/objects/{register}/{schema}', {\n\t\t\t\t\t\tregister: source.register,\n\t\t\t\t\t\tschema: source.schema,\n\t\t\t\t\t})\n\t\t\t\t\tconst response = await axios.get(url, { params: { _limit: source.limit || 200 } })\n\t\t\t\t\tconst rows = response?.data?.results || response?.data || []\n\t\t\t\t\tconst valueField = source.valueField || '@self.uuid'\n\t\t\t\t\tconst labelField = source.labelField || 'title'\n\t\t\t\t\tconst options = rows\n\t\t\t\t\t\t.map((row) => ({\n\t\t\t\t\t\t\tid: this.readPath(row, valueField),\n\t\t\t\t\t\t\tlabel: String(this.readPath(row, labelField) ?? this.readPath(row, valueField) ?? ''),\n\t\t\t\t\t\t}))\n\t\t\t\t\t\t.filter((option) => option.id !== null && option.id !== undefined && option.id !== '')\n\t\t\t\t\t\t.sort((a, b) => a.label.localeCompare(b.label))\n\t\t\t\t\tthis.referenceOptions = { ...this.referenceOptions, [filter.key]: options }\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.error(`[CnIndexSidebar] the reference filter \"${filter.key}\" could not load its options`, error)\n\t\t\t\t\tthis.referenceOptions = { ...this.referenceOptions, [filter.key]: [] }\n\t\t\t\t} finally {\n\t\t\t\t\tthis.referenceLoading = { ...this.referenceLoading, [filter.key]: false }\n\t\t\t\t}\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Read a dotted path off a row (`@self.uuid`, `title`).\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {string} path The dotted path.\n\t\t *\n\t\t * @return {unknown} The value, or undefined.\n\t\t */\n\t\treadPath(row, path) {\n\t\t\treturn String(path).split('.').reduce((acc, part) => ((acc === null || acc === undefined) ? acc : acc[part]), row)\n\t\t},\n\n\t\t/**\n\t\t * Get currently selected options for a filter\n\t\t *\n\t\t * @param {object} filter Filter object\n\t\t */\n\t\tgetSelectedFilterOptions(filter) {\n\t\t\tconst value = this.activeFilters[filter.key]\n\t\t\tif (!value) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst values = Array.isArray(value) ? value : [value]\n\t\t\tconst options = this.getFilterOptions(filter)\n\t\t\treturn values.map((v) => options.find((o) => o.id === v) || { id: v, label: String(v) })\n\t\t},\n\n\t\t/**\n\t\t * Handle filter select change\n\t\t *\n\t\t * @param {string} key Filter key\n\t\t * @param {Array} selected Selected values\n\t\t */\n\t\tonFilterChange(key, selected) {\n\t\t\t// 🔴 A SINGLE-VALUED SELECT EMITS AN OBJECT, NOT AN ARRAY. NcSelect\n\t\t\t// changes the SHAPE of its payload with `multiple`, and `.map` on\n\t\t\t// the object shape throws inside an event handler, where Vue logs\n\t\t\t// it and carries on: the picker looks inert and the console says\n\t\t\t// why in a place nobody is looking.\n\t\t\tconst chosen = Array.isArray(selected) ? selected : (selected ? [selected] : [])\n\t\t\tconst values = chosen.map((o) => ((o && typeof o === 'object' && 'id' in o) ? o.id : o))\n\t\t\tthis.$emit('filter-change', { key, values })\n\t\t},\n\n\t\t/**\n\t\t * \"Clear all\" click: reset search and every active facet filter in\n\t\t * one shot, so the parent does one fetch instead of one per field.\n\t\t */\n\t\tonClearAll() {\n\t\t\t/**\n\t\t\t * @event clear-filters \"Clear all\" clicked; reset search and every active filter.\n\t\t\t */\n\t\t\tthis.$emit('clear-filters')\n\t\t},\n\t},\n}\n</script>\n\n<!-- Styles in css/index-sidebar.css -->\n"],"names":["_createBlock","_createVNode","_createElementVNode","_openBlock","_createElementBlock","_renderSlot","_toDisplayString","_createTextVNode","_Fragment","_renderList","_normalizeClass","_withModifiers"],"mappings":"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"}
@@ -2,7 +2,7 @@ import script from './CnNcWidgetWidget.vue2.js';
2
2
  import { render } from './CnNcWidgetWidget.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-f553a198";
5
+ script.__scopeId = "data-v-6d5d59a8";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -46,7 +46,10 @@ var script = {
46
46
 
47
47
  props: {
48
48
  /**
49
- * Persisted widget content `{widgetId, displayMode, limit?, showAllUrl?, showAllLabel?, showHeader?}`.
49
+ * Persisted widget content `{widgetId, displayMode, limit?, showAllUrl?, showAllLabel?, showHeader?, excludeApps?, excludeTypes?}`.
50
+ * `excludeApps` (`["systemtags"]`) and `excludeTypes` leave out the
51
+ * items of those apps or types (an item's own `app` / `type`, else the
52
+ * app in its link or icon URL); the list then comes from the items API.
50
53
  * `showHeader: false` drops the widget's own header (icon and title);
51
54
  * it is dropped too when the hosting card draws a title row.
52
55
  * `limit` is the most items shown (the list then comes from the items
@@ -174,7 +177,38 @@ var script = {
174
177
  * @return {object[]} the items.
175
178
  */
176
179
  shownItems() {
177
- return this.itemLimit > 0 ? this.items.slice(0, this.itemLimit) : this.items
180
+ const kept = this.hasExclusions ? this.items.filter((item) => !this.isExcluded(item)) : this.items;
181
+ return this.itemLimit > 0 ? kept.slice(0, this.itemLimit) : kept
182
+ },
183
+
184
+ /**
185
+ * The apps and item types `content.excludeApps` / `content.excludeTypes`
186
+ * leave out, lower-cased.
187
+ *
188
+ * @spec openspec/changes/nc-widget-exclude-apps/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-can-leave-out-items-of-an-app-or-type
189
+ * @return {{apps: string[], types: string[]}}
190
+ */
191
+ exclusions() {
192
+ const list = (value) => (Array.isArray(value) ? value : (typeof value === 'string' && value !== '' ? [value] : []))
193
+ .filter((entry) => typeof entry === 'string' && entry !== '')
194
+ .map((entry) => entry.toLowerCase());
195
+ return { apps: list(this.content && this.content.excludeApps), types: list(this.content && this.content.excludeTypes) }
196
+ },
197
+
198
+ /**
199
+ * How many items to ask the API for: the limit (or the default), and
200
+ * more while items are left out, so a filtered list still fills it.
201
+ *
202
+ * @return {number}
203
+ */
204
+ requestLimit() {
205
+ const base = this.itemLimit > 0 ? this.itemLimit : API_ITEM_LIMIT;
206
+ return this.hasExclusions ? Math.max(base * 3, 20) : base
207
+ },
208
+
209
+ /** @return {boolean} Whether any app or type is left out. */
210
+ hasExclusions() {
211
+ return this.exclusions.apps.length > 0 || this.exclusions.types.length > 0
178
212
  },
179
213
 
180
214
  /**
@@ -226,6 +260,34 @@ var script = {
226
260
  },
227
261
 
228
262
  methods: {
263
+ /**
264
+ * Whether an item belongs to an app or type the content leaves out: its
265
+ * own `app` / `type` / `objectType`, else the app in an `/apps/<app>/`
266
+ * part of its link or icons.
267
+ *
268
+ * @spec openspec/changes/nc-widget-exclude-apps/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-can-leave-out-items-of-an-app-or-type
269
+ * @param {object} item A widget item.
270
+ * @return {boolean}
271
+ */
272
+ isExcluded(item) {
273
+ if (!item || typeof item !== 'object') {
274
+ return false
275
+ }
276
+ const { apps, types } = this.exclusions;
277
+ const own = (value) => (typeof value === 'string' ? value.toLowerCase() : '');
278
+ const appsOf = [own(item.app)];
279
+ for (const url of [item.link, item.iconUrl, item.overlayIconUrl]) {
280
+ const match = typeof url === 'string' ? url.match(/\/apps\/([a-z0-9_-]+)\//i) : null;
281
+ if (match) {
282
+ appsOf.push(match[1].toLowerCase());
283
+ }
284
+ }
285
+ if (apps.length > 0 && appsOf.some((app) => app !== '' && apps.includes(app))) {
286
+ return true
287
+ }
288
+ return types.length > 0 && [own(item.type), own(item.objectType)].some((type) => type !== '' && types.includes(type))
289
+ },
290
+
229
291
  t: translate,
230
292
 
231
293
  /**
@@ -248,7 +310,8 @@ var script = {
248
310
  // where the widget has a registered native callback.
249
311
  // A `limit` also takes the API list first: the native callback paints
250
312
  // as many items as it likes. Its fallback to native stays.
251
- if (this.displayMode !== 'horizontal' && this.itemLimit === 0) {
313
+ // Leaving items out works on the API list only, so it skips native too.
314
+ if (this.displayMode !== 'horizontal' && this.itemLimit === 0 && !this.hasExclusions) {
252
315
  const callback = this.resolveNativeCallback();
253
316
  if (typeof callback === 'function') {
254
317
  this.mountNative(callback);
@@ -333,7 +396,7 @@ var script = {
333
396
  // both the flat-array (older providers) and `{items}` (v2) shapes.
334
397
  const url = generateOcsUrl('/apps/dashboard/api/v2/widget-items');
335
398
  const response = await axios__default.get(url, {
336
- params: { widgets: [this.widgetId], limit: this.itemLimit > 0 ? this.itemLimit : API_ITEM_LIMIT },
399
+ params: { widgets: [this.widgetId], limit: this.requestLimit },
337
400
  });
338
401
  const data = response && response.data && response.data.ocs ? response.data.ocs.data : null;
339
402
  const widgetData = data ? data[this.widgetId] : null;
@@ -1 +1 @@
1
- {"version":3,"file":"CnNcWidgetWidget.vue2.js","sources":["../../../../src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-nc-widget-widget\" :class=\"{ 'cn-nc-widget-widget--horizontal': displayMode === 'horizontal' }\">\n\t\t<header v-if=\"showsHeader\" class=\"cn-nc-widget-widget__header\" data-testid=\"cn-nc-widget-header\">\n\t\t\t<img\n\t\t\t\tv-if=\"widgetIconUrl\"\n\t\t\t\tclass=\"cn-nc-widget-widget__header-icon\"\n\t\t\t\t:src=\"widgetIconUrl\"\n\t\t\t\talt=\"\">\n\t\t\t<span class=\"cn-nc-widget-widget__header-title\">{{ widgetTitle }}</span>\n\t\t</header>\n\n\t\t<!--\n\t\t\tNative callback container — always present but hidden until the\n\t\t\tOCA.Dashboard callback mounts into it. Keeping it mounted avoids a\n\t\t\tflicker when the native path wins after the API list has painted.\n\n\t\t\tThe `--horizontal` reskin class lives on the ROOT element, not here:\n\t\t\tnative widget callbacks mount via `new Vue(...).$mount(el)`, which\n\t\t\tREPLACES this element in the live DOM with the callback's own root\n\t\t\tnode — any class we put directly on it is discarded along with the\n\t\t\telement itself, so it can never appear in the rendered page.\n\t\t-->\n\t\t<div\n\t\t\tv-show=\"mode === 'native'\"\n\t\t\tref=\"nativeContainer\"\n\t\t\tclass=\"cn-nc-widget-widget__native\" />\n\n\t\t<div\n\t\t\tv-if=\"mode !== 'native'\"\n\t\t\tclass=\"cn-nc-widget-widget__body\"\n\t\t\t:class=\"bodyClass\">\n\t\t\t<div v-if=\"loading\" class=\"cn-nc-widget-widget__state\">\n\t\t\t\t{{ t('nextcloud-vue', 'Loading…') }}\n\t\t\t</div>\n\n\t\t\t<div v-else-if=\"!widgetId\" class=\"cn-nc-widget-widget__state\">\n\t\t\t\t{{ t('nextcloud-vue', 'No widget selected') }}\n\t\t\t</div>\n\n\t\t\t<div v-else-if=\"unsupported\" class=\"cn-nc-widget-widget__state\" data-testid=\"nc-widget-unsupported\">\n\t\t\t\t{{ t('nextcloud-vue', 'This widget can only be shown on the Nextcloud dashboard itself.') }}\n\t\t\t</div>\n\n\t\t\t<div v-else-if=\"items.length === 0\" class=\"cn-nc-widget-widget__state\">\n\t\t\t\t{{ t('nextcloud-vue', 'No items available') }}\n\t\t\t</div>\n\n\t\t\t<template v-else>\n\t\t\t\t<a\n\t\t\t\t\tv-for=\"(item, idx) in shownItems\"\n\t\t\t\t\t:key=\"item.sinceId || item.id || idx\"\n\t\t\t\t\tclass=\"cn-nc-widget-widget__item\"\n\t\t\t\t\t:class=\"itemClass\"\n\t\t\t\t\t:href=\"item.link || '#'\"\n\t\t\t\t\t:title=\"item.title\">\n\t\t\t\t\t<span class=\"cn-nc-widget-widget__item-icon-wrap\">\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-if=\"item.iconUrl\"\n\t\t\t\t\t\t\tclass=\"cn-nc-widget-widget__item-icon\"\n\t\t\t\t\t\t\t:src=\"item.iconUrl\"\n\t\t\t\t\t\t\talt=\"\">\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-if=\"item.overlayIconUrl\"\n\t\t\t\t\t\t\tclass=\"cn-nc-widget-widget__item-overlay\"\n\t\t\t\t\t\t\t:src=\"item.overlayIconUrl\"\n\t\t\t\t\t\t\talt=\"\">\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-nc-widget-widget__item-text\">\n\t\t\t\t\t\t<span class=\"cn-nc-widget-widget__item-title\">{{ item.title }}</span>\n\t\t\t\t\t\t<span v-if=\"item.subtitle\" class=\"cn-nc-widget-widget__item-subtitle\">{{ item.subtitle }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t</a>\n\t\t\t\t<!-- With a `limit`, the rest is one link away (`showAllUrl`, else the widget's own page). -->\n\t\t\t\t<a\n\t\t\t\t\tv-if=\"showAllHref\"\n\t\t\t\t\tclass=\"cn-nc-widget-widget__show-all\"\n\t\t\t\t\tdata-testid=\"nc-widget-show-all\"\n\t\t\t\t\t:href=\"showAllHref\">\n\t\t\t\t\t{{ showAllLabel }}\n\t\t\t\t</a>\n\t\t\t</template>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateOcsUrl } from '@nextcloud/router'\n\nconst API_ITEM_LIMIT = 7\n\n/**\n * Read the global `OCA.Dashboard` registry without assuming it exists.\n *\n * @return {object|null} the `OCA.Dashboard` object, or `null` when absent.\n */\nfunction getDashboardGlobal() {\n\tif (typeof window === 'undefined') {\n\t\treturn null\n\t}\n\tconst oca = window.OCA\n\treturn oca && oca.Dashboard ? oca.Dashboard : null\n}\n\n/**\n * CnNcWidgetWidget — proxies any native Nextcloud Dashboard widget into a\n * dashboard grid cell.\n *\n * Two-mode rendering (decoupling seam — reads NC directly, no app bridge):\n * - **native** — when the widget bundle has registered a callback on the\n * global `OCA.Dashboard` (`getWidget(id)` / `widgets[id]`), the callback is\n * handed the render container and paints itself (native fast-path).\n * - **api** — otherwise the OCS Dashboard endpoint\n * `/apps/dashboard/api/v{1,2}/widget-items` is fetched directly via\n * `@nextcloud/axios` and a flat item list is rendered.\n *\n * The header title + icon come from the dashboard widget metadata\n * (`OCA.Dashboard` registry, falling back to the configured `widgetId`). When\n * no `widgetId` is configured the widget renders an empty state and never hits\n * the network.\n *\n * @spec openspec/changes/cn-widget-library/specs/cn-widget-library/spec.md\n */\nexport default {\n\tname: 'CnNcWidgetWidget',\n\n\tinject: {\n\t\t/** Whether the hosting card draws a title row (CnWidgetWrapper). */\n\t\tcnWidgetTitled: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted widget content `{widgetId, displayMode, limit?, showAllUrl?, showAllLabel?, showHeader?}`.\n\t\t * `showHeader: false` drops the widget's own header (icon and title);\n\t\t * it is dropped too when the hosting card draws a title row.\n\t\t * `limit` is the most items shown (the list then comes from the items\n\t\t * API, so it fits its cell); `showAllUrl` / `showAllLabel` the link to\n\t\t * the rest (default the widget's own page and \"Show all\").\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\t/** @type {'pending'|'native'|'api'} the resolved mounting mode. */\n\t\t\tmode: 'pending',\n\t\t\t/**\n\t\t\t * Whether the items API has no entry for this widget at all.\n\t\t\t *\n\t\t\t * Not the same as an empty list. A widget whose provider implements\n\t\t\t * only `IWidget` (no `IAPIWidget`/`IAPIWidgetV2`) declares\n\t\t\t * `itemApiVersions: []` and is simply ABSENT from the widget-items\n\t\t\t * response, while a widget with nothing to show right now comes\n\t\t\t * back as its own key holding an empty list. The Tasks app's widget\n\t\t\t * is the first kind: with no native callback registered on the page\n\t\t\t * it can never render a single item here, and saying \"No items\n\t\t\t * available\" under it told the reader their task list was empty.\n\t\t\t *\n\t\t\t * @type {boolean}\n\t\t\t */\n\t\t\tunsupported: false,\n\t\t\tloading: false,\n\t\t\titems: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The configured native widget id.\n\t\t *\n\t\t * @return {string} the widget id (empty when unset).\n\t\t */\n\t\twidgetId() {\n\t\t\treturn typeof (this.content && this.content.widgetId) === 'string' ? this.content.widgetId : ''\n\t\t},\n\n\t\t/**\n\t\t * The item list orientation.\n\t\t *\n\t\t * @return {string} `horizontal` or `vertical`.\n\t\t */\n\t\tdisplayMode() {\n\t\t\treturn (this.content && this.content.displayMode) === 'horizontal' ? 'horizontal' : 'vertical'\n\t\t},\n\n\t\t/**\n\t\t * The native widget metadata from the `OCA.Dashboard` global.\n\t\t *\n\t\t * @return {object|null} the widget metadata, or `null`.\n\t\t */\n\t\twidgetMeta() {\n\t\t\tconst dashboard = getDashboardGlobal()\n\t\t\tif (!dashboard || !this.widgetId) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof dashboard.getWidget === 'function') {\n\t\t\t\treturn dashboard.getWidget(this.widgetId) || null\n\t\t\t}\n\t\t\tif (dashboard.widgets && typeof dashboard.widgets === 'object') {\n\t\t\t\treturn dashboard.widgets[this.widgetId] || null\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget draws its own header: not with\n\t\t * `content.showHeader: false`, nor inside a card that draws a title.\n\t\t *\n\t\t * @spec openspec/changes/nc-widget-header/specs/nc-widget-header/spec.md#requirement-a-nextcloud-widget-draws-no-second-heading\n\t\t * @return {boolean}\n\t\t */\n\t\tshowsHeader() {\n\t\t\tif (this.content && this.content.showHeader === false) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !(typeof this.cnWidgetTitled === 'function' && this.cnWidgetTitled())\n\t\t},\n\n\t\t/**\n\t\t * The header title.\n\t\t *\n\t\t * @return {string} the title.\n\t\t */\n\t\twidgetTitle() {\n\t\t\treturn (this.widgetMeta && this.widgetMeta.title) || this.widgetId || t('nextcloud-vue', 'Widget')\n\t\t},\n\n\t\t/**\n\t\t * The header icon URL.\n\t\t *\n\t\t * @return {string} the icon URL (empty when none).\n\t\t */\n\t\twidgetIconUrl() {\n\t\t\treturn (this.widgetMeta && this.widgetMeta.iconUrl) || ''\n\t\t},\n\n\t\t/**\n\t\t * The most items the list shows (`content.limit`), or 0 for no limit.\n\t\t * A limit lets the widget fit a dashboard cell instead of scrolling\n\t\t * inside it.\n\t\t *\n\t\t * @spec openspec/changes/screens-nc-widget-limit/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-shows-at-most-its-limit\n\t\t * @return {number} the limit.\n\t\t */\n\t\titemLimit() {\n\t\t\tconst limit = Number(this.content && this.content.limit)\n\t\t\treturn Number.isInteger(limit) && limit > 0 ? limit : 0\n\t\t},\n\n\t\t/**\n\t\t * The items drawn: at most `itemLimit`.\n\t\t *\n\t\t * @return {object[]} the items.\n\t\t */\n\t\tshownItems() {\n\t\t\treturn this.itemLimit > 0 ? this.items.slice(0, this.itemLimit) : this.items\n\t\t},\n\n\t\t/**\n\t\t * Where \"Show all\" goes: `content.showAllUrl`, else the page the widget\n\t\t * names itself (its `url`). Only with a limit; '' for no link.\n\t\t *\n\t\t * @spec openspec/changes/screens-nc-widget-limit/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-shows-at-most-its-limit\n\t\t * @return {string} the URL.\n\t\t */\n\t\tshowAllHref() {\n\t\t\tif (this.itemLimit === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst own = this.content && typeof this.content.showAllUrl === 'string' ? this.content.showAllUrl : ''\n\t\t\treturn own || (this.widgetMeta && typeof this.widgetMeta.url === 'string' ? this.widgetMeta.url : '')\n\t\t},\n\n\t\t/**\n\t\t * The \"Show all\" text (`content.showAllLabel`, else the library's).\n\t\t *\n\t\t * @return {string} the label.\n\t\t */\n\t\tshowAllLabel() {\n\t\t\tconst label = this.content && this.content.showAllLabel\n\t\t\treturn typeof label === 'string' && label !== '' ? label : t('nextcloud-vue', 'Show all')\n\t\t},\n\n\t\t/**\n\t\t * The body orientation CSS modifier class.\n\t\t *\n\t\t * @return {string} the body class.\n\t\t */\n\t\tbodyClass() {\n\t\t\treturn `cn-nc-widget-widget__body--${this.displayMode}`\n\t\t},\n\n\t\t/**\n\t\t * The item orientation CSS modifier class.\n\t\t *\n\t\t * @return {string} the item class.\n\t\t */\n\t\titemClass() {\n\t\t\treturn `cn-nc-widget-widget__item--${this.displayMode}`\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.tryMount()\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Resolve the mounting mode. Prefers the native `OCA.Dashboard`\n\t\t * callback fast-path; otherwise falls back to the OCS item list.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\ttryMount() {\n\t\t\tif (!this.widgetId) {\n\t\t\t\tthis.mode = 'api'\n\t\t\t\tthis.items = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// The native callback paints its own opaque markup, so `displayMode`\n\t\t\t// (bodyClass/itemClass below) has no effect on it — only the API\n\t\t\t// item list honours the vertical/horizontal setting. Horizontal mode\n\t\t\t// must therefore skip the native fast-path, or the \"Horizontal\n\t\t\t// (cards)\" option would silently do nothing for the (common) case\n\t\t\t// where the widget has a registered native callback.\n\t\t\t// A `limit` also takes the API list first: the native callback paints\n\t\t\t// as many items as it likes. Its fallback to native stays.\n\t\t\tif (this.displayMode !== 'horizontal' && this.itemLimit === 0) {\n\t\t\t\tconst callback = this.resolveNativeCallback()\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tthis.mountNative(callback)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.mode = 'api'\n\t\t\tthis.loadApiItems()\n\t\t},\n\n\t\t/**\n\t\t * Look up a native render callback on the `OCA.Dashboard` global.\n\t\t *\n\t\t * @return {((el: HTMLElement, ctx: {widget: object}) => unknown)|null} the callback, or `null` when none is registered.\n\t\t */\n\t\tresolveNativeCallback() {\n\t\t\tconst dashboard = getDashboardGlobal()\n\t\t\tif (!dashboard) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (this.widgetMeta && typeof this.widgetMeta.callback === 'function') {\n\t\t\t\treturn this.widgetMeta.callback\n\t\t\t}\n\t\t\tif (dashboard.callbacks && typeof dashboard.callbacks[this.widgetId] === 'function') {\n\t\t\t\treturn dashboard.callbacks[this.widgetId]\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * Mount the widget natively by invoking its registered callback with\n\t\t * our render container.\n\t\t *\n\t\t * @param {(el: HTMLElement, ctx: {widget: object}) => unknown} callback the native render callback.\n\t\t * @return {void}\n\t\t */\n\t\tmountNative(callback) {\n\t\t\tthis.mode = 'native'\n\t\t\tthis.$nextTick(() => {\n\t\t\t\tconst container = this.$refs.nativeContainer\n\t\t\t\tif (!container) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// Native callback failed — fall back to the API list.\n\t\t\t\tconst fallback = () => {\n\t\t\t\t\tthis.mode = 'api'\n\t\t\t\t\tthis.loadApiItems()\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\t// NC dashboard widgets are registered as\n\t\t\t\t\t// `register(id, (el, { widget }) => …)` — the second argument\n\t\t\t\t\t// MUST be the `{ widget }` envelope, not the bare metadata, or\n\t\t\t\t\t// the widget destructures `widget` as undefined and throws on\n\t\t\t\t\t// first use (e.g. `widget.title`).\n\t\t\t\t\tconst result = callback(container, { widget: this.widgetMeta || {} })\n\t\t\t\t\t// Most widget callbacks are async; a synchronous try/catch\n\t\t\t\t\t// can't see a rejected promise, so wire the fallback to it too.\n\t\t\t\t\tif (result && typeof result.then === 'function') {\n\t\t\t\t\t\tresult.catch(fallback)\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tfallback()\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Fetch the API fallback list directly from the OCS Dashboard\n\t\t * endpoint. Malformed or failed responses collapse to an empty list\n\t\t * (the empty state) instead of throwing.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadApiItems() {\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\t// The v2 widget-items API only returns an entry for widgets\n\t\t\t\t// whose server-side provider implements `IAPIWidgetV2` — plenty\n\t\t\t\t// of native dashboard widgets are JS-callback-only (`IWidget`)\n\t\t\t\t// and never appear in this response at all, which looks\n\t\t\t\t// identical to \"0 items\" from here. extractItems() tolerates\n\t\t\t\t// both the flat-array (older providers) and `{items}` (v2) shapes.\n\t\t\t\tconst url = generateOcsUrl('/apps/dashboard/api/v2/widget-items')\n\t\t\t\tconst response = await axios.get(url, {\n\t\t\t\t\tparams: { widgets: [this.widgetId], limit: this.itemLimit > 0 ? this.itemLimit : API_ITEM_LIMIT },\n\t\t\t\t})\n\t\t\t\tconst data = response && response.data && response.data.ocs ? response.data.ocs.data : null\n\t\t\t\tconst widgetData = data ? data[this.widgetId] : null\n\t\t\t\tthis.items = this.extractItems(widgetData)\n\t\t\t\t// Only a SUCCESSFUL response can say the widget is absent. A\n\t\t\t\t// failed request says nothing about the widget, so it keeps\n\t\t\t\t// the ordinary empty state rather than a claim about the app.\n\t\t\t\tthis.unsupported = data !== null && (widgetData === null || widgetData === undefined)\n\t\t\t} catch {\n\t\t\t\tthis.items = []\n\t\t\t\tthis.unsupported = false\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\n\t\t\t// Horizontal mode deliberately skips the native fast-path (see\n\t\t\t// tryMount()) to get the styled card layout. But when the API has\n\t\t\t// no entry for this widget at all — no `IAPIWidgetV2` support, not\n\t\t\t// \"no items right now\" — that would render a false empty state for\n\t\t\t// a widget that actually has content. Fall back to native\n\t\t\t// rendering rather than lying about there being nothing to show.\n\t\t\tif (this.items.length === 0) {\n\t\t\t\tconst callback = this.resolveNativeCallback()\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tthis.mountNative(callback)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Normalise a per-widget OCS payload to an items array, tolerating both\n\t\t * the flat array and the `{items}` envelope shapes.\n\t\t *\n\t\t * @param {unknown} widgetData the per-widget payload.\n\t\t * @return {object[]} the items array (possibly empty).\n\t\t */\n\t\textractItems(widgetData) {\n\t\t\tif (!widgetData) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tif (Array.isArray(widgetData)) {\n\t\t\t\treturn widgetData\n\t\t\t}\n\t\t\tif (Array.isArray(widgetData.items)) {\n\t\t\t\treturn widgetData.items\n\t\t\t}\n\t\t\tif (widgetData.items && typeof widgetData.items === 'object') {\n\t\t\t\treturn Object.values(widgetData.items)\n\t\t\t}\n\t\t\treturn []\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-nc-widget-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\twidth: 100%;\n\theight: 100%;\n\toverflow: hidden;\n}\n\n/*\n * Header + content match the native Nextcloud Dashboard panel (apps/dashboard)\n * exactly — this component's whole job is rendering NC dashboard widgets, so it\n * should look native by default: 16px header, 32px leading icon with a 16px\n * gap, a 20px/700 title, and the native panel content inset (16px sides +\n * bottom, flush to the header on top). Same design tokens as core; overridable\n * via the host's CnWidgetWrapper styleConfig / nldesign.\n */\n.cn-nc-widget-widget__header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 16px;\n\tpadding: 16px;\n\tfont-weight: 700;\n}\n\n.cn-nc-widget-widget__header-icon {\n\twidth: 32px;\n\theight: 32px;\n\tflex: 0 0 auto;\n}\n\n.cn-nc-widget-widget__header-title {\n\tflex: 1;\n\tfont-size: 20px;\n\tfont-weight: 700;\n\tline-height: 24px;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-nc-widget-widget__show-all {\n\talign-self: flex-start;\n\tpadding: 8px 0 0;\n\tcolor: var(--color-primary-element);\n\tfont-weight: 600;\n\ttext-decoration: none;\n}\n\n.cn-nc-widget-widget__show-all:hover,\n.cn-nc-widget-widget__show-all:focus-visible {\n\ttext-decoration: underline;\n}\n\n.cn-nc-widget-widget__native {\n\tflex: 1;\n\toverflow: auto;\n\tpadding: 0 16px 16px;\n}\n\n/*\n * The native `OCA.Dashboard` callback paints its own markup we don't control\n * — for first-party widgets that's almost always `@nextcloud/vue`'s\n * `NcDashboardWidget` / `NcDashboardWidgetItem` (`.dashboard-widget` wrapping\n * a bare `<ul>`/`<li>` list, each item a `.item-list__entry`).\n *\n * Only the LIST CONTAINER is retiled into a grid here — `.item-list__entry`'s\n * own internal layout is left untouched. An earlier version of this override\n * also forced `.item-list__entry` from row to column, but its icon-overlay\n * badge (`.item-icon`, see @nextcloud/vue's NcDashboardWidgetItem CSS) is\n * positioned with negative margins calibrated for the row layout, so\n * flipping to column made items visually overlap. Tiling the `<li>`s into a\n * grid while each entry keeps its normal icon+text row reads as a grid of\n * card tiles without touching that internal math.\n *\n * Scoped from `.cn-nc-widget-widget--horizontal` on the ROOT element, not\n * `.cn-nc-widget-widget__native`: the callback mounts via `.$mount(el)`,\n * which replaces `nativeContainer` in the live DOM outright, so any class\n * placed directly on it never survives to be selectable.\n *\n * The 250px column floor matches `.item-list__entry`'s own natural minimum\n * width (avatar + padding + its un-truncatable-below-this content) — a grid\n * track narrower than that squeezes the entry below its real minimum and it\n * overflows into the neighbouring cell. `min-width: 0` on the `<li>` alone\n * isn't enough to shrink it further: the item's own internal flex layout\n * still claims that much room regardless of the grid track size, so the\n * track itself must not go below it.\n */\n.cn-nc-widget-widget--horizontal :deep(.dashboard-widget > ul) {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n\tgap: 8px;\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-nc-widget-widget--horizontal :deep(.dashboard-widget > ul > li) {\n\twidth: auto;\n\tmin-width: 0;\n}\n\n.cn-nc-widget-widget--horizontal :deep(.item-list__entry) {\n\theight: 100%;\n\tmargin: 0;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n}\n\n.cn-nc-widget-widget__body {\n\tflex: 1;\n\toverflow: auto;\n\tpadding: 0 16px 16px;\n}\n\n.cn-nc-widget-widget__body--vertical {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-nc-widget-widget__body--horizontal {\n\tdisplay: flex;\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\tgap: 12px;\n}\n\n.cn-nc-widget-widget__state {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tflex: 1;\n\tmin-height: 64px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-style: italic;\n}\n\n.cn-nc-widget-widget__item {\n\tdisplay: flex;\n\ttext-decoration: none;\n\tcolor: var(--color-main-text);\n\tborder-radius: var(--border-radius);\n\tpadding: 4px;\n}\n\n.cn-nc-widget-widget__item:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-nc-widget-widget__item--vertical {\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-nc-widget-widget__item--horizontal {\n\tflex-direction: column;\n\talign-items: center;\n\twidth: 120px;\n\ttext-align: center;\n}\n\n.cn-nc-widget-widget__item-icon-wrap {\n\twidth: 32px;\n\theight: 32px;\n\tflex: 0 0 32px;\n\tposition: relative;\n}\n\n.cn-nc-widget-widget__item-icon {\n\twidth: 32px;\n\theight: 32px;\n\tobject-fit: cover;\n\tborder-radius: 50%;\n}\n\n.cn-nc-widget-widget__item-overlay {\n\tposition: absolute;\n\tright: -2px;\n\tbottom: -2px;\n\twidth: 14px;\n\theight: 14px;\n}\n\n.cn-nc-widget-widget__item-text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1;\n}\n\n.cn-nc-widget-widget__item-title {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-nc-widget-widget__item-subtitle {\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["t","axios"],"mappings":"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"}
1
+ {"version":3,"file":"CnNcWidgetWidget.vue2.js","sources":["../../../../src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-nc-widget-widget\" :class=\"{ 'cn-nc-widget-widget--horizontal': displayMode === 'horizontal' }\">\n\t\t<header v-if=\"showsHeader\" class=\"cn-nc-widget-widget__header\" data-testid=\"cn-nc-widget-header\">\n\t\t\t<img\n\t\t\t\tv-if=\"widgetIconUrl\"\n\t\t\t\tclass=\"cn-nc-widget-widget__header-icon\"\n\t\t\t\t:src=\"widgetIconUrl\"\n\t\t\t\talt=\"\">\n\t\t\t<span class=\"cn-nc-widget-widget__header-title\">{{ widgetTitle }}</span>\n\t\t</header>\n\n\t\t<!--\n\t\t\tNative callback container — always present but hidden until the\n\t\t\tOCA.Dashboard callback mounts into it. Keeping it mounted avoids a\n\t\t\tflicker when the native path wins after the API list has painted.\n\n\t\t\tThe `--horizontal` reskin class lives on the ROOT element, not here:\n\t\t\tnative widget callbacks mount via `new Vue(...).$mount(el)`, which\n\t\t\tREPLACES this element in the live DOM with the callback's own root\n\t\t\tnode — any class we put directly on it is discarded along with the\n\t\t\telement itself, so it can never appear in the rendered page.\n\t\t-->\n\t\t<div\n\t\t\tv-show=\"mode === 'native'\"\n\t\t\tref=\"nativeContainer\"\n\t\t\tclass=\"cn-nc-widget-widget__native\" />\n\n\t\t<div\n\t\t\tv-if=\"mode !== 'native'\"\n\t\t\tclass=\"cn-nc-widget-widget__body\"\n\t\t\t:class=\"bodyClass\">\n\t\t\t<div v-if=\"loading\" class=\"cn-nc-widget-widget__state\">\n\t\t\t\t{{ t('nextcloud-vue', 'Loading…') }}\n\t\t\t</div>\n\n\t\t\t<div v-else-if=\"!widgetId\" class=\"cn-nc-widget-widget__state\">\n\t\t\t\t{{ t('nextcloud-vue', 'No widget selected') }}\n\t\t\t</div>\n\n\t\t\t<div v-else-if=\"unsupported\" class=\"cn-nc-widget-widget__state\" data-testid=\"nc-widget-unsupported\">\n\t\t\t\t{{ t('nextcloud-vue', 'This widget can only be shown on the Nextcloud dashboard itself.') }}\n\t\t\t</div>\n\n\t\t\t<div v-else-if=\"shownItems.length === 0\" class=\"cn-nc-widget-widget__state\">\n\t\t\t\t{{ t('nextcloud-vue', 'No items available') }}\n\t\t\t</div>\n\n\t\t\t<template v-else>\n\t\t\t\t<a\n\t\t\t\t\tv-for=\"(item, idx) in shownItems\"\n\t\t\t\t\t:key=\"item.sinceId || item.id || idx\"\n\t\t\t\t\tclass=\"cn-nc-widget-widget__item\"\n\t\t\t\t\t:class=\"itemClass\"\n\t\t\t\t\t:href=\"item.link || '#'\"\n\t\t\t\t\t:title=\"item.title\">\n\t\t\t\t\t<span class=\"cn-nc-widget-widget__item-icon-wrap\">\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-if=\"item.iconUrl\"\n\t\t\t\t\t\t\tclass=\"cn-nc-widget-widget__item-icon\"\n\t\t\t\t\t\t\t:src=\"item.iconUrl\"\n\t\t\t\t\t\t\talt=\"\">\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\tv-if=\"item.overlayIconUrl\"\n\t\t\t\t\t\t\tclass=\"cn-nc-widget-widget__item-overlay\"\n\t\t\t\t\t\t\t:src=\"item.overlayIconUrl\"\n\t\t\t\t\t\t\talt=\"\">\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-nc-widget-widget__item-text\">\n\t\t\t\t\t\t<span class=\"cn-nc-widget-widget__item-title\">{{ item.title }}</span>\n\t\t\t\t\t\t<span v-if=\"item.subtitle\" class=\"cn-nc-widget-widget__item-subtitle\">{{ item.subtitle }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t</a>\n\t\t\t\t<!-- With a `limit`, the rest is one link away (`showAllUrl`, else the widget's own page). -->\n\t\t\t\t<a\n\t\t\t\t\tv-if=\"showAllHref\"\n\t\t\t\t\tclass=\"cn-nc-widget-widget__show-all\"\n\t\t\t\t\tdata-testid=\"nc-widget-show-all\"\n\t\t\t\t\t:href=\"showAllHref\">\n\t\t\t\t\t{{ showAllLabel }}\n\t\t\t\t</a>\n\t\t\t</template>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateOcsUrl } from '@nextcloud/router'\n\nconst API_ITEM_LIMIT = 7\n\n/**\n * Read the global `OCA.Dashboard` registry without assuming it exists.\n *\n * @return {object|null} the `OCA.Dashboard` object, or `null` when absent.\n */\nfunction getDashboardGlobal() {\n\tif (typeof window === 'undefined') {\n\t\treturn null\n\t}\n\tconst oca = window.OCA\n\treturn oca && oca.Dashboard ? oca.Dashboard : null\n}\n\n/**\n * CnNcWidgetWidget — proxies any native Nextcloud Dashboard widget into a\n * dashboard grid cell.\n *\n * Two-mode rendering (decoupling seam — reads NC directly, no app bridge):\n * - **native** — when the widget bundle has registered a callback on the\n * global `OCA.Dashboard` (`getWidget(id)` / `widgets[id]`), the callback is\n * handed the render container and paints itself (native fast-path).\n * - **api** — otherwise the OCS Dashboard endpoint\n * `/apps/dashboard/api/v{1,2}/widget-items` is fetched directly via\n * `@nextcloud/axios` and a flat item list is rendered.\n *\n * The header title + icon come from the dashboard widget metadata\n * (`OCA.Dashboard` registry, falling back to the configured `widgetId`). When\n * no `widgetId` is configured the widget renders an empty state and never hits\n * the network.\n *\n * @spec openspec/changes/cn-widget-library/specs/cn-widget-library/spec.md\n */\nexport default {\n\tname: 'CnNcWidgetWidget',\n\n\tinject: {\n\t\t/** Whether the hosting card draws a title row (CnWidgetWrapper). */\n\t\tcnWidgetTitled: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * Persisted widget content `{widgetId, displayMode, limit?, showAllUrl?, showAllLabel?, showHeader?, excludeApps?, excludeTypes?}`.\n\t\t * `excludeApps` (`[\"systemtags\"]`) and `excludeTypes` leave out the\n\t\t * items of those apps or types (an item's own `app` / `type`, else the\n\t\t * app in its link or icon URL); the list then comes from the items API.\n\t\t * `showHeader: false` drops the widget's own header (icon and title);\n\t\t * it is dropped too when the hosting card draws a title row.\n\t\t * `limit` is the most items shown (the list then comes from the items\n\t\t * API, so it fits its cell); `showAllUrl` / `showAllLabel` the link to\n\t\t * the rest (default the widget's own page and \"Show all\").\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\t/** @type {'pending'|'native'|'api'} the resolved mounting mode. */\n\t\t\tmode: 'pending',\n\t\t\t/**\n\t\t\t * Whether the items API has no entry for this widget at all.\n\t\t\t *\n\t\t\t * Not the same as an empty list. A widget whose provider implements\n\t\t\t * only `IWidget` (no `IAPIWidget`/`IAPIWidgetV2`) declares\n\t\t\t * `itemApiVersions: []` and is simply ABSENT from the widget-items\n\t\t\t * response, while a widget with nothing to show right now comes\n\t\t\t * back as its own key holding an empty list. The Tasks app's widget\n\t\t\t * is the first kind: with no native callback registered on the page\n\t\t\t * it can never render a single item here, and saying \"No items\n\t\t\t * available\" under it told the reader their task list was empty.\n\t\t\t *\n\t\t\t * @type {boolean}\n\t\t\t */\n\t\t\tunsupported: false,\n\t\t\tloading: false,\n\t\t\titems: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The configured native widget id.\n\t\t *\n\t\t * @return {string} the widget id (empty when unset).\n\t\t */\n\t\twidgetId() {\n\t\t\treturn typeof (this.content && this.content.widgetId) === 'string' ? this.content.widgetId : ''\n\t\t},\n\n\t\t/**\n\t\t * The item list orientation.\n\t\t *\n\t\t * @return {string} `horizontal` or `vertical`.\n\t\t */\n\t\tdisplayMode() {\n\t\t\treturn (this.content && this.content.displayMode) === 'horizontal' ? 'horizontal' : 'vertical'\n\t\t},\n\n\t\t/**\n\t\t * The native widget metadata from the `OCA.Dashboard` global.\n\t\t *\n\t\t * @return {object|null} the widget metadata, or `null`.\n\t\t */\n\t\twidgetMeta() {\n\t\t\tconst dashboard = getDashboardGlobal()\n\t\t\tif (!dashboard || !this.widgetId) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof dashboard.getWidget === 'function') {\n\t\t\t\treturn dashboard.getWidget(this.widgetId) || null\n\t\t\t}\n\t\t\tif (dashboard.widgets && typeof dashboard.widgets === 'object') {\n\t\t\t\treturn dashboard.widgets[this.widgetId] || null\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * Whether the widget draws its own header: not with\n\t\t * `content.showHeader: false`, nor inside a card that draws a title.\n\t\t *\n\t\t * @spec openspec/changes/nc-widget-header/specs/nc-widget-header/spec.md#requirement-a-nextcloud-widget-draws-no-second-heading\n\t\t * @return {boolean}\n\t\t */\n\t\tshowsHeader() {\n\t\t\tif (this.content && this.content.showHeader === false) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\treturn !(typeof this.cnWidgetTitled === 'function' && this.cnWidgetTitled())\n\t\t},\n\n\t\t/**\n\t\t * The header title.\n\t\t *\n\t\t * @return {string} the title.\n\t\t */\n\t\twidgetTitle() {\n\t\t\treturn (this.widgetMeta && this.widgetMeta.title) || this.widgetId || t('nextcloud-vue', 'Widget')\n\t\t},\n\n\t\t/**\n\t\t * The header icon URL.\n\t\t *\n\t\t * @return {string} the icon URL (empty when none).\n\t\t */\n\t\twidgetIconUrl() {\n\t\t\treturn (this.widgetMeta && this.widgetMeta.iconUrl) || ''\n\t\t},\n\n\t\t/**\n\t\t * The most items the list shows (`content.limit`), or 0 for no limit.\n\t\t * A limit lets the widget fit a dashboard cell instead of scrolling\n\t\t * inside it.\n\t\t *\n\t\t * @spec openspec/changes/screens-nc-widget-limit/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-shows-at-most-its-limit\n\t\t * @return {number} the limit.\n\t\t */\n\t\titemLimit() {\n\t\t\tconst limit = Number(this.content && this.content.limit)\n\t\t\treturn Number.isInteger(limit) && limit > 0 ? limit : 0\n\t\t},\n\n\t\t/**\n\t\t * The items drawn: at most `itemLimit`.\n\t\t *\n\t\t * @return {object[]} the items.\n\t\t */\n\t\tshownItems() {\n\t\t\tconst kept = this.hasExclusions ? this.items.filter((item) => !this.isExcluded(item)) : this.items\n\t\t\treturn this.itemLimit > 0 ? kept.slice(0, this.itemLimit) : kept\n\t\t},\n\n\t\t/**\n\t\t * The apps and item types `content.excludeApps` / `content.excludeTypes`\n\t\t * leave out, lower-cased.\n\t\t *\n\t\t * @spec openspec/changes/nc-widget-exclude-apps/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-can-leave-out-items-of-an-app-or-type\n\t\t * @return {{apps: string[], types: string[]}}\n\t\t */\n\t\texclusions() {\n\t\t\tconst list = (value) => (Array.isArray(value) ? value : (typeof value === 'string' && value !== '' ? [value] : []))\n\t\t\t\t.filter((entry) => typeof entry === 'string' && entry !== '')\n\t\t\t\t.map((entry) => entry.toLowerCase())\n\t\t\treturn { apps: list(this.content && this.content.excludeApps), types: list(this.content && this.content.excludeTypes) }\n\t\t},\n\n\t\t/**\n\t\t * How many items to ask the API for: the limit (or the default), and\n\t\t * more while items are left out, so a filtered list still fills it.\n\t\t *\n\t\t * @return {number}\n\t\t */\n\t\trequestLimit() {\n\t\t\tconst base = this.itemLimit > 0 ? this.itemLimit : API_ITEM_LIMIT\n\t\t\treturn this.hasExclusions ? Math.max(base * 3, 20) : base\n\t\t},\n\n\t\t/** @return {boolean} Whether any app or type is left out. */\n\t\thasExclusions() {\n\t\t\treturn this.exclusions.apps.length > 0 || this.exclusions.types.length > 0\n\t\t},\n\n\t\t/**\n\t\t * Where \"Show all\" goes: `content.showAllUrl`, else the page the widget\n\t\t * names itself (its `url`). Only with a limit; '' for no link.\n\t\t *\n\t\t * @spec openspec/changes/screens-nc-widget-limit/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-shows-at-most-its-limit\n\t\t * @return {string} the URL.\n\t\t */\n\t\tshowAllHref() {\n\t\t\tif (this.itemLimit === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst own = this.content && typeof this.content.showAllUrl === 'string' ? this.content.showAllUrl : ''\n\t\t\treturn own || (this.widgetMeta && typeof this.widgetMeta.url === 'string' ? this.widgetMeta.url : '')\n\t\t},\n\n\t\t/**\n\t\t * The \"Show all\" text (`content.showAllLabel`, else the library's).\n\t\t *\n\t\t * @return {string} the label.\n\t\t */\n\t\tshowAllLabel() {\n\t\t\tconst label = this.content && this.content.showAllLabel\n\t\t\treturn typeof label === 'string' && label !== '' ? label : t('nextcloud-vue', 'Show all')\n\t\t},\n\n\t\t/**\n\t\t * The body orientation CSS modifier class.\n\t\t *\n\t\t * @return {string} the body class.\n\t\t */\n\t\tbodyClass() {\n\t\t\treturn `cn-nc-widget-widget__body--${this.displayMode}`\n\t\t},\n\n\t\t/**\n\t\t * The item orientation CSS modifier class.\n\t\t *\n\t\t * @return {string} the item class.\n\t\t */\n\t\titemClass() {\n\t\t\treturn `cn-nc-widget-widget__item--${this.displayMode}`\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.tryMount()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Whether an item belongs to an app or type the content leaves out: its\n\t\t * own `app` / `type` / `objectType`, else the app in an `/apps/<app>/`\n\t\t * part of its link or icons.\n\t\t *\n\t\t * @spec openspec/changes/nc-widget-exclude-apps/specs/nc-widget/spec.md#requirement-a-nextcloud-widget-can-leave-out-items-of-an-app-or-type\n\t\t * @param {object} item A widget item.\n\t\t * @return {boolean}\n\t\t */\n\t\tisExcluded(item) {\n\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst { apps, types } = this.exclusions\n\t\t\tconst own = (value) => (typeof value === 'string' ? value.toLowerCase() : '')\n\t\t\tconst appsOf = [own(item.app)]\n\t\t\tfor (const url of [item.link, item.iconUrl, item.overlayIconUrl]) {\n\t\t\t\tconst match = typeof url === 'string' ? url.match(/\\/apps\\/([a-z0-9_-]+)\\//i) : null\n\t\t\t\tif (match) {\n\t\t\t\t\tappsOf.push(match[1].toLowerCase())\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (apps.length > 0 && appsOf.some((app) => app !== '' && apps.includes(app))) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn types.length > 0 && [own(item.type), own(item.objectType)].some((type) => type !== '' && types.includes(type))\n\t\t},\n\n\t\tt,\n\n\t\t/**\n\t\t * Resolve the mounting mode. Prefers the native `OCA.Dashboard`\n\t\t * callback fast-path; otherwise falls back to the OCS item list.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\ttryMount() {\n\t\t\tif (!this.widgetId) {\n\t\t\t\tthis.mode = 'api'\n\t\t\t\tthis.items = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// The native callback paints its own opaque markup, so `displayMode`\n\t\t\t// (bodyClass/itemClass below) has no effect on it — only the API\n\t\t\t// item list honours the vertical/horizontal setting. Horizontal mode\n\t\t\t// must therefore skip the native fast-path, or the \"Horizontal\n\t\t\t// (cards)\" option would silently do nothing for the (common) case\n\t\t\t// where the widget has a registered native callback.\n\t\t\t// A `limit` also takes the API list first: the native callback paints\n\t\t\t// as many items as it likes. Its fallback to native stays.\n\t\t\t// Leaving items out works on the API list only, so it skips native too.\n\t\t\tif (this.displayMode !== 'horizontal' && this.itemLimit === 0 && !this.hasExclusions) {\n\t\t\t\tconst callback = this.resolveNativeCallback()\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tthis.mountNative(callback)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.mode = 'api'\n\t\t\tthis.loadApiItems()\n\t\t},\n\n\t\t/**\n\t\t * Look up a native render callback on the `OCA.Dashboard` global.\n\t\t *\n\t\t * @return {((el: HTMLElement, ctx: {widget: object}) => unknown)|null} the callback, or `null` when none is registered.\n\t\t */\n\t\tresolveNativeCallback() {\n\t\t\tconst dashboard = getDashboardGlobal()\n\t\t\tif (!dashboard) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (this.widgetMeta && typeof this.widgetMeta.callback === 'function') {\n\t\t\t\treturn this.widgetMeta.callback\n\t\t\t}\n\t\t\tif (dashboard.callbacks && typeof dashboard.callbacks[this.widgetId] === 'function') {\n\t\t\t\treturn dashboard.callbacks[this.widgetId]\n\t\t\t}\n\t\t\treturn null\n\t\t},\n\n\t\t/**\n\t\t * Mount the widget natively by invoking its registered callback with\n\t\t * our render container.\n\t\t *\n\t\t * @param {(el: HTMLElement, ctx: {widget: object}) => unknown} callback the native render callback.\n\t\t * @return {void}\n\t\t */\n\t\tmountNative(callback) {\n\t\t\tthis.mode = 'native'\n\t\t\tthis.$nextTick(() => {\n\t\t\t\tconst container = this.$refs.nativeContainer\n\t\t\t\tif (!container) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// Native callback failed — fall back to the API list.\n\t\t\t\tconst fallback = () => {\n\t\t\t\t\tthis.mode = 'api'\n\t\t\t\t\tthis.loadApiItems()\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\t// NC dashboard widgets are registered as\n\t\t\t\t\t// `register(id, (el, { widget }) => …)` — the second argument\n\t\t\t\t\t// MUST be the `{ widget }` envelope, not the bare metadata, or\n\t\t\t\t\t// the widget destructures `widget` as undefined and throws on\n\t\t\t\t\t// first use (e.g. `widget.title`).\n\t\t\t\t\tconst result = callback(container, { widget: this.widgetMeta || {} })\n\t\t\t\t\t// Most widget callbacks are async; a synchronous try/catch\n\t\t\t\t\t// can't see a rejected promise, so wire the fallback to it too.\n\t\t\t\t\tif (result && typeof result.then === 'function') {\n\t\t\t\t\t\tresult.catch(fallback)\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tfallback()\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Fetch the API fallback list directly from the OCS Dashboard\n\t\t * endpoint. Malformed or failed responses collapse to an empty list\n\t\t * (the empty state) instead of throwing.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadApiItems() {\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\t// The v2 widget-items API only returns an entry for widgets\n\t\t\t\t// whose server-side provider implements `IAPIWidgetV2` — plenty\n\t\t\t\t// of native dashboard widgets are JS-callback-only (`IWidget`)\n\t\t\t\t// and never appear in this response at all, which looks\n\t\t\t\t// identical to \"0 items\" from here. extractItems() tolerates\n\t\t\t\t// both the flat-array (older providers) and `{items}` (v2) shapes.\n\t\t\t\tconst url = generateOcsUrl('/apps/dashboard/api/v2/widget-items')\n\t\t\t\tconst response = await axios.get(url, {\n\t\t\t\t\tparams: { widgets: [this.widgetId], limit: this.requestLimit },\n\t\t\t\t})\n\t\t\t\tconst data = response && response.data && response.data.ocs ? response.data.ocs.data : null\n\t\t\t\tconst widgetData = data ? data[this.widgetId] : null\n\t\t\t\tthis.items = this.extractItems(widgetData)\n\t\t\t\t// Only a SUCCESSFUL response can say the widget is absent. A\n\t\t\t\t// failed request says nothing about the widget, so it keeps\n\t\t\t\t// the ordinary empty state rather than a claim about the app.\n\t\t\t\tthis.unsupported = data !== null && (widgetData === null || widgetData === undefined)\n\t\t\t} catch {\n\t\t\t\tthis.items = []\n\t\t\t\tthis.unsupported = false\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\n\t\t\t// Horizontal mode deliberately skips the native fast-path (see\n\t\t\t// tryMount()) to get the styled card layout. But when the API has\n\t\t\t// no entry for this widget at all — no `IAPIWidgetV2` support, not\n\t\t\t// \"no items right now\" — that would render a false empty state for\n\t\t\t// a widget that actually has content. Fall back to native\n\t\t\t// rendering rather than lying about there being nothing to show.\n\t\t\tif (this.items.length === 0) {\n\t\t\t\tconst callback = this.resolveNativeCallback()\n\t\t\t\tif (typeof callback === 'function') {\n\t\t\t\t\tthis.mountNative(callback)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Normalise a per-widget OCS payload to an items array, tolerating both\n\t\t * the flat array and the `{items}` envelope shapes.\n\t\t *\n\t\t * @param {unknown} widgetData the per-widget payload.\n\t\t * @return {object[]} the items array (possibly empty).\n\t\t */\n\t\textractItems(widgetData) {\n\t\t\tif (!widgetData) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tif (Array.isArray(widgetData)) {\n\t\t\t\treturn widgetData\n\t\t\t}\n\t\t\tif (Array.isArray(widgetData.items)) {\n\t\t\t\treturn widgetData.items\n\t\t\t}\n\t\t\tif (widgetData.items && typeof widgetData.items === 'object') {\n\t\t\t\treturn Object.values(widgetData.items)\n\t\t\t}\n\t\t\treturn []\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-nc-widget-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\twidth: 100%;\n\theight: 100%;\n\toverflow: hidden;\n}\n\n/*\n * Header + content match the native Nextcloud Dashboard panel (apps/dashboard)\n * exactly — this component's whole job is rendering NC dashboard widgets, so it\n * should look native by default: 16px header, 32px leading icon with a 16px\n * gap, a 20px/700 title, and the native panel content inset (16px sides +\n * bottom, flush to the header on top). Same design tokens as core; overridable\n * via the host's CnWidgetWrapper styleConfig / nldesign.\n */\n.cn-nc-widget-widget__header {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 16px;\n\tpadding: 16px;\n\tfont-weight: 700;\n}\n\n.cn-nc-widget-widget__header-icon {\n\twidth: 32px;\n\theight: 32px;\n\tflex: 0 0 auto;\n}\n\n.cn-nc-widget-widget__header-title {\n\tflex: 1;\n\tfont-size: 20px;\n\tfont-weight: 700;\n\tline-height: 24px;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-nc-widget-widget__show-all {\n\talign-self: flex-start;\n\tpadding: 8px 0 0;\n\tcolor: var(--color-primary-element);\n\tfont-weight: 600;\n\ttext-decoration: none;\n}\n\n.cn-nc-widget-widget__show-all:hover,\n.cn-nc-widget-widget__show-all:focus-visible {\n\ttext-decoration: underline;\n}\n\n.cn-nc-widget-widget__native {\n\tflex: 1;\n\toverflow: auto;\n\tpadding: 0 16px 16px;\n}\n\n/*\n * The native `OCA.Dashboard` callback paints its own markup we don't control\n * — for first-party widgets that's almost always `@nextcloud/vue`'s\n * `NcDashboardWidget` / `NcDashboardWidgetItem` (`.dashboard-widget` wrapping\n * a bare `<ul>`/`<li>` list, each item a `.item-list__entry`).\n *\n * Only the LIST CONTAINER is retiled into a grid here — `.item-list__entry`'s\n * own internal layout is left untouched. An earlier version of this override\n * also forced `.item-list__entry` from row to column, but its icon-overlay\n * badge (`.item-icon`, see @nextcloud/vue's NcDashboardWidgetItem CSS) is\n * positioned with negative margins calibrated for the row layout, so\n * flipping to column made items visually overlap. Tiling the `<li>`s into a\n * grid while each entry keeps its normal icon+text row reads as a grid of\n * card tiles without touching that internal math.\n *\n * Scoped from `.cn-nc-widget-widget--horizontal` on the ROOT element, not\n * `.cn-nc-widget-widget__native`: the callback mounts via `.$mount(el)`,\n * which replaces `nativeContainer` in the live DOM outright, so any class\n * placed directly on it never survives to be selectable.\n *\n * The 250px column floor matches `.item-list__entry`'s own natural minimum\n * width (avatar + padding + its un-truncatable-below-this content) — a grid\n * track narrower than that squeezes the entry below its real minimum and it\n * overflows into the neighbouring cell. `min-width: 0` on the `<li>` alone\n * isn't enough to shrink it further: the item's own internal flex layout\n * still claims that much room regardless of the grid track size, so the\n * track itself must not go below it.\n */\n.cn-nc-widget-widget--horizontal :deep(.dashboard-widget > ul) {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fill, minmax(250px, 1fr));\n\tgap: 8px;\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-nc-widget-widget--horizontal :deep(.dashboard-widget > ul > li) {\n\twidth: auto;\n\tmin-width: 0;\n}\n\n.cn-nc-widget-widget--horizontal :deep(.item-list__entry) {\n\theight: 100%;\n\tmargin: 0;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n}\n\n.cn-nc-widget-widget__body {\n\tflex: 1;\n\toverflow: auto;\n\tpadding: 0 16px 16px;\n}\n\n.cn-nc-widget-widget__body--vertical {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-nc-widget-widget__body--horizontal {\n\tdisplay: flex;\n\tflex-direction: row;\n\tflex-wrap: wrap;\n\tgap: 12px;\n}\n\n.cn-nc-widget-widget__state {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tflex: 1;\n\tmin-height: 64px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-style: italic;\n}\n\n.cn-nc-widget-widget__item {\n\tdisplay: flex;\n\ttext-decoration: none;\n\tcolor: var(--color-main-text);\n\tborder-radius: var(--border-radius);\n\tpadding: 4px;\n}\n\n.cn-nc-widget-widget__item:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-nc-widget-widget__item--vertical {\n\tflex-direction: row;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-nc-widget-widget__item--horizontal {\n\tflex-direction: column;\n\talign-items: center;\n\twidth: 120px;\n\ttext-align: center;\n}\n\n.cn-nc-widget-widget__item-icon-wrap {\n\twidth: 32px;\n\theight: 32px;\n\tflex: 0 0 32px;\n\tposition: relative;\n}\n\n.cn-nc-widget-widget__item-icon {\n\twidth: 32px;\n\theight: 32px;\n\tobject-fit: cover;\n\tborder-radius: 50%;\n}\n\n.cn-nc-widget-widget__item-overlay {\n\tposition: absolute;\n\tright: -2px;\n\tbottom: -2px;\n\twidth: 14px;\n\theight: 14px;\n}\n\n.cn-nc-widget-widget__item-text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1;\n}\n\n.cn-nc-widget-widget__item-title {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n\n.cn-nc-widget-widget__item-subtitle {\n\tfont-size: 0.85em;\n\tcolor: var(--color-text-maxcontrast);\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n}\n</style>\n"],"names":["t","axios"],"mappings":"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"}
@@ -71,7 +71,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
71
71
  ? (openBlock(), createElementBlock("div", _hoisted_6, toDisplayString($options.t('nextcloud-vue', 'No widget selected')), 1 /* TEXT */))
72
72
  : ($data.unsupported)
73
73
  ? (openBlock(), createElementBlock("div", _hoisted_7, toDisplayString($options.t('nextcloud-vue', 'This widget can only be shown on the Nextcloud dashboard itself.')), 1 /* TEXT */))
74
- : ($data.items.length === 0)
74
+ : ($options.shownItems.length === 0)
75
75
  ? (openBlock(), createElementBlock("div", _hoisted_8, toDisplayString($options.t('nextcloud-vue', 'No items available')), 1 /* TEXT */))
76
76
  : (openBlock(), createElementBlock(Fragment, { key: 4 }, [
77
77
  (openBlock(true), createElementBlock(Fragment, null, renderList($options.shownItems, (item, idx) => {