@conduction/nextcloud-vue 2.104.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 (224) hide show
  1. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
  2. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
  4. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  5. package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
  6. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +18 -0
  7. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  8. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +3 -1
  9. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  10. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
  11. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +18 -0
  12. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  13. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +1 -1
  14. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  15. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  16. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +93 -1
  17. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  18. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  19. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  20. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +6 -3
  21. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  22. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +3 -3
  23. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  24. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +112 -5
  25. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  26. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  27. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +9 -0
  28. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js.map +1 -0
  29. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js +24 -0
  30. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -0
  31. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js +49 -0
  32. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -0
  33. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  34. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +36 -18
  35. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  36. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +17 -38
  37. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  38. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
  39. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  40. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  41. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
  42. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +1 -1
  43. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  44. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  45. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +1 -1
  46. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +2 -0
  47. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -1
  48. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +32 -29
  49. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -1
  50. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  51. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +53 -2
  52. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  53. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +119 -111
  54. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  55. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
  56. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +62 -1
  57. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  58. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  59. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
  60. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +73 -4
  61. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
  62. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +74 -27
  63. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
  64. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +208 -46
  65. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +121 -98
  67. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
  69. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +24 -0
  70. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
  71. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +20 -4
  72. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
  73. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +25 -6
  74. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  75. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +112 -1
  76. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  77. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +100 -44
  78. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  79. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
  80. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +67 -4
  81. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
  82. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +1 -1
  83. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
  84. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js +9 -0
  85. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js.map +1 -0
  86. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js +88 -0
  87. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js.map +1 -0
  88. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js +39 -0
  89. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js.map +1 -0
  90. package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
  91. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +295 -12
  92. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  93. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +267 -144
  94. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  95. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
  96. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +4 -0
  97. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  98. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +3 -1
  99. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  100. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  101. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +93 -1
  102. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  103. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +322 -246
  104. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  105. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue.js +1 -1
  106. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +122 -7
  107. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
  108. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js +189 -93
  109. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
  110. package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +1 -1
  111. package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -1
  112. package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +3 -3
  113. package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -1
  114. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
  115. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  116. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +16 -4
  117. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  118. package/dist/esm/components/CnTabs/CnTabs.vue.js +1 -1
  119. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  120. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  121. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  122. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +42 -0
  123. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  124. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +38 -19
  125. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  126. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js +9 -0
  127. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js.map +1 -0
  128. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js +258 -0
  129. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js.map +1 -0
  130. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js +69 -0
  131. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js.map +1 -0
  132. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
  133. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +11 -0
  134. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
  135. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +4 -4
  136. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
  137. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +16 -14
  138. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
  139. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
  140. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  141. package/dist/esm/index.js +2 -0
  142. package/dist/esm/index.js.map +1 -1
  143. package/dist/esm/l10n/en.json.js +24 -1
  144. package/dist/esm/l10n/en.json.js.map +1 -1
  145. package/dist/esm/l10n/nl.json.js +24 -1
  146. package/dist/esm/l10n/nl.json.js.map +1 -1
  147. package/dist/esm/library-style.js +1 -1
  148. package/dist/esm/nextcloud-vue.css +1369 -748
  149. package/dist/esm/utils/dueText.js +18 -3
  150. package/dist/esm/utils/dueText.js.map +1 -1
  151. package/dist/esm/utils/libraryWidgetKeys.js +2 -0
  152. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  153. package/dist/esm/utils/nextcloudApps.js +45 -0
  154. package/dist/esm/utils/nextcloudApps.js.map +1 -0
  155. package/dist/esm/utils/scopeListLayout.js +9 -2
  156. package/dist/esm/utils/scopeListLayout.js.map +1 -1
  157. package/dist/esm/utils/sortOrder.js +11 -1
  158. package/dist/esm/utils/sortOrder.js.map +1 -1
  159. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  160. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  161. package/dist/esm/utils/visibleWhen.js +12 -4
  162. package/dist/esm/utils/visibleWhen.js.map +1 -1
  163. package/dist/nextcloud-vue.cjs.js +8965 -6497
  164. package/dist/nextcloud-vue.cjs.js.map +2 -2
  165. package/dist/nextcloud-vue.css +1369 -748
  166. package/l10n/en.json +24 -1
  167. package/l10n/nl.json +24 -1
  168. package/package.json +1 -1
  169. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -1
  170. package/src/components/CnCardGrid/CnCardGrid.md +2 -0
  171. package/src/components/CnCardGrid/CnCardGrid.vue +20 -0
  172. package/src/components/CnCellRenderer/CnCellRenderer.vue +19 -1
  173. package/src/components/CnChartWidget/CnChartWidget.md +2 -0
  174. package/src/components/CnChartWidget/CnChartWidget.vue +93 -1
  175. package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -6
  176. package/src/components/CnDetailPage/CnDetailPage.md +3 -2
  177. package/src/components/CnDetailPage/CnDetailPage.vue +112 -5
  178. package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +60 -0
  179. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +36 -29
  180. package/src/components/CnFactsWidget/CnFactsWidget.vue +4 -0
  181. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -1
  182. package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +4 -1
  183. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +70 -4
  184. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +62 -1
  185. package/src/components/CnFlowsPage/CnFlowBoard.vue +132 -8
  186. package/src/components/CnIndexPage/CnIndexPage.md +8 -5
  187. package/src/components/CnIndexPage/CnIndexPage.vue +236 -54
  188. package/src/components/CnIndexPage/CnIndexPageWidgets.vue +36 -1
  189. package/src/components/CnIndexPage/useSelfFetchList.js +25 -6
  190. package/src/components/CnIndexSidebar/CnIndexSidebar.md +2 -0
  191. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +148 -1
  192. package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +68 -5
  193. package/src/components/CnNoticeWidget/CnNoticeWidget.vue +153 -0
  194. package/src/components/CnNoticeWidget/index.js +12 -0
  195. package/src/components/CnObjectCard/CnObjectCard.md +1 -0
  196. package/src/components/CnObjectCard/CnObjectCard.vue +354 -13
  197. package/src/components/CnObjectSidebar/CnFilesTab.vue +6 -0
  198. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +190 -4
  199. package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +209 -9
  200. package/src/components/CnSettingsField/CnSettingsField.vue +4 -1
  201. package/src/components/CnSetupWizard/CnSetupWizard.vue +9 -1
  202. package/src/components/CnTabs/CnTabs.vue +11 -0
  203. package/src/components/CnTabsWidget/CnTabsWidget.vue +91 -18
  204. package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.md +11 -0
  205. package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue +382 -0
  206. package/src/components/CnTeamWorkloadWidget/index.js +14 -0
  207. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +15 -4
  208. package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
  209. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
  210. package/src/components/index.js +2 -0
  211. package/src/css/dialog.css +20 -2
  212. package/src/css/index-page.css +14 -2
  213. package/src/css/look-board-detail.css +125 -8
  214. package/src/css/look-board-index.css +100 -4
  215. package/src/css/look-board.css +122 -14
  216. package/src/index.js +2 -1
  217. package/src/schemas/app-manifest-v2.schema.json +110 -8
  218. package/src/utils/dueText.js +18 -3
  219. package/src/utils/libraryWidgetKeys.js +2 -0
  220. package/src/utils/nextcloudApps.js +50 -0
  221. package/src/utils/scopeListLayout.js +9 -2
  222. package/src/utils/sortOrder.js +10 -0
  223. package/src/utils/validateManifestV2.compiled.js +3 -3
  224. package/src/utils/visibleWhen.js +12 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnTeamWorkloadWidget.vue2.js","sources":["../../../../src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-team-workload\" data-testid=\"cn-team-workload\">\n\t\t<p v-if=\"loading && members.length === 0\" class=\"cn-team-workload__state-line\" role=\"status\">\n\t\t\t{{ loadingLabel }}\n\t\t</p>\n\t\t<p v-else-if=\"members.length === 0\" class=\"cn-team-workload__state-line\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<ul v-else class=\"cn-team-workload__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"member in members\"\n\t\t\t\t:key=\"member.id\"\n\t\t\t\tclass=\"cn-team-workload__member\"\n\t\t\t\tdata-testid=\"cn-team-workload-member\">\n\t\t\t\t<div class=\"cn-team-workload__row\">\n\t\t\t\t\t<span class=\"cn-team-workload__avatar\" aria-hidden=\"true\">{{ member.initials }}</span>\n\t\t\t\t\t<span class=\"cn-team-workload__who\">\n\t\t\t\t\t\t<strong class=\"cn-team-workload__name\">{{ member.name }}</strong>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclass=\"cn-team-workload__state\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-team-workload__state--away': !member.available }\">{{ member.line }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-team-workload__count\">{{ member.countText }}</span>\n\t\t\t\t</div>\n\t\t\t\t<span class=\"cn-team-workload__bar\" aria-hidden=\"true\">\n\t\t\t\t\t<span\n\t\t\t\t\t\tclass=\"cn-team-workload__bar-fill\"\n\t\t\t\t\t\t:class=\"{ 'cn-team-workload__bar-fill--hot': member.hot }\"\n\t\t\t\t\t\t:style=\"{ width: member.percent + '%' }\" />\n\t\t\t\t</span>\n\t\t\t</li>\n\t\t</ul>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { fetchStatuses } from '../../utils/nextcloudDirectory.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/** The share of the capacity from which a load bar reads as full. */\nconst HOT_PERCENT = 90\n\n/**\n * CnTeamWorkloadWidget: the `team-workload` widget (\"Team vandaag\" on board\n * DqTeamwachtrij). Each person of the team with their initials, name, an\n * availability line, their open count and a load bar; the card's header\n * note says how many are present (\"4 of 5 present\").\n *\n * The counts come from the app (`content.source`, an endpoint that answers a\n * row per person). The availability comes from Nextcloud's user status, read\n * on the client through the OCS user status API: the person's own message\n * with the time it ends (\"In a meeting until 14:00\"), else Available, Away or\n * Busy, and Absent today without a status. Present means any status but\n * offline.\n *\n * `content`:\n * - `source`: `{ url, responsePath?, userField?, nameField?, countField? }`;\n * the url goes through `generateUrl`, the rows are read at `responsePath`\n * (else the body), each with the user id at `userField` (default\n * `userId`), the name at `nameField` (default `displayName`) and the count\n * at `countField` (default `count`).\n * - `capacity`: the count at a full bar; without it the highest count is.\n * - `countLabel`: `{ one, other }` with `{count}`, through the app's\n * translate; without it the count reads \"{count} open\".\n * - `emptyText`: shown without anyone to list.\n */\nexport default {\n\tname: 'CnTeamWorkloadWidget',\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** The widget's content: `source`, `capacity`, `countLabel`, `emptyText`. */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['header'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The rows the source answered. */\n\t\t\trows: [],\n\t\t\t/** The user statuses by user id. */\n\t\t\tstatuses: {},\n\t\t\t/** Whether the source is being read. */\n\t\t\tloading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The signed-in user's id. */\n\t\tviewerId() {\n\t\t\treturn String(getCurrentUser()?.uid || '')\n\t\t},\n\n\t\t/**\n\t\t * The people to list, the viewer first and the rest by name, each with\n\t\t * the line, count and bar to draw.\n\t\t *\n\t\t * @return {Array<object>} The members.\n\t\t */\n\t\tmembers() {\n\t\t\tconst source = this.content?.source || {}\n\t\t\tconst userField = source.userField || 'userId'\n\t\t\tconst nameField = source.nameField || 'displayName'\n\t\t\tconst countField = source.countField || 'count'\n\t\t\tconst people = this.rows\n\t\t\t\t.filter((row) => row && typeof row === 'object' && readPath(row, userField))\n\t\t\t\t.map((row) => {\n\t\t\t\t\tconst id = String(readPath(row, userField))\n\t\t\t\t\tconst name = String(readPath(row, nameField) || id)\n\t\t\t\t\treturn { id, name, count: Number(readPath(row, countField)) || 0 }\n\t\t\t\t})\n\t\t\tconst capacity = Number(this.content?.capacity) > 0\n\t\t\t\t? Number(this.content.capacity)\n\t\t\t\t: Math.max(1, ...people.map((p) => p.count))\n\t\t\treturn people\n\t\t\t\t.sort((a, b) => (Number(b.id === this.viewerId) - Number(a.id === this.viewerId)) || a.name.localeCompare(b.name))\n\t\t\t\t.map((person) => {\n\t\t\t\t\tconst status = this.statuses[person.id] || null\n\t\t\t\t\tconst percent = Math.min(100, Math.round((person.count / capacity) * 100))\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...person,\n\t\t\t\t\t\tname: person.id === this.viewerId ? t('nextcloud-vue', '{name} (you)', { name: person.name }) : person.name,\n\t\t\t\t\t\tinitials: initialsOf(person.name),\n\t\t\t\t\t\tline: this.lineOf(status),\n\t\t\t\t\t\tavailable: !!status && status.status === 'online',\n\t\t\t\t\t\tpresent: isPresent(status),\n\t\t\t\t\t\tcountText: this.countText(person.count),\n\t\t\t\t\t\tpercent,\n\t\t\t\t\t\thot: percent >= HOT_PERCENT,\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/** @return {string} The header note: how many of the team are present. */\n\t\theaderNote() {\n\t\t\tconst total = this.members.length\n\t\t\tif (total === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst present = this.members.filter((member) => member.present).length\n\t\t\treturn t('nextcloud-vue', '{present} of {total} present', { present, total })\n\t\t},\n\n\t\t/** @return {string} What the card says while it reads. */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\t/** @return {string} What the card says without anyone to list. */\n\t\temptyLabel() {\n\t\t\treturn this.content?.emptyText ? this.cnTranslate(this.content.emptyText) : t('nextcloud-vue', 'No one in the team')\n\t\t},\n\t},\n\n\twatch: {\n\t\theaderNote: {\n\t\t\timmediate: true,\n\t\t\thandler(note) {\n\t\t\t\t/**\n\t\t\t\t * @event header The card header's parts: `{ link, note, action, pill }`, the note being how many are present.\n\t\t\t\t */\n\t\t\t\tthis.$emit('header', { link: null, note, action: null, pill: null })\n\t\t\t},\n\t\t},\n\n\t\t'content.source': {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the counts and the user statuses. A failed read leaves the card\n\t\t * empty; a failed status read leaves everyone without a status.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tconst source = this.content?.source\n\t\t\tif (!source || typeof source.url !== 'string' || source.url === '') {\n\t\t\t\tthis.rows = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst [answer, statuses] = await Promise.all([\n\t\t\t\t\taxios.get(generateUrl(source.url)),\n\t\t\t\t\tfetchStatuses(axios),\n\t\t\t\t])\n\t\t\t\tconst body = answer && answer.data\n\t\t\t\tconst rows = source.responsePath ? readPath(body, source.responsePath) : body\n\t\t\t\tthis.rows = Array.isArray(rows) ? rows : []\n\t\t\t\tthis.statuses = statuses || {}\n\t\t\t} catch {\n\t\t\t\tthis.rows = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The availability line of a user status.\n\t\t *\n\t\t * @param {object|null} status The user status, or null without one.\n\t\t * @return {string} The line.\n\t\t */\n\t\tlineOf(status) {\n\t\t\tif (!status) {\n\t\t\t\treturn t('nextcloud-vue', 'Absent today')\n\t\t\t}\n\t\t\tconst message = typeof status.message === 'string' ? status.message.trim() : ''\n\t\t\tif (message !== '') {\n\t\t\t\tconst clearAt = Number(status.clearAt)\n\t\t\t\tif (!Number.isFinite(clearAt) || clearAt <= 0) {\n\t\t\t\t\treturn message\n\t\t\t\t}\n\t\t\t\tconst time = new Date(clearAt * 1000).toLocaleTimeString(userLocale() || undefined, { hour: '2-digit', minute: '2-digit' })\n\t\t\t\treturn t('nextcloud-vue', '{message} until {time}', { message, time })\n\t\t\t}\n\t\t\tswitch (status.status) {\n\t\t\t\tcase 'online':\n\t\t\t\t\treturn t('nextcloud-vue', 'Available')\n\t\t\t\tcase 'away':\n\t\t\t\t\treturn t('nextcloud-vue', 'Away')\n\t\t\t\tcase 'dnd':\n\t\t\t\tcase 'busy':\n\t\t\t\t\treturn t('nextcloud-vue', 'Busy')\n\t\t\t\tdefault:\n\t\t\t\t\treturn t('nextcloud-vue', 'Absent today')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The count as words: the content's `countLabel`, else \"{count} open\".\n\t\t *\n\t\t * @param {number} count The open count.\n\t\t * @return {string} The text.\n\t\t */\n\t\tcountText(count) {\n\t\t\tconst label = this.content?.countLabel\n\t\t\tif (label && typeof label === 'object' && typeof label.one === 'string' && typeof label.other === 'string') {\n\t\t\t\treturn this.cnTranslate(count === 1 ? label.one : label.other).replace('{count}', String(count))\n\t\t\t}\n\t\t\treturn n('nextcloud-vue', '{count} open', '{count} open', count, { count })\n\t\t},\n\t},\n}\n\n/**\n * Up to two initials of a name.\n *\n * @param {string} name The name.\n * @return {string} The initials, upper case.\n */\nfunction initialsOf(name) {\n\tconst parts = String(name || '').trim().split(/\\s+/).filter(Boolean)\n\tif (parts.length === 0) {\n\t\treturn ''\n\t}\n\tconst last = parts.length > 1 ? parts[parts.length - 1].charAt(0) : ''\n\treturn (parts[0].charAt(0) + last).toUpperCase()\n}\n\n/**\n * Whether a person is at work today: any status but offline or invisible.\n *\n * @param {object|null} status The user status.\n * @return {boolean} True when present.\n */\nfunction isPresent(status) {\n\treturn !!status && status.status !== 'offline' && status.status !== 'invisible'\n}\n</script>\n\n<style scoped>\n.cn-team-workload__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 14px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-team-workload__member {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-team-workload__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n}\n\n.cn-team-workload__avatar {\n\tdisplay: flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-team-workload__who {\n\tdisplay: flex;\n\tflex: 1;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-team-workload__name {\n\tfont-size: 14px;\n}\n\n.cn-team-workload__state {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-team-workload__state--away {\n\tcolor: var(--color-warning-text, var(--color-text-maxcontrast));\n}\n\n.cn-team-workload__count {\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n}\n\n.cn-team-workload__bar {\n\tdisplay: block;\n\theight: 6px;\n\toverflow: hidden;\n\tborder-radius: 3px;\n\tbackground: var(--color-border);\n}\n\n.cn-team-workload__bar-fill {\n\tdisplay: block;\n\theight: 100%;\n\tbackground: var(--color-primary-element);\n}\n\n.cn-team-workload__bar-fill--hot {\n\tbackground: var(--color-error);\n}\n\n.cn-team-workload__state-line {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["t","n"],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { openBlock, createElementBlock, toDisplayString, Fragment, renderList, createElementVNode, normalizeClass, normalizeStyle } from 'vue';
2
+
3
+ const _hoisted_1 = {
4
+ class: "cn-team-workload",
5
+ "data-testid": "cn-team-workload"
6
+ };
7
+ const _hoisted_2 = {
8
+ key: 0,
9
+ class: "cn-team-workload__state-line",
10
+ role: "status"
11
+ };
12
+ const _hoisted_3 = {
13
+ key: 1,
14
+ class: "cn-team-workload__state-line"
15
+ };
16
+ const _hoisted_4 = {
17
+ key: 2,
18
+ class: "cn-team-workload__list"
19
+ };
20
+ const _hoisted_5 = { class: "cn-team-workload__row" };
21
+ const _hoisted_6 = {
22
+ class: "cn-team-workload__avatar",
23
+ "aria-hidden": "true"
24
+ };
25
+ const _hoisted_7 = { class: "cn-team-workload__who" };
26
+ const _hoisted_8 = { class: "cn-team-workload__name" };
27
+ const _hoisted_9 = { class: "cn-team-workload__count" };
28
+ const _hoisted_10 = {
29
+ class: "cn-team-workload__bar",
30
+ "aria-hidden": "true"
31
+ };
32
+
33
+ function render(_ctx, _cache, $props, $setup, $data, $options) {
34
+ return (openBlock(), createElementBlock("div", _hoisted_1, [
35
+ ($data.loading && $options.members.length === 0)
36
+ ? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString($options.loadingLabel), 1 /* TEXT */))
37
+ : ($options.members.length === 0)
38
+ ? (openBlock(), createElementBlock("p", _hoisted_3, toDisplayString($options.emptyLabel), 1 /* TEXT */))
39
+ : (openBlock(), createElementBlock("ul", _hoisted_4, [
40
+ (openBlock(true), createElementBlock(Fragment, null, renderList($options.members, (member) => {
41
+ return (openBlock(), createElementBlock("li", {
42
+ key: member.id,
43
+ class: "cn-team-workload__member",
44
+ "data-testid": "cn-team-workload-member"
45
+ }, [
46
+ createElementVNode("div", _hoisted_5, [
47
+ createElementVNode("span", _hoisted_6, toDisplayString(member.initials), 1 /* TEXT */),
48
+ createElementVNode("span", _hoisted_7, [
49
+ createElementVNode("strong", _hoisted_8, toDisplayString(member.name), 1 /* TEXT */),
50
+ createElementVNode("span", {
51
+ class: normalizeClass(["cn-team-workload__state", { 'cn-team-workload__state--away': !member.available }])
52
+ }, toDisplayString(member.line), 3 /* TEXT, CLASS */)
53
+ ]),
54
+ createElementVNode("span", _hoisted_9, toDisplayString(member.countText), 1 /* TEXT */)
55
+ ]),
56
+ createElementVNode("span", _hoisted_10, [
57
+ createElementVNode("span", {
58
+ class: normalizeClass(["cn-team-workload__bar-fill", { 'cn-team-workload__bar-fill--hot': member.hot }]),
59
+ style: normalizeStyle({ width: member.percent + '%' })
60
+ }, null, 6 /* CLASS, STYLE */)
61
+ ])
62
+ ]))
63
+ }), 128 /* KEYED_FRAGMENT */))
64
+ ]))
65
+ ]))
66
+ }
67
+
68
+ export { render };
69
+ //# sourceMappingURL=CnTeamWorkloadWidget.vue3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CnTeamWorkloadWidget.vue3.js","sources":["../../../../src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue?vue&type=template&id=8e82bdea&lang.js"],"sourcesContent":["<!--\n SPDX-FileCopyrightText: 2026 Conduction B.V.\n SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-team-workload\" data-testid=\"cn-team-workload\">\n\t\t<p v-if=\"loading && members.length === 0\" class=\"cn-team-workload__state-line\" role=\"status\">\n\t\t\t{{ loadingLabel }}\n\t\t</p>\n\t\t<p v-else-if=\"members.length === 0\" class=\"cn-team-workload__state-line\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<ul v-else class=\"cn-team-workload__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"member in members\"\n\t\t\t\t:key=\"member.id\"\n\t\t\t\tclass=\"cn-team-workload__member\"\n\t\t\t\tdata-testid=\"cn-team-workload-member\">\n\t\t\t\t<div class=\"cn-team-workload__row\">\n\t\t\t\t\t<span class=\"cn-team-workload__avatar\" aria-hidden=\"true\">{{ member.initials }}</span>\n\t\t\t\t\t<span class=\"cn-team-workload__who\">\n\t\t\t\t\t\t<strong class=\"cn-team-workload__name\">{{ member.name }}</strong>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclass=\"cn-team-workload__state\"\n\t\t\t\t\t\t\t:class=\"{ 'cn-team-workload__state--away': !member.available }\">{{ member.line }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-team-workload__count\">{{ member.countText }}</span>\n\t\t\t\t</div>\n\t\t\t\t<span class=\"cn-team-workload__bar\" aria-hidden=\"true\">\n\t\t\t\t\t<span\n\t\t\t\t\t\tclass=\"cn-team-workload__bar-fill\"\n\t\t\t\t\t\t:class=\"{ 'cn-team-workload__bar-fill--hot': member.hot }\"\n\t\t\t\t\t\t:style=\"{ width: member.percent + '%' }\" />\n\t\t\t\t</span>\n\t\t\t</li>\n\t\t</ul>\n\t</div>\n</template>\n\n<script>\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { fetchStatuses } from '../../utils/nextcloudDirectory.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/** The share of the capacity from which a load bar reads as full. */\nconst HOT_PERCENT = 90\n\n/**\n * CnTeamWorkloadWidget: the `team-workload` widget (\"Team vandaag\" on board\n * DqTeamwachtrij). Each person of the team with their initials, name, an\n * availability line, their open count and a load bar; the card's header\n * note says how many are present (\"4 of 5 present\").\n *\n * The counts come from the app (`content.source`, an endpoint that answers a\n * row per person). The availability comes from Nextcloud's user status, read\n * on the client through the OCS user status API: the person's own message\n * with the time it ends (\"In a meeting until 14:00\"), else Available, Away or\n * Busy, and Absent today without a status. Present means any status but\n * offline.\n *\n * `content`:\n * - `source`: `{ url, responsePath?, userField?, nameField?, countField? }`;\n * the url goes through `generateUrl`, the rows are read at `responsePath`\n * (else the body), each with the user id at `userField` (default\n * `userId`), the name at `nameField` (default `displayName`) and the count\n * at `countField` (default `count`).\n * - `capacity`: the count at a full bar; without it the highest count is.\n * - `countLabel`: `{ one, other }` with `{count}`, through the app's\n * translate; without it the count reads \"{count} open\".\n * - `emptyText`: shown without anyone to list.\n */\nexport default {\n\tname: 'CnTeamWorkloadWidget',\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** The widget's content: `source`, `capacity`, `countLabel`, `emptyText`. */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['header'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The rows the source answered. */\n\t\t\trows: [],\n\t\t\t/** The user statuses by user id. */\n\t\t\tstatuses: {},\n\t\t\t/** Whether the source is being read. */\n\t\t\tloading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The signed-in user's id. */\n\t\tviewerId() {\n\t\t\treturn String(getCurrentUser()?.uid || '')\n\t\t},\n\n\t\t/**\n\t\t * The people to list, the viewer first and the rest by name, each with\n\t\t * the line, count and bar to draw.\n\t\t *\n\t\t * @return {Array<object>} The members.\n\t\t */\n\t\tmembers() {\n\t\t\tconst source = this.content?.source || {}\n\t\t\tconst userField = source.userField || 'userId'\n\t\t\tconst nameField = source.nameField || 'displayName'\n\t\t\tconst countField = source.countField || 'count'\n\t\t\tconst people = this.rows\n\t\t\t\t.filter((row) => row && typeof row === 'object' && readPath(row, userField))\n\t\t\t\t.map((row) => {\n\t\t\t\t\tconst id = String(readPath(row, userField))\n\t\t\t\t\tconst name = String(readPath(row, nameField) || id)\n\t\t\t\t\treturn { id, name, count: Number(readPath(row, countField)) || 0 }\n\t\t\t\t})\n\t\t\tconst capacity = Number(this.content?.capacity) > 0\n\t\t\t\t? Number(this.content.capacity)\n\t\t\t\t: Math.max(1, ...people.map((p) => p.count))\n\t\t\treturn people\n\t\t\t\t.sort((a, b) => (Number(b.id === this.viewerId) - Number(a.id === this.viewerId)) || a.name.localeCompare(b.name))\n\t\t\t\t.map((person) => {\n\t\t\t\t\tconst status = this.statuses[person.id] || null\n\t\t\t\t\tconst percent = Math.min(100, Math.round((person.count / capacity) * 100))\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...person,\n\t\t\t\t\t\tname: person.id === this.viewerId ? t('nextcloud-vue', '{name} (you)', { name: person.name }) : person.name,\n\t\t\t\t\t\tinitials: initialsOf(person.name),\n\t\t\t\t\t\tline: this.lineOf(status),\n\t\t\t\t\t\tavailable: !!status && status.status === 'online',\n\t\t\t\t\t\tpresent: isPresent(status),\n\t\t\t\t\t\tcountText: this.countText(person.count),\n\t\t\t\t\t\tpercent,\n\t\t\t\t\t\thot: percent >= HOT_PERCENT,\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t},\n\n\t\t/** @return {string} The header note: how many of the team are present. */\n\t\theaderNote() {\n\t\t\tconst total = this.members.length\n\t\t\tif (total === 0) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst present = this.members.filter((member) => member.present).length\n\t\t\treturn t('nextcloud-vue', '{present} of {total} present', { present, total })\n\t\t},\n\n\t\t/** @return {string} What the card says while it reads. */\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\t/** @return {string} What the card says without anyone to list. */\n\t\temptyLabel() {\n\t\t\treturn this.content?.emptyText ? this.cnTranslate(this.content.emptyText) : t('nextcloud-vue', 'No one in the team')\n\t\t},\n\t},\n\n\twatch: {\n\t\theaderNote: {\n\t\t\timmediate: true,\n\t\t\thandler(note) {\n\t\t\t\t/**\n\t\t\t\t * @event header The card header's parts: `{ link, note, action, pill }`, the note being how many are present.\n\t\t\t\t */\n\t\t\t\tthis.$emit('header', { link: null, note, action: null, pill: null })\n\t\t\t},\n\t\t},\n\n\t\t'content.source': {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.load()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the counts and the user statuses. A failed read leaves the card\n\t\t * empty; a failed status read leaves everyone without a status.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync load() {\n\t\t\tconst source = this.content?.source\n\t\t\tif (!source || typeof source.url !== 'string' || source.url === '') {\n\t\t\t\tthis.rows = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst { default: axios } = await import('@nextcloud/axios')\n\t\t\t\tconst [answer, statuses] = await Promise.all([\n\t\t\t\t\taxios.get(generateUrl(source.url)),\n\t\t\t\t\tfetchStatuses(axios),\n\t\t\t\t])\n\t\t\t\tconst body = answer && answer.data\n\t\t\t\tconst rows = source.responsePath ? readPath(body, source.responsePath) : body\n\t\t\t\tthis.rows = Array.isArray(rows) ? rows : []\n\t\t\t\tthis.statuses = statuses || {}\n\t\t\t} catch {\n\t\t\t\tthis.rows = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The availability line of a user status.\n\t\t *\n\t\t * @param {object|null} status The user status, or null without one.\n\t\t * @return {string} The line.\n\t\t */\n\t\tlineOf(status) {\n\t\t\tif (!status) {\n\t\t\t\treturn t('nextcloud-vue', 'Absent today')\n\t\t\t}\n\t\t\tconst message = typeof status.message === 'string' ? status.message.trim() : ''\n\t\t\tif (message !== '') {\n\t\t\t\tconst clearAt = Number(status.clearAt)\n\t\t\t\tif (!Number.isFinite(clearAt) || clearAt <= 0) {\n\t\t\t\t\treturn message\n\t\t\t\t}\n\t\t\t\tconst time = new Date(clearAt * 1000).toLocaleTimeString(userLocale() || undefined, { hour: '2-digit', minute: '2-digit' })\n\t\t\t\treturn t('nextcloud-vue', '{message} until {time}', { message, time })\n\t\t\t}\n\t\t\tswitch (status.status) {\n\t\t\t\tcase 'online':\n\t\t\t\t\treturn t('nextcloud-vue', 'Available')\n\t\t\t\tcase 'away':\n\t\t\t\t\treturn t('nextcloud-vue', 'Away')\n\t\t\t\tcase 'dnd':\n\t\t\t\tcase 'busy':\n\t\t\t\t\treturn t('nextcloud-vue', 'Busy')\n\t\t\t\tdefault:\n\t\t\t\t\treturn t('nextcloud-vue', 'Absent today')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The count as words: the content's `countLabel`, else \"{count} open\".\n\t\t *\n\t\t * @param {number} count The open count.\n\t\t * @return {string} The text.\n\t\t */\n\t\tcountText(count) {\n\t\t\tconst label = this.content?.countLabel\n\t\t\tif (label && typeof label === 'object' && typeof label.one === 'string' && typeof label.other === 'string') {\n\t\t\t\treturn this.cnTranslate(count === 1 ? label.one : label.other).replace('{count}', String(count))\n\t\t\t}\n\t\t\treturn n('nextcloud-vue', '{count} open', '{count} open', count, { count })\n\t\t},\n\t},\n}\n\n/**\n * Up to two initials of a name.\n *\n * @param {string} name The name.\n * @return {string} The initials, upper case.\n */\nfunction initialsOf(name) {\n\tconst parts = String(name || '').trim().split(/\\s+/).filter(Boolean)\n\tif (parts.length === 0) {\n\t\treturn ''\n\t}\n\tconst last = parts.length > 1 ? parts[parts.length - 1].charAt(0) : ''\n\treturn (parts[0].charAt(0) + last).toUpperCase()\n}\n\n/**\n * Whether a person is at work today: any status but offline or invisible.\n *\n * @param {object|null} status The user status.\n * @return {boolean} True when present.\n */\nfunction isPresent(status) {\n\treturn !!status && status.status !== 'offline' && status.status !== 'invisible'\n}\n</script>\n\n<style scoped>\n.cn-team-workload__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 14px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-team-workload__member {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-team-workload__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n}\n\n.cn-team-workload__avatar {\n\tdisplay: flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 32px;\n\theight: 32px;\n\tborder-radius: 50%;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-size: 12px;\n\tfont-weight: 700;\n}\n\n.cn-team-workload__who {\n\tdisplay: flex;\n\tflex: 1;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-team-workload__name {\n\tfont-size: 14px;\n}\n\n.cn-team-workload__state {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-team-workload__state--away {\n\tcolor: var(--color-warning-text, var(--color-text-maxcontrast));\n}\n\n.cn-team-workload__count {\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n}\n\n.cn-team-workload__bar {\n\tdisplay: block;\n\theight: 6px;\n\toverflow: hidden;\n\tborder-radius: 3px;\n\tbackground: var(--color-border);\n}\n\n.cn-team-workload__bar-fill {\n\tdisplay: block;\n\theight: 100%;\n\tbackground: var(--color-primary-element);\n}\n\n.cn-team-workload__bar-fill--hot {\n\tbackground: var(--color-error);\n}\n\n.cn-team-workload__state-line {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_toDisplayString","_createElementVNode","_normalizeClass","_normalizeStyle"],"mappings":";;;AASM,EAAA,KAAK,EAAC,kBAAiB;AAAE,EAAA,aAAW,EAAC,kBAAkB;;;;AAC3C,EAAA,KAAA,EAAA,8BAAA;AAAA,EAAA,IAAA,EAAA,QAAA;;;;AAGb,EAAA,KAAA,EAAA,8BAAA;;;;AAGQ,EAAA,KAAK,EAAC,wBAAgB;;AAM1B,MAAA,UAAA,GAAA,EAAA,KAAC,EAAA,uBAAA,GAAA;;AACC,EAAA,KAAK,EAAC,0BAAoB;AAAA,EAAA,aAAA,EAAA,MAAA;;AAC1B,MAAA,UAAA,GAAA,EAAA,KAAI,EAAE,uBAAuB,GAAA;AAC7B,MAAA,UAAA,GAAA,EAAA,KAAA,EAAA,wBAAA,GAAA;AAKA,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,yBAAsB,GAAA;;AAE7B,EAAA,KAAM,EAAA;AAAwB,EAAA,aAAQ,EAAA,MAAA;;;;AAvB9C,EAAA,QAAAA,SAAA,EAAA,EAAAC,kBAAA,QAAA;KACS,KAAO,CAAA,OAAA,IAAA,QAAA,CAAA,OAAA,CAAA,MAAA,KAAA,CAAA;wCAEZ,CAAA,GAAA,YAAA,EAAAC,eAAA,CADD,QAAA,CAAA,YAAA,CAAA,EAAA,CAAA,YAAA;AAEA,QAAA,CAAA,QAAA,CAAA,OAAA,CAAA,MAAA,KAAA,CAAA;wBAAFD,kBAEG,CAAA,GAAA,EAFH,UAEG,EAAAC,eAAA,CADA,QAAU,CAAA,UAAA,CAAA,EAAA,CAAA,YAAA;AAEZ,WAAAF,SAAA,EAAA,EAAAC,kBAAA,OAAA;8BACAA,8CACiB,QAAO,CAAA,OAAA,EAAA,CAAjB,MAAM,KAAA;mCADbA;gBAEC,GAAG,EAAG,MAAK,CAAC,EAAE;AACd,gBAAA,KAAI,EAAA,0BAA2B;6BACrB,EAAC,yBAAyB;;mCAU/B,iBAAA,EAAA;AARH,kBAAAE,kBAAA,CAA8B,MAA9B,EAAA,UAA8B,EAAAD,eAAA,CAAA,MAAA,CAAA,QAAA,CAAA,EAAA,CAAA,YAAA;AAC9B,kBAAAC,kBAAA,CAKE,QALF,UAKE,EAAA;AAJH,oBAAAA,kBAAA,CAAK,QAAL,EAAA,UAAK,EAAAD,eAAA,CAAA,MAAA,CAAA,IAAA,CAAA,EAAA,CAAA,YAAA;oBACLC,kBAEoD,CAAA,MAAA,EAAA;AADnD,sBAAA,KAAE,EAAAC,cAAA,CAAA,CAAA,yBAAA,EAC0C,EAAA,+BAAA,EAAA,CAAA,MAAM,CAAC,SAAA,EAAA,CAAA,CAAA;AAAA,qBAAA,EAAAF,eAAA,CAAA,MAAA,CAAA,IAAA,CAAA,EAAA,CAAA,mBAAA;;AAEpD,kBAAAC,kBAAA,CAAiC,MAAjC,EAAA,UAAiC,EAAAD,eAAA,CAAA,MAAA,CAAA,SAAA,CAAA,EAAA,CAAA,YAAA;;AAEjC,gBAAAC,kBAAA,SAAA;kBACDA,kBAGC,CAAA,MAAA,EAAA;AAFA,oBAAA,KAAC,EAAAC,cAAA,CAAA,CAAA,4BAAA,EACD,EAAA,iCAAA,EAAA,MAAA,CAAA,GAAA,EAAA,CAAA,CAAA;oBACA,KAAA,EAAAC,cAAA,CAAA,EAAA,KAAA,EAAA,MAAA,CAAA,OAAA,GAAA,GAAA,EAAA,CAAA;;;;;;;;;;;"}
@@ -2,7 +2,7 @@ import script from './CnVersionInfoCard.vue2.js';
2
2
  import { render } from './CnVersionInfoCard.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-f0527aa2";
5
+ script.__scopeId = "data-v-61e98520";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -223,6 +223,17 @@ var script = {
223
223
  },
224
224
 
225
225
  computed: {
226
+ /**
227
+ * The colon after each label: none on the compact board card, which
228
+ * sets each label beside its value ("Versie 0.4.47", DqInstellingenAlgemeen);
229
+ * one otherwise, PqBeheer's card included.
230
+ *
231
+ * @return {string} The colon, or ''.
232
+ */
233
+ labelColon() {
234
+ return this.isBoard && this.compact ? '' : ':'
235
+ },
236
+
226
237
  /**
227
238
  * The field labels: the app's, else the library's in the reader's language.
228
239
  *
@@ -1 +1 @@
1
- {"version":3,"file":"CnVersionInfoCard.vue2.js","sources":["../../../../src/components/CnVersionInfoCard/CnVersionInfoCard.vue"],"sourcesContent":["<template>\n\t<CnSettingsSection\n\t\t:name=\"title\"\n\t\t:description=\"description\"\n\t\t:docUrl=\"docUrl\"\n\t\t:loading=\"loading\"\n\t\t:wide=\"isBoard && wide\"\n\t\t:loadingMessage=\"t('nextcloud-vue', 'Loading version information…')\">\n\t\t<!-- Actions slot (top right). Under the board look the same buttons sit\n\t\t in the footer row of the card instead. -->\n\t\t<template v-if=\"!isBoard\" #actions>\n\t\t\t<!-- Update Button -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ updateButtonText }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Additional Actions (slot) -->\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Main content (only shown when not loading) -->\n\t\t<div v-if=\"!loading\" class=\"cn-version-info\" :class=\"{ 'cn-version-info--board': isBoard, 'cn-version-info--compact': isBoard && compact }\">\n\t\t\t<!-- Version card with gray background -->\n\t\t\t<div class=\"cn-version-info__card\">\n\t\t\t\t<h4>{{ cardTitle }}</h4>\n\t\t\t\t<div class=\"cn-version-info__details\">\n\t\t\t\t\t<!-- Application Name (the board card can leave it to its description: `showAppName`) -->\n\t\t\t\t\t<div v-if=\"!isBoard || (showAppName && !compact)\" class=\"cn-version-info__item\" data-testid=\"cn-version-info-app-name\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.appName }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appName }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Version -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.version }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Configured version: when provided, and always in the board look,\n\t\t\t\t\t which draws the row (\"Unknown\" until the app reports it) with the\n\t\t\t\t\t up-to-date state inline (\"0.4.47, bijgewerkt\"). -->\n\t\t\t\t\t<div v-if=\"configuredVersion || isBoard\" class=\"cn-version-info__item\" data-testid=\"cn-version-info-configured\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.configuredVersion }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ isBoard ? boardConfiguredText : configuredVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Additional items -->\n\t\t\t\t\t<div v-for=\"item in additionalItems\" :key=\"item.label\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ item.label }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\" :class=\"item.statusClass\">{{ item.value }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Optional additional items slot -->\n\t\t\t\t\t<slot name=\"additional-items\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- The board card's buttons: update (only while one is due), then the actions. -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"isBoard\"\n\t\t\t\t\tclass=\"cn-version-info__footer-row\"\n\t\t\t\t\t:class=\"{ 'cn-version-info__footer-row--divided': actionsDivider && !compact }\"\n\t\t\t\t\tdata-testid=\"cn-version-info-footer-row\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"showUpdateButton && (!upToDateInline || !isUpToDate || updating)\"\n\t\t\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ updateButtonText }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Optional footer slot -->\n\t\t\t\t<slot name=\"footer\" />\n\t\t\t</div>\n\n\t\t\t<!-- Optional extra cards slot -->\n\t\t\t<slot name=\"extra-cards\" />\n\t\t</div>\n\t</CnSettingsSection>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Update from 'vue-material-design-icons/Update.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { ensureTranslations } from '../../l10n/index.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\n\n/**\n * CnVersionInfoCard - App version information card for admin settings pages.\n *\n * Displays application name, version, and optional configured version with an\n * update button. Wraps CnSettingsSection for consistent admin settings layout.\n *\n * Every Conduction Nextcloud app should show this as the first section on its\n * admin settings page.\n *\n * Basic usage\n * ```vue\n * <CnVersionInfoCard app-name=\"Open Register\" app-version=\"0.2.3\" />\n * ```\n *\n * With update button\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Open Register\"\n * app-version=\"0.2.3\"\n * configured-version=\"0.2.2\"\n * :is-up-to-date=\"false\"\n * :show-update-button=\"true\"\n * :updating=\"isUpdating\"\n * @update=\"runUpdate\" />\n * ```\n *\n * With additional items and actions\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Pipelinq\"\n * app-version=\"0.1.7\"\n * :additional-items=\"[{ label: 'Database', value: 'Connected', statusClass: 'cn-version-info__status--ok' }]\">\n * <template #actions>\n * <NcButton @click=\"clearCache\">Clear App Store Cache</NcButton>\n * </template>\n * </CnVersionInfoCard>\n * ```\n */\nexport default {\n\tname: 'CnVersionInfoCard',\n\n\tcomponents: {\n\t\tCnSettingsSection,\n\t\tNcLoadingIcon,\n\t\tNcButton,\n\t\tCheck,\n\t\tUpdate,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the card is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides. Under `board` the facts are a\n\t\t * two-column list and the actions sit in a footer row.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-version-card-takes-the-board-facts-and-footer\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the card spans the whole settings grid, as the\n\t\t * boards draw the version card. Set to `false` to keep it one card in\n\t\t * the grid. Without the board look it has no effect.\n\t\t *\n\t\t * @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid\n\t\t */\n\t\twide: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Section title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Section description */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Information about the current application installation'),\n\t\t},\n\n\t\t/** Documentation URL (shows info icon next to title) */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Card heading text */\n\t\tcardTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Application information'),\n\t\t},\n\n\t\t/** Application name to display */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Application version string */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Configured version (optional, for apps that track configuration versions separately) */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Board look: draw the \"Application name\" row (PqBeheer does,\n\t\t * dossiq's boards name the app in the description instead).\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tshowAppName: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: draw a rule between the facts and the buttons (PqBeheer\n\t\t * does, dossiq's boards do not).\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tactionsDivider: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: read the up-to-date state in the configured version row\n\t\t * (\"0.4.47, bijgewerkt\", dossiq's boards) instead of a disabled \"Up to\n\t\t * date\" button among the buttons (PqBeheer). The update button still\n\t\t * shows while an update is due.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tinlineUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the compact card of dossiq's boards in one switch: no\n\t\t * application name row, no rule above the buttons, the up-to-date\n\t\t * state inline, and 15px facts. The default keeps PqBeheer's card.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether the app configuration is up to date */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether to show the update button */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether an update is currently in progress */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Additional key-value items to display.\n\t\t * Format: [{ label: 'Label', value: 'Value', statusClass: 'cn-version-info__status--ok' }]\n\t\t */\n\t\tadditionalItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether version info is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Custom labels for the standard fields, `{ appName?, version?, configuredVersion? }`.\n\t\t * A label left out keeps the translated default.\n\t\t */\n\t\tlabels: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['update'],\n\n\tsetup(props) {\n\t\t// An admin page can be an entry with no other library surface: its\n\t\t// chrome reads in the user's language without the app registering.\n\t\tensureTranslations()\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The field labels: the app's, else the library's in the reader's language.\n\t\t *\n\t\t * @return {{appName: string, version: string, configuredVersion: string}}\n\t\t * @spec openspec/changes/version-card-dutch-and-header/specs/settings-board-look/spec.md#requirement-the-admin-chrome-reads-in-the-readers-language\n\t\t */\n\t\tfieldLabels() {\n\t\t\treturn {\n\t\t\t\tappName: t('nextcloud-vue', 'Application name'),\n\t\t\t\tversion: t('nextcloud-vue', 'Version'),\n\t\t\t\tconfiguredVersion: t('nextcloud-vue', 'Configured version'),\n\t\t\t\t...(this.labels || {}),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The board card's configured version line: the version (\"Unknown\"\n\t\t * without one), and with `inlineUpToDate` \", up to date\" when the app\n\t\t * tracks updates and is.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tboardConfiguredText() {\n\t\t\tconst version = this.configuredVersion || t('nextcloud-vue', 'Unknown')\n\t\t\treturn this.upToDateInline && this.showUpdateButton && this.isUpToDate && !this.updating\n\t\t\t\t? t('nextcloud-vue', '{version}, up to date', { version })\n\t\t\t\t: version\n\t\t},\n\n\t\t/** @return {boolean} Whether the up-to-date state reads in the configured version row. */\n\t\tupToDateInline() {\n\t\t\treturn this.inlineUpToDate || this.compact\n\t\t},\n\n\t\t/** @return {string} Button type based on update status */\n\t\tupdateButtonType() {\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\treturn 'error'\n\t\t},\n\n\t\t/** @return {boolean} Whether the update button should be disabled */\n\t\tupdateButtonDisabled() {\n\t\t\treturn this.isUpToDate || this.updating\n\t\t},\n\n\t\t/** @return {string} Update button label text */\n\t\tupdateButtonText() {\n\t\t\tif (this.updating) {\n\t\t\t\treturn t('nextcloud-vue', 'Updating…')\n\t\t\t}\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn t('nextcloud-vue', 'Up to date')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Update')\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\thandleUpdateClick() {\n\t\t\tif (!this.updateButtonDisabled) {\n\t\t\t\tthis.$emit('update')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-info__card {\n\tbackground: var(--color-background-hover);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: 20px;\n\tmargin-bottom: 20px;\n}\n\n.cn-version-info__card h4 {\n\tmargin: 0 0 16px 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-info__details {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-version-info__item {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-info__item:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-info__label {\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-version-info__value {\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n/* Status classes for values */\n.cn-version-info__status--ok {\n\tcolor: var(--color-success);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--warning {\n\tcolor: var(--color-warning);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--error {\n\tcolor: var(--color-error);\n\tfont-weight: 600;\n}\n\n@media (max-width: 768px) {\n\t.cn-version-info__item {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 4px;\n\t}\n\n\t.cn-version-info__label {\n\t\tfont-weight: 600;\n\t}\n\n\t.cn-version-info__value {\n\t\tword-break: break-all;\n\t}\n}\n</style>\n"],"names":["CnSettingsSection","t"],"mappings":"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"}
1
+ {"version":3,"file":"CnVersionInfoCard.vue2.js","sources":["../../../../src/components/CnVersionInfoCard/CnVersionInfoCard.vue"],"sourcesContent":["<template>\n\t<CnSettingsSection\n\t\t:name=\"title\"\n\t\t:description=\"description\"\n\t\t:docUrl=\"docUrl\"\n\t\t:loading=\"loading\"\n\t\t:wide=\"isBoard && wide\"\n\t\t:loadingMessage=\"t('nextcloud-vue', 'Loading version information…')\">\n\t\t<!-- Actions slot (top right). Under the board look the same buttons sit\n\t\t in the footer row of the card instead. -->\n\t\t<template v-if=\"!isBoard\" #actions>\n\t\t\t<!-- Update Button -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ updateButtonText }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Additional Actions (slot) -->\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Main content (only shown when not loading) -->\n\t\t<div v-if=\"!loading\" class=\"cn-version-info\" :class=\"{ 'cn-version-info--board': isBoard, 'cn-version-info--compact': isBoard && compact }\">\n\t\t\t<!-- Version card with gray background -->\n\t\t\t<div class=\"cn-version-info__card\">\n\t\t\t\t<h4>{{ cardTitle }}</h4>\n\t\t\t\t<div class=\"cn-version-info__details\">\n\t\t\t\t\t<!-- Application Name (the board card can leave it to its description: `showAppName`) -->\n\t\t\t\t\t<div v-if=\"!isBoard || (showAppName && !compact)\" class=\"cn-version-info__item\" data-testid=\"cn-version-info-app-name\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.appName }}{{ labelColon }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appName }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Version -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.version }}{{ labelColon }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Configured version: when provided, and always in the board look,\n\t\t\t\t\t which draws the row (\"Unknown\" until the app reports it) with the\n\t\t\t\t\t up-to-date state inline (\"0.4.47, bijgewerkt\"). -->\n\t\t\t\t\t<div v-if=\"configuredVersion || isBoard\" class=\"cn-version-info__item\" data-testid=\"cn-version-info-configured\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.configuredVersion }}{{ labelColon }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ isBoard ? boardConfiguredText : configuredVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Additional items -->\n\t\t\t\t\t<div v-for=\"item in additionalItems\" :key=\"item.label\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ item.label }}{{ labelColon }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\" :class=\"item.statusClass\">{{ item.value }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Optional additional items slot -->\n\t\t\t\t\t<slot name=\"additional-items\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- The board card's buttons: update (only while one is due), then the actions. -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"isBoard\"\n\t\t\t\t\tclass=\"cn-version-info__footer-row\"\n\t\t\t\t\t:class=\"{ 'cn-version-info__footer-row--divided': actionsDivider && !compact }\"\n\t\t\t\t\tdata-testid=\"cn-version-info-footer-row\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"showUpdateButton && (!upToDateInline || !isUpToDate || updating)\"\n\t\t\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ updateButtonText }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Optional footer slot -->\n\t\t\t\t<slot name=\"footer\" />\n\t\t\t</div>\n\n\t\t\t<!-- Optional extra cards slot -->\n\t\t\t<slot name=\"extra-cards\" />\n\t\t</div>\n\t</CnSettingsSection>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Update from 'vue-material-design-icons/Update.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { ensureTranslations } from '../../l10n/index.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\n\n/**\n * CnVersionInfoCard - App version information card for admin settings pages.\n *\n * Displays application name, version, and optional configured version with an\n * update button. Wraps CnSettingsSection for consistent admin settings layout.\n *\n * Every Conduction Nextcloud app should show this as the first section on its\n * admin settings page.\n *\n * Basic usage\n * ```vue\n * <CnVersionInfoCard app-name=\"Open Register\" app-version=\"0.2.3\" />\n * ```\n *\n * With update button\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Open Register\"\n * app-version=\"0.2.3\"\n * configured-version=\"0.2.2\"\n * :is-up-to-date=\"false\"\n * :show-update-button=\"true\"\n * :updating=\"isUpdating\"\n * @update=\"runUpdate\" />\n * ```\n *\n * With additional items and actions\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Pipelinq\"\n * app-version=\"0.1.7\"\n * :additional-items=\"[{ label: 'Database', value: 'Connected', statusClass: 'cn-version-info__status--ok' }]\">\n * <template #actions>\n * <NcButton @click=\"clearCache\">Clear App Store Cache</NcButton>\n * </template>\n * </CnVersionInfoCard>\n * ```\n */\nexport default {\n\tname: 'CnVersionInfoCard',\n\n\tcomponents: {\n\t\tCnSettingsSection,\n\t\tNcLoadingIcon,\n\t\tNcButton,\n\t\tCheck,\n\t\tUpdate,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the card is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides. Under `board` the facts are a\n\t\t * two-column list and the actions sit in a footer row.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-version-card-takes-the-board-facts-and-footer\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the card spans the whole settings grid, as the\n\t\t * boards draw the version card. Set to `false` to keep it one card in\n\t\t * the grid. Without the board look it has no effect.\n\t\t *\n\t\t * @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid\n\t\t */\n\t\twide: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Section title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Section description */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Information about the current application installation'),\n\t\t},\n\n\t\t/** Documentation URL (shows info icon next to title) */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Card heading text */\n\t\tcardTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Application information'),\n\t\t},\n\n\t\t/** Application name to display */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Application version string */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Configured version (optional, for apps that track configuration versions separately) */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Board look: draw the \"Application name\" row (PqBeheer does,\n\t\t * dossiq's boards name the app in the description instead).\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tshowAppName: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: draw a rule between the facts and the buttons (PqBeheer\n\t\t * does, dossiq's boards do not).\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tactionsDivider: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: read the up-to-date state in the configured version row\n\t\t * (\"0.4.47, bijgewerkt\", dossiq's boards) instead of a disabled \"Up to\n\t\t * date\" button among the buttons (PqBeheer). The update button still\n\t\t * shows while an update is due.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tinlineUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the compact card of dossiq's boards in one switch: no\n\t\t * application name row, no rule above the buttons, the up-to-date\n\t\t * state inline, and 15px facts. The default keeps PqBeheer's card.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether the app configuration is up to date */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether to show the update button */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether an update is currently in progress */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Additional key-value items to display.\n\t\t * Format: [{ label: 'Label', value: 'Value', statusClass: 'cn-version-info__status--ok' }]\n\t\t */\n\t\tadditionalItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether version info is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Custom labels for the standard fields, `{ appName?, version?, configuredVersion? }`.\n\t\t * A label left out keeps the translated default.\n\t\t */\n\t\tlabels: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['update'],\n\n\tsetup(props) {\n\t\t// An admin page can be an entry with no other library surface: its\n\t\t// chrome reads in the user's language without the app registering.\n\t\tensureTranslations()\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The colon after each label: none on the compact board card, which\n\t\t * sets each label beside its value (\"Versie 0.4.47\", DqInstellingenAlgemeen);\n\t\t * one otherwise, PqBeheer's card included.\n\t\t *\n\t\t * @return {string} The colon, or ''.\n\t\t */\n\t\tlabelColon() {\n\t\t\treturn this.isBoard && this.compact ? '' : ':'\n\t\t},\n\n\t\t/**\n\t\t * The field labels: the app's, else the library's in the reader's language.\n\t\t *\n\t\t * @return {{appName: string, version: string, configuredVersion: string}}\n\t\t * @spec openspec/changes/version-card-dutch-and-header/specs/settings-board-look/spec.md#requirement-the-admin-chrome-reads-in-the-readers-language\n\t\t */\n\t\tfieldLabels() {\n\t\t\treturn {\n\t\t\t\tappName: t('nextcloud-vue', 'Application name'),\n\t\t\t\tversion: t('nextcloud-vue', 'Version'),\n\t\t\t\tconfiguredVersion: t('nextcloud-vue', 'Configured version'),\n\t\t\t\t...(this.labels || {}),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The board card's configured version line: the version (\"Unknown\"\n\t\t * without one), and with `inlineUpToDate` \", up to date\" when the app\n\t\t * tracks updates and is.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tboardConfiguredText() {\n\t\t\tconst version = this.configuredVersion || t('nextcloud-vue', 'Unknown')\n\t\t\treturn this.upToDateInline && this.showUpdateButton && this.isUpToDate && !this.updating\n\t\t\t\t? t('nextcloud-vue', '{version}, up to date', { version })\n\t\t\t\t: version\n\t\t},\n\n\t\t/** @return {boolean} Whether the up-to-date state reads in the configured version row. */\n\t\tupToDateInline() {\n\t\t\treturn this.inlineUpToDate || this.compact\n\t\t},\n\n\t\t/** @return {string} Button type based on update status */\n\t\tupdateButtonType() {\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\treturn 'error'\n\t\t},\n\n\t\t/** @return {boolean} Whether the update button should be disabled */\n\t\tupdateButtonDisabled() {\n\t\t\treturn this.isUpToDate || this.updating\n\t\t},\n\n\t\t/** @return {string} Update button label text */\n\t\tupdateButtonText() {\n\t\t\tif (this.updating) {\n\t\t\t\treturn t('nextcloud-vue', 'Updating…')\n\t\t\t}\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn t('nextcloud-vue', 'Up to date')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Update')\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\thandleUpdateClick() {\n\t\t\tif (!this.updateButtonDisabled) {\n\t\t\t\tthis.$emit('update')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-info__card {\n\tbackground: var(--color-background-hover);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: 20px;\n\tmargin-bottom: 20px;\n}\n\n.cn-version-info__card h4 {\n\tmargin: 0 0 16px 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-info__details {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-version-info__item {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-info__item:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-info__label {\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-version-info__value {\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n/* Status classes for values */\n.cn-version-info__status--ok {\n\tcolor: var(--color-success);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--warning {\n\tcolor: var(--color-warning);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--error {\n\tcolor: var(--color-error);\n\tfont-weight: 600;\n}\n\n@media (max-width: 768px) {\n\t.cn-version-info__item {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 4px;\n\t}\n\n\t.cn-version-info__label {\n\t\tfont-weight: 600;\n\t}\n\n\t.cn-version-info__value {\n\t\tword-break: break-all;\n\t}\n}\n</style>\n"],"names":["CnSettingsSection","t"],"mappings":"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"}
@@ -47,17 +47,17 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
47
47
  createElementVNode("div", _hoisted_2, [
48
48
  (!$setup.isBoard || ($props.showAppName && !$props.compact))
49
49
  ? (openBlock(), createElementBlock("div", _hoisted_3, [
50
- createElementVNode("span", _hoisted_4, toDisplayString($options.fieldLabels.appName) + ":", 1 /* TEXT */),
50
+ createElementVNode("span", _hoisted_4, toDisplayString($options.fieldLabels.appName) + toDisplayString($options.labelColon), 1 /* TEXT */),
51
51
  createElementVNode("span", _hoisted_5, toDisplayString($props.appName), 1 /* TEXT */)
52
52
  ]))
53
53
  : createCommentVNode("v-if", true),
54
54
  createElementVNode("div", _hoisted_6, [
55
- createElementVNode("span", _hoisted_7, toDisplayString($options.fieldLabels.version) + ":", 1 /* TEXT */),
55
+ createElementVNode("span", _hoisted_7, toDisplayString($options.fieldLabels.version) + toDisplayString($options.labelColon), 1 /* TEXT */),
56
56
  createElementVNode("span", _hoisted_8, toDisplayString($props.appVersion), 1 /* TEXT */)
57
57
  ]),
58
58
  ($props.configuredVersion || $setup.isBoard)
59
59
  ? (openBlock(), createElementBlock("div", _hoisted_9, [
60
- createElementVNode("span", _hoisted_10, toDisplayString($options.fieldLabels.configuredVersion) + ":", 1 /* TEXT */),
60
+ createElementVNode("span", _hoisted_10, toDisplayString($options.fieldLabels.configuredVersion) + toDisplayString($options.labelColon), 1 /* TEXT */),
61
61
  createElementVNode("span", _hoisted_11, toDisplayString($setup.isBoard ? $options.boardConfiguredText : $props.configuredVersion), 1 /* TEXT */)
62
62
  ]))
63
63
  : createCommentVNode("v-if", true),
@@ -66,7 +66,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
66
66
  key: item.label,
67
67
  class: "cn-version-info__item"
68
68
  }, [
69
- createElementVNode("span", _hoisted_12, toDisplayString(item.label) + ":", 1 /* TEXT */),
69
+ createElementVNode("span", _hoisted_12, toDisplayString(item.label) + toDisplayString($options.labelColon), 1 /* TEXT */),
70
70
  createElementVNode("span", {
71
71
  class: normalizeClass(["cn-version-info__value", item.statusClass])
72
72
  }, toDisplayString(item.value), 3 /* TEXT, CLASS */)
@@ -1 +1 @@
1
- {"version":3,"file":"CnVersionInfoCard.vue3.js","sources":["../../../../src/components/CnVersionInfoCard/CnVersionInfoCard.vue?vue&type=template&id=f0527aa2&lang.js"],"sourcesContent":["<template>\n\t<CnSettingsSection\n\t\t:name=\"title\"\n\t\t:description=\"description\"\n\t\t:docUrl=\"docUrl\"\n\t\t:loading=\"loading\"\n\t\t:wide=\"isBoard && wide\"\n\t\t:loadingMessage=\"t('nextcloud-vue', 'Loading version information…')\">\n\t\t<!-- Actions slot (top right). Under the board look the same buttons sit\n\t\t in the footer row of the card instead. -->\n\t\t<template v-if=\"!isBoard\" #actions>\n\t\t\t<!-- Update Button -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ updateButtonText }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Additional Actions (slot) -->\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Main content (only shown when not loading) -->\n\t\t<div v-if=\"!loading\" class=\"cn-version-info\" :class=\"{ 'cn-version-info--board': isBoard, 'cn-version-info--compact': isBoard && compact }\">\n\t\t\t<!-- Version card with gray background -->\n\t\t\t<div class=\"cn-version-info__card\">\n\t\t\t\t<h4>{{ cardTitle }}</h4>\n\t\t\t\t<div class=\"cn-version-info__details\">\n\t\t\t\t\t<!-- Application Name (the board card can leave it to its description: `showAppName`) -->\n\t\t\t\t\t<div v-if=\"!isBoard || (showAppName && !compact)\" class=\"cn-version-info__item\" data-testid=\"cn-version-info-app-name\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.appName }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appName }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Version -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.version }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Configured version: when provided, and always in the board look,\n\t\t\t\t\t which draws the row (\"Unknown\" until the app reports it) with the\n\t\t\t\t\t up-to-date state inline (\"0.4.47, bijgewerkt\"). -->\n\t\t\t\t\t<div v-if=\"configuredVersion || isBoard\" class=\"cn-version-info__item\" data-testid=\"cn-version-info-configured\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.configuredVersion }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ isBoard ? boardConfiguredText : configuredVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Additional items -->\n\t\t\t\t\t<div v-for=\"item in additionalItems\" :key=\"item.label\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ item.label }}:</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\" :class=\"item.statusClass\">{{ item.value }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Optional additional items slot -->\n\t\t\t\t\t<slot name=\"additional-items\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- The board card's buttons: update (only while one is due), then the actions. -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"isBoard\"\n\t\t\t\t\tclass=\"cn-version-info__footer-row\"\n\t\t\t\t\t:class=\"{ 'cn-version-info__footer-row--divided': actionsDivider && !compact }\"\n\t\t\t\t\tdata-testid=\"cn-version-info-footer-row\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"showUpdateButton && (!upToDateInline || !isUpToDate || updating)\"\n\t\t\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ updateButtonText }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Optional footer slot -->\n\t\t\t\t<slot name=\"footer\" />\n\t\t\t</div>\n\n\t\t\t<!-- Optional extra cards slot -->\n\t\t\t<slot name=\"extra-cards\" />\n\t\t</div>\n\t</CnSettingsSection>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Update from 'vue-material-design-icons/Update.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { ensureTranslations } from '../../l10n/index.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\n\n/**\n * CnVersionInfoCard - App version information card for admin settings pages.\n *\n * Displays application name, version, and optional configured version with an\n * update button. Wraps CnSettingsSection for consistent admin settings layout.\n *\n * Every Conduction Nextcloud app should show this as the first section on its\n * admin settings page.\n *\n * Basic usage\n * ```vue\n * <CnVersionInfoCard app-name=\"Open Register\" app-version=\"0.2.3\" />\n * ```\n *\n * With update button\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Open Register\"\n * app-version=\"0.2.3\"\n * configured-version=\"0.2.2\"\n * :is-up-to-date=\"false\"\n * :show-update-button=\"true\"\n * :updating=\"isUpdating\"\n * @update=\"runUpdate\" />\n * ```\n *\n * With additional items and actions\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Pipelinq\"\n * app-version=\"0.1.7\"\n * :additional-items=\"[{ label: 'Database', value: 'Connected', statusClass: 'cn-version-info__status--ok' }]\">\n * <template #actions>\n * <NcButton @click=\"clearCache\">Clear App Store Cache</NcButton>\n * </template>\n * </CnVersionInfoCard>\n * ```\n */\nexport default {\n\tname: 'CnVersionInfoCard',\n\n\tcomponents: {\n\t\tCnSettingsSection,\n\t\tNcLoadingIcon,\n\t\tNcButton,\n\t\tCheck,\n\t\tUpdate,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the card is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides. Under `board` the facts are a\n\t\t * two-column list and the actions sit in a footer row.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-version-card-takes-the-board-facts-and-footer\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the card spans the whole settings grid, as the\n\t\t * boards draw the version card. Set to `false` to keep it one card in\n\t\t * the grid. Without the board look it has no effect.\n\t\t *\n\t\t * @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid\n\t\t */\n\t\twide: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Section title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Section description */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Information about the current application installation'),\n\t\t},\n\n\t\t/** Documentation URL (shows info icon next to title) */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Card heading text */\n\t\tcardTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Application information'),\n\t\t},\n\n\t\t/** Application name to display */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Application version string */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Configured version (optional, for apps that track configuration versions separately) */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Board look: draw the \"Application name\" row (PqBeheer does,\n\t\t * dossiq's boards name the app in the description instead).\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tshowAppName: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: draw a rule between the facts and the buttons (PqBeheer\n\t\t * does, dossiq's boards do not).\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tactionsDivider: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: read the up-to-date state in the configured version row\n\t\t * (\"0.4.47, bijgewerkt\", dossiq's boards) instead of a disabled \"Up to\n\t\t * date\" button among the buttons (PqBeheer). The update button still\n\t\t * shows while an update is due.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tinlineUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the compact card of dossiq's boards in one switch: no\n\t\t * application name row, no rule above the buttons, the up-to-date\n\t\t * state inline, and 15px facts. The default keeps PqBeheer's card.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether the app configuration is up to date */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether to show the update button */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether an update is currently in progress */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Additional key-value items to display.\n\t\t * Format: [{ label: 'Label', value: 'Value', statusClass: 'cn-version-info__status--ok' }]\n\t\t */\n\t\tadditionalItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether version info is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Custom labels for the standard fields, `{ appName?, version?, configuredVersion? }`.\n\t\t * A label left out keeps the translated default.\n\t\t */\n\t\tlabels: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['update'],\n\n\tsetup(props) {\n\t\t// An admin page can be an entry with no other library surface: its\n\t\t// chrome reads in the user's language without the app registering.\n\t\tensureTranslations()\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The field labels: the app's, else the library's in the reader's language.\n\t\t *\n\t\t * @return {{appName: string, version: string, configuredVersion: string}}\n\t\t * @spec openspec/changes/version-card-dutch-and-header/specs/settings-board-look/spec.md#requirement-the-admin-chrome-reads-in-the-readers-language\n\t\t */\n\t\tfieldLabels() {\n\t\t\treturn {\n\t\t\t\tappName: t('nextcloud-vue', 'Application name'),\n\t\t\t\tversion: t('nextcloud-vue', 'Version'),\n\t\t\t\tconfiguredVersion: t('nextcloud-vue', 'Configured version'),\n\t\t\t\t...(this.labels || {}),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The board card's configured version line: the version (\"Unknown\"\n\t\t * without one), and with `inlineUpToDate` \", up to date\" when the app\n\t\t * tracks updates and is.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tboardConfiguredText() {\n\t\t\tconst version = this.configuredVersion || t('nextcloud-vue', 'Unknown')\n\t\t\treturn this.upToDateInline && this.showUpdateButton && this.isUpToDate && !this.updating\n\t\t\t\t? t('nextcloud-vue', '{version}, up to date', { version })\n\t\t\t\t: version\n\t\t},\n\n\t\t/** @return {boolean} Whether the up-to-date state reads in the configured version row. */\n\t\tupToDateInline() {\n\t\t\treturn this.inlineUpToDate || this.compact\n\t\t},\n\n\t\t/** @return {string} Button type based on update status */\n\t\tupdateButtonType() {\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\treturn 'error'\n\t\t},\n\n\t\t/** @return {boolean} Whether the update button should be disabled */\n\t\tupdateButtonDisabled() {\n\t\t\treturn this.isUpToDate || this.updating\n\t\t},\n\n\t\t/** @return {string} Update button label text */\n\t\tupdateButtonText() {\n\t\t\tif (this.updating) {\n\t\t\t\treturn t('nextcloud-vue', 'Updating…')\n\t\t\t}\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn t('nextcloud-vue', 'Up to date')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Update')\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\thandleUpdateClick() {\n\t\t\tif (!this.updateButtonDisabled) {\n\t\t\t\tthis.$emit('update')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-info__card {\n\tbackground: var(--color-background-hover);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: 20px;\n\tmargin-bottom: 20px;\n}\n\n.cn-version-info__card h4 {\n\tmargin: 0 0 16px 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-info__details {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-version-info__item {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-info__item:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-info__label {\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-version-info__value {\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n/* Status classes for values */\n.cn-version-info__status--ok {\n\tcolor: var(--color-success);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--warning {\n\tcolor: var(--color-warning);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--error {\n\tcolor: var(--color-error);\n\tfont-weight: 600;\n}\n\n@media (max-width: 768px) {\n\t.cn-version-info__item {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 4px;\n\t}\n\n\t.cn-version-info__label {\n\t\tfont-weight: 600;\n\t}\n\n\t.cn-version-info__value {\n\t\tword-break: break-all;\n\t}\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_createElementVNode","_openBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass","_renderSlot","_createTextVNode"],"mappings":"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"}
1
+ {"version":3,"file":"CnVersionInfoCard.vue3.js","sources":["../../../../src/components/CnVersionInfoCard/CnVersionInfoCard.vue?vue&type=template&id=61e98520&lang.js"],"sourcesContent":["<template>\n\t<CnSettingsSection\n\t\t:name=\"title\"\n\t\t:description=\"description\"\n\t\t:docUrl=\"docUrl\"\n\t\t:loading=\"loading\"\n\t\t:wide=\"isBoard && wide\"\n\t\t:loadingMessage=\"t('nextcloud-vue', 'Loading version information…')\">\n\t\t<!-- Actions slot (top right). Under the board look the same buttons sit\n\t\t in the footer row of the card instead. -->\n\t\t<template v-if=\"!isBoard\" #actions>\n\t\t\t<!-- Update Button -->\n\t\t\t<NcButton\n\t\t\t\tv-if=\"showUpdateButton\"\n\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ updateButtonText }}\n\t\t\t</NcButton>\n\n\t\t\t<!-- Additional Actions (slot) -->\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Main content (only shown when not loading) -->\n\t\t<div v-if=\"!loading\" class=\"cn-version-info\" :class=\"{ 'cn-version-info--board': isBoard, 'cn-version-info--compact': isBoard && compact }\">\n\t\t\t<!-- Version card with gray background -->\n\t\t\t<div class=\"cn-version-info__card\">\n\t\t\t\t<h4>{{ cardTitle }}</h4>\n\t\t\t\t<div class=\"cn-version-info__details\">\n\t\t\t\t\t<!-- Application Name (the board card can leave it to its description: `showAppName`) -->\n\t\t\t\t\t<div v-if=\"!isBoard || (showAppName && !compact)\" class=\"cn-version-info__item\" data-testid=\"cn-version-info-app-name\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.appName }}{{ labelColon }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appName }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Version -->\n\t\t\t\t\t<div class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.version }}{{ labelColon }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ appVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Configured version: when provided, and always in the board look,\n\t\t\t\t\t which draws the row (\"Unknown\" until the app reports it) with the\n\t\t\t\t\t up-to-date state inline (\"0.4.47, bijgewerkt\"). -->\n\t\t\t\t\t<div v-if=\"configuredVersion || isBoard\" class=\"cn-version-info__item\" data-testid=\"cn-version-info-configured\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ fieldLabels.configuredVersion }}{{ labelColon }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\">{{ isBoard ? boardConfiguredText : configuredVersion }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Additional items -->\n\t\t\t\t\t<div v-for=\"item in additionalItems\" :key=\"item.label\" class=\"cn-version-info__item\">\n\t\t\t\t\t\t<span class=\"cn-version-info__label\">{{ item.label }}{{ labelColon }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-info__value\" :class=\"item.statusClass\">{{ item.value }}</span>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Optional additional items slot -->\n\t\t\t\t\t<slot name=\"additional-items\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- The board card's buttons: update (only while one is due), then the actions. -->\n\t\t\t\t<div\n\t\t\t\t\tv-if=\"isBoard\"\n\t\t\t\t\tclass=\"cn-version-info__footer-row\"\n\t\t\t\t\t:class=\"{ 'cn-version-info__footer-row--divided': actionsDivider && !compact }\"\n\t\t\t\t\tdata-testid=\"cn-version-info-footer-row\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"showUpdateButton && (!upToDateInline || !isUpToDate || updating)\"\n\t\t\t\t\t\t:type=\"updateButtonType\"\n\t\t\t\t\t\t:disabled=\"updateButtonDisabled\"\n\t\t\t\t\t\t@click=\"handleUpdateClick\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"updating\" :size=\"20\" />\n\t\t\t\t\t\t\t<Check v-else-if=\"isUpToDate\" :size=\"20\" />\n\t\t\t\t\t\t\t<Update v-else :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ updateButtonText }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<slot name=\"actions\" />\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Optional footer slot -->\n\t\t\t\t<slot name=\"footer\" />\n\t\t\t</div>\n\n\t\t\t<!-- Optional extra cards slot -->\n\t\t\t<slot name=\"extra-cards\" />\n\t\t</div>\n\t</CnSettingsSection>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcLoadingIcon } from '@nextcloud/vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport Update from 'vue-material-design-icons/Update.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { ensureTranslations } from '../../l10n/index.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\n\n/**\n * CnVersionInfoCard - App version information card for admin settings pages.\n *\n * Displays application name, version, and optional configured version with an\n * update button. Wraps CnSettingsSection for consistent admin settings layout.\n *\n * Every Conduction Nextcloud app should show this as the first section on its\n * admin settings page.\n *\n * Basic usage\n * ```vue\n * <CnVersionInfoCard app-name=\"Open Register\" app-version=\"0.2.3\" />\n * ```\n *\n * With update button\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Open Register\"\n * app-version=\"0.2.3\"\n * configured-version=\"0.2.2\"\n * :is-up-to-date=\"false\"\n * :show-update-button=\"true\"\n * :updating=\"isUpdating\"\n * @update=\"runUpdate\" />\n * ```\n *\n * With additional items and actions\n * ```vue\n * <CnVersionInfoCard\n * app-name=\"Pipelinq\"\n * app-version=\"0.1.7\"\n * :additional-items=\"[{ label: 'Database', value: 'Connected', statusClass: 'cn-version-info__status--ok' }]\">\n * <template #actions>\n * <NcButton @click=\"clearCache\">Clear App Store Cache</NcButton>\n * </template>\n * </CnVersionInfoCard>\n * ```\n */\nexport default {\n\tname: 'CnVersionInfoCard',\n\n\tcomponents: {\n\t\tCnSettingsSection,\n\t\tNcLoadingIcon,\n\t\tNcButton,\n\t\tCheck,\n\t\tUpdate,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the card is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides. Under `board` the facts are a\n\t\t * two-column list and the actions sit in a footer row.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-version-card-takes-the-board-facts-and-footer\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the card spans the whole settings grid, as the\n\t\t * boards draw the version card. Set to `false` to keep it one card in\n\t\t * the grid. Without the board look it has no effect.\n\t\t *\n\t\t * @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid\n\t\t */\n\t\twide: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Section title */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Section description */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Information about the current application installation'),\n\t\t},\n\n\t\t/** Documentation URL (shows info icon next to title) */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Card heading text */\n\t\tcardTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Application information'),\n\t\t},\n\n\t\t/** Application name to display */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Application version string */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Configured version (optional, for apps that track configuration versions separately) */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Board look: draw the \"Application name\" row (PqBeheer does,\n\t\t * dossiq's boards name the app in the description instead).\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tshowAppName: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: draw a rule between the facts and the buttons (PqBeheer\n\t\t * does, dossiq's boards do not).\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tactionsDivider: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: read the up-to-date state in the configured version row\n\t\t * (\"0.4.47, bijgewerkt\", dossiq's boards) instead of a disabled \"Up to\n\t\t * date\" button among the buttons (PqBeheer). The update button still\n\t\t * shows while an update is due.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tinlineUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the compact card of dossiq's boards in one switch: no\n\t\t * application name row, no rule above the buttons, the up-to-date\n\t\t * state inline, and 15px facts. The default keeps PqBeheer's card.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether the app configuration is up to date */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether to show the update button */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether an update is currently in progress */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Additional key-value items to display.\n\t\t * Format: [{ label: 'Label', value: 'Value', statusClass: 'cn-version-info__status--ok' }]\n\t\t */\n\t\tadditionalItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether version info is loading */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Custom labels for the standard fields, `{ appName?, version?, configuredVersion? }`.\n\t\t * A label left out keeps the translated default.\n\t\t */\n\t\tlabels: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['update'],\n\n\tsetup(props) {\n\t\t// An admin page can be an entry with no other library surface: its\n\t\t// chrome reads in the user's language without the app registering.\n\t\tensureTranslations()\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The colon after each label: none on the compact board card, which\n\t\t * sets each label beside its value (\"Versie 0.4.47\", DqInstellingenAlgemeen);\n\t\t * one otherwise, PqBeheer's card included.\n\t\t *\n\t\t * @return {string} The colon, or ''.\n\t\t */\n\t\tlabelColon() {\n\t\t\treturn this.isBoard && this.compact ? '' : ':'\n\t\t},\n\n\t\t/**\n\t\t * The field labels: the app's, else the library's in the reader's language.\n\t\t *\n\t\t * @return {{appName: string, version: string, configuredVersion: string}}\n\t\t * @spec openspec/changes/version-card-dutch-and-header/specs/settings-board-look/spec.md#requirement-the-admin-chrome-reads-in-the-readers-language\n\t\t */\n\t\tfieldLabels() {\n\t\t\treturn {\n\t\t\t\tappName: t('nextcloud-vue', 'Application name'),\n\t\t\t\tversion: t('nextcloud-vue', 'Version'),\n\t\t\t\tconfiguredVersion: t('nextcloud-vue', 'Configured version'),\n\t\t\t\t...(this.labels || {}),\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The board card's configured version line: the version (\"Unknown\"\n\t\t * without one), and with `inlineUpToDate` \", up to date\" when the app\n\t\t * tracks updates and is.\n\t\t *\n\t\t * @return {string}\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tboardConfiguredText() {\n\t\t\tconst version = this.configuredVersion || t('nextcloud-vue', 'Unknown')\n\t\t\treturn this.upToDateInline && this.showUpdateButton && this.isUpToDate && !this.updating\n\t\t\t\t? t('nextcloud-vue', '{version}, up to date', { version })\n\t\t\t\t: version\n\t\t},\n\n\t\t/** @return {boolean} Whether the up-to-date state reads in the configured version row. */\n\t\tupToDateInline() {\n\t\t\treturn this.inlineUpToDate || this.compact\n\t\t},\n\n\t\t/** @return {string} Button type based on update status */\n\t\tupdateButtonType() {\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\treturn 'error'\n\t\t},\n\n\t\t/** @return {boolean} Whether the update button should be disabled */\n\t\tupdateButtonDisabled() {\n\t\t\treturn this.isUpToDate || this.updating\n\t\t},\n\n\t\t/** @return {string} Update button label text */\n\t\tupdateButtonText() {\n\t\t\tif (this.updating) {\n\t\t\t\treturn t('nextcloud-vue', 'Updating…')\n\t\t\t}\n\t\t\tif (this.isUpToDate) {\n\t\t\t\treturn t('nextcloud-vue', 'Up to date')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Update')\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\thandleUpdateClick() {\n\t\t\tif (!this.updateButtonDisabled) {\n\t\t\t\tthis.$emit('update')\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-info__card {\n\tbackground: var(--color-background-hover);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tpadding: 20px;\n\tmargin-bottom: 20px;\n}\n\n.cn-version-info__card h4 {\n\tmargin: 0 0 16px 0;\n\tfont-size: 16px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-info__details {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-version-info__item {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-info__item:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-info__label {\n\tfont-weight: 500;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-version-info__value {\n\tfont-family: 'Courier New', Courier, monospace;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n}\n\n/* Status classes for values */\n.cn-version-info__status--ok {\n\tcolor: var(--color-success);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--warning {\n\tcolor: var(--color-warning);\n\tfont-weight: 600;\n}\n\n.cn-version-info__status--error {\n\tcolor: var(--color-error);\n\tfont-weight: 600;\n}\n\n@media (max-width: 768px) {\n\t.cn-version-info__item {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t\tgap: 4px;\n\t}\n\n\t.cn-version-info__label {\n\t\tfont-weight: 600;\n\t}\n\n\t.cn-version-info__value {\n\t\tword-break: break-all;\n\t}\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_createElementVNode","_openBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass","_renderSlot","_createTextVNode"],"mappings":"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"}
@@ -1,17 +1,18 @@
1
- import __sfc_main$b from '../CnAuditTrailWidget/CnAuditTrailWidget.vue.js';
1
+ import __sfc_main$c from '../CnAuditTrailWidget/CnAuditTrailWidget.vue.js';
2
2
  import __sfc_main$a from '../CnBannerWidget/CnBannerWidget.vue.js';
3
- import __sfc_main$f from '../CnDividerWidget/CnDividerWidget.vue.js';
4
- import __sfc_main$h from '../CnExportsWidget/CnExportsWidget.vue.js';
5
- import __sfc_main$d from '../CnHeaderWidget/CnHeaderWidget.vue.js';
3
+ import __sfc_main$g from '../CnDividerWidget/CnDividerWidget.vue.js';
4
+ import __sfc_main$i from '../CnExportsWidget/CnExportsWidget.vue.js';
5
+ import __sfc_main$e from '../CnHeaderWidget/CnHeaderWidget.vue.js';
6
6
  import __sfc_main$9 from '../CnIntegrationWidget/CnIntegrationWidget.vue.js';
7
7
  import __sfc_main$5 from '../CnNavCardGrid/CnNavCardGrid.vue.js';
8
+ import __sfc_main$b from '../CnNoticeWidget/CnNoticeWidget.vue.js';
8
9
  import __sfc_main$6 from '../CnObjectDataWidget/CnObjectDataWidget.vue.js';
9
10
  import __sfc_main$3 from '../CnObjectGeoWidget/CnObjectGeoWidget.vue.js';
10
11
  import __sfc_main$7 from '../CnObjectMetadataWidget/CnObjectMetadataWidget.vue.js';
11
12
  import __sfc_main$8 from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue.js';
12
- import __sfc_main$g from '../CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js';
13
- import __sfc_main$e from '../CnTextWidget/CnTextWidget.vue.js';
14
- import __sfc_main$c from '../CnTimelineWidget/CnTimelineWidget.vue.js';
13
+ import __sfc_main$h from '../CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue.js';
14
+ import __sfc_main$f from '../CnTextWidget/CnTextWidget.vue.js';
15
+ import __sfc_main$d from '../CnTimelineWidget/CnTimelineWidget.vue.js';
15
16
  import __sfc_main$4 from '../CnWidgetCardGrid/CnWidgetCardGrid.vue.js';
16
17
  import __sfc_main$1 from '../CnWidgetFormRenderer/CnWidgetFormRenderer.vue.js';
17
18
  import __sfc_main$2 from '../CnWidgetMapViewer/CnWidgetMapViewer.vue.js';
@@ -87,13 +88,14 @@ const BUILT_IN_WIDGETS = {
87
88
  related: __sfc_main$8,
88
89
  integration: __sfc_main$9,
89
90
  banner: __sfc_main$a,
90
- 'audit-trail': __sfc_main$b,
91
- timeline: __sfc_main$c,
92
- header: __sfc_main$d,
93
- text: __sfc_main$e,
94
- divider: __sfc_main$f,
95
- 'saved-view-alert': __sfc_main$g,
96
- exports: __sfc_main$h,
91
+ notice: __sfc_main$b,
92
+ 'audit-trail': __sfc_main$c,
93
+ timeline: __sfc_main$d,
94
+ header: __sfc_main$e,
95
+ text: __sfc_main$f,
96
+ divider: __sfc_main$g,
97
+ 'saved-view-alert': __sfc_main$h,
98
+ exports: __sfc_main$i,
97
99
  };
98
100
 
99
101
  export { BUILT_IN_WIDGETS };
@@ -1 +1 @@
1
- {"version":3,"file":"builtInWidgets.js","sources":["../../../../src/components/CnWidgetGrid/builtInWidgets.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2024 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * builtInWidgets — internal registry of the library's built-in v2 widget components.\n *\n * Keys are the `widgetKey` values used in v2 manifests.\n * Values are the Vue component definitions.\n *\n * CnWidgetGrid resolves widget keys first against this registry, then against\n * the consumer-supplied `cnRegistry` inject. A consumer can override a built-in\n * by registering a custom component with the same key in `cnRegistry`.\n *\n * Spec: REQ-MVR-005 (manifest-v2-renderer) — widget key resolution\n */\n\nimport CnAuditTrailWidget from '../CnAuditTrailWidget/CnAuditTrailWidget.vue'\nimport CnBannerWidget from '../CnBannerWidget/CnBannerWidget.vue'\nimport CnDividerWidget from '../CnDividerWidget/CnDividerWidget.vue'\nimport CnExportsWidget from '../CnExportsWidget/CnExportsWidget.vue'\nimport CnHeaderWidget from '../CnHeaderWidget/CnHeaderWidget.vue'\nimport CnIntegrationWidget from '../CnIntegrationWidget/CnIntegrationWidget.vue'\nimport CnNavCardGrid from '../CnNavCardGrid/CnNavCardGrid.vue'\nimport CnObjectDataWidget from '../CnObjectDataWidget/CnObjectDataWidget.vue'\nimport CnObjectGeoWidget from '../CnObjectGeoWidget/CnObjectGeoWidget.vue'\nimport CnObjectMetadataWidget from '../CnObjectMetadataWidget/CnObjectMetadataWidget.vue'\nimport CnRelatedObjectsWidget from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue'\nimport CnSavedViewAlertWidget from '../CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue'\nimport CnTextWidget from '../CnTextWidget/CnTextWidget.vue'\nimport CnTimelineWidget from '../CnTimelineWidget/CnTimelineWidget.vue'\nimport CnWidgetCardGrid from '../CnWidgetCardGrid/CnWidgetCardGrid.vue'\nimport CnWidgetFormRenderer from '../CnWidgetFormRenderer/CnWidgetFormRenderer.vue'\nimport CnWidgetMapViewer from '../CnWidgetMapViewer/CnWidgetMapViewer.vue'\nimport CnWidgetObjectTable from '../CnWidgetObjectTable/CnWidgetObjectTable.vue'\n\n/**\n * Built-in widget registry.\n *\n * The `data` and `metadata` keys are the canonical object-detail widgets:\n * a manifest `type:\"detail\"` page that places `widgetKey:\"data\"` /\n * `widgetKey:\"metadata\"` gets the object's editable property grid /\n * read-only `@self` metadata respectively. Both need the loaded object —\n * `CnPageRenderer` loads it for the detail page and `CnWidgetGrid` merges\n * `{ objectData, schema, objectType, objectId, register, store }` into each\n * widget's props (see CnWidgetGrid.resolvedWidgets), so the manifest entry\n * needs no per-widget `props`.\n *\n * The `integration` key places an OpenRegister integration leaf\n * (`CnIntegrationWidget`) on the page — e.g. Integriq's `sync-contract`\n * (\"Synced from\"). Pick the leaf with `props.only: \"<integrationId>\"`; the\n * object's `register` / `objectId` arrive via the detail-context merge, and\n * the manifest should set `props.schema` to the schema slug (the merged\n * context `schema` is the schema *object*, so an explicit slug prop wins).\n *\n * The `banner` key places a declarative notice banner (CnBannerWidget):\n * `props { variant, text, visibleWhen?, route? }` — see the component for\n * the visibleWhen predicate shape.\n *\n * The `audit-trail` key places the object change-log card\n * (CnAuditTrailWidget) — a detail-page widget whose register / schema /\n * objectId arrive via the detail-context merge (or explicit `props`).\n *\n * The `header` / `text` / `divider` keys reuse the dashboard catalog's\n * content-only presentation widgets on v2 pages: each takes a single\n * `props.content` object with the same shape their dashboard `content`\n * blob uses (see the components' docblocks).\n *\n * The `nav-card-grid` key (ADR-044 §4 cards-collapse) places CnNavCardGrid:\n * a grid of arbitrary navigation-link cards from `props.entries` (the\n * navCardEntry shape). Unlike `card-grid` (CnWidgetCardGrid, which renders\n * OpenRegister objects as CnObjectCard), `nav-card-grid` renders links, not\n * data — the intended remedy for a deep menu group collapsed into one\n * top-level entry via `menu-layout.json` relocations.\n *\n * @type {Record<string, import('vue').Component>}\n */\nexport const BUILT_IN_WIDGETS = {\n\t'object-table': CnWidgetObjectTable,\n\t'form-renderer': CnWidgetFormRenderer,\n\t'map-viewer': CnWidgetMapViewer,\n\t'object-geo': CnObjectGeoWidget,\n\t'card-grid': CnWidgetCardGrid,\n\t'nav-card-grid': CnNavCardGrid,\n\tdata: CnObjectDataWidget,\n\tmetadata: CnObjectMetadataWidget,\n\trelated: CnRelatedObjectsWidget,\n\tintegration: CnIntegrationWidget,\n\tbanner: CnBannerWidget,\n\t'audit-trail': CnAuditTrailWidget,\n\ttimeline: CnTimelineWidget,\n\theader: CnHeaderWidget,\n\ttext: CnTextWidget,\n\tdivider: CnDividerWidget,\n\t'saved-view-alert': CnSavedViewAlertWidget,\n\texports: CnExportsWidget,\n}\n"],"names":["CnWidgetObjectTable","CnWidgetFormRenderer","CnWidgetMapViewer","CnObjectGeoWidget","CnWidgetCardGrid","CnNavCardGrid","CnObjectDataWidget","CnObjectMetadataWidget","CnRelatedObjectsWidget","CnIntegrationWidget","CnBannerWidget","CnAuditTrailWidget","CnTimelineWidget","CnHeaderWidget","CnTextWidget","CnDividerWidget","CnSavedViewAlertWidget","CnExportsWidget"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAmBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,gBAAgB,GAAG;AAChC,CAAC,cAAc,EAAEA,UAAmB;AACpC,CAAC,eAAe,EAAEC,YAAoB;AACtC,CAAC,YAAY,EAAEC,YAAiB;AAChC,CAAC,YAAY,EAAEC,YAAiB;AAChC,CAAC,WAAW,EAAEC,YAAgB;AAC9B,CAAC,eAAe,EAAEC,YAAa;AAC/B,CAAC,IAAI,EAAEC,YAAkB;AACzB,CAAC,QAAQ,EAAEC,YAAsB;AACjC,CAAC,OAAO,EAAEC,YAAsB;AAChC,CAAC,WAAW,EAAEC,YAAmB;AACjC,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,aAAa,EAAEC,YAAkB;AAClC,CAAC,QAAQ,EAAEC,YAAgB;AAC3B,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,IAAI,EAAEC,YAAY;AACnB,CAAC,OAAO,EAAEC,YAAe;AACzB,CAAC,kBAAkB,EAAEC,YAAsB;AAC3C,CAAC,OAAO,EAAEC,YAAe;AACzB;;;;"}
1
+ {"version":3,"file":"builtInWidgets.js","sources":["../../../../src/components/CnWidgetGrid/builtInWidgets.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2024 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * builtInWidgets — internal registry of the library's built-in v2 widget components.\n *\n * Keys are the `widgetKey` values used in v2 manifests.\n * Values are the Vue component definitions.\n *\n * CnWidgetGrid resolves widget keys first against this registry, then against\n * the consumer-supplied `cnRegistry` inject. A consumer can override a built-in\n * by registering a custom component with the same key in `cnRegistry`.\n *\n * Spec: REQ-MVR-005 (manifest-v2-renderer) — widget key resolution\n */\n\nimport CnAuditTrailWidget from '../CnAuditTrailWidget/CnAuditTrailWidget.vue'\nimport CnBannerWidget from '../CnBannerWidget/CnBannerWidget.vue'\nimport CnDividerWidget from '../CnDividerWidget/CnDividerWidget.vue'\nimport CnExportsWidget from '../CnExportsWidget/CnExportsWidget.vue'\nimport CnHeaderWidget from '../CnHeaderWidget/CnHeaderWidget.vue'\nimport CnIntegrationWidget from '../CnIntegrationWidget/CnIntegrationWidget.vue'\nimport CnNavCardGrid from '../CnNavCardGrid/CnNavCardGrid.vue'\nimport CnNoticeWidget from '../CnNoticeWidget/CnNoticeWidget.vue'\nimport CnObjectDataWidget from '../CnObjectDataWidget/CnObjectDataWidget.vue'\nimport CnObjectGeoWidget from '../CnObjectGeoWidget/CnObjectGeoWidget.vue'\nimport CnObjectMetadataWidget from '../CnObjectMetadataWidget/CnObjectMetadataWidget.vue'\nimport CnRelatedObjectsWidget from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue'\nimport CnSavedViewAlertWidget from '../CnSavedViewAlertWidget/CnSavedViewAlertWidget.vue'\nimport CnTextWidget from '../CnTextWidget/CnTextWidget.vue'\nimport CnTimelineWidget from '../CnTimelineWidget/CnTimelineWidget.vue'\nimport CnWidgetCardGrid from '../CnWidgetCardGrid/CnWidgetCardGrid.vue'\nimport CnWidgetFormRenderer from '../CnWidgetFormRenderer/CnWidgetFormRenderer.vue'\nimport CnWidgetMapViewer from '../CnWidgetMapViewer/CnWidgetMapViewer.vue'\nimport CnWidgetObjectTable from '../CnWidgetObjectTable/CnWidgetObjectTable.vue'\n\n/**\n * Built-in widget registry.\n *\n * The `data` and `metadata` keys are the canonical object-detail widgets:\n * a manifest `type:\"detail\"` page that places `widgetKey:\"data\"` /\n * `widgetKey:\"metadata\"` gets the object's editable property grid /\n * read-only `@self` metadata respectively. Both need the loaded object —\n * `CnPageRenderer` loads it for the detail page and `CnWidgetGrid` merges\n * `{ objectData, schema, objectType, objectId, register, store }` into each\n * widget's props (see CnWidgetGrid.resolvedWidgets), so the manifest entry\n * needs no per-widget `props`.\n *\n * The `integration` key places an OpenRegister integration leaf\n * (`CnIntegrationWidget`) on the page — e.g. Integriq's `sync-contract`\n * (\"Synced from\"). Pick the leaf with `props.only: \"<integrationId>\"`; the\n * object's `register` / `objectId` arrive via the detail-context merge, and\n * the manifest should set `props.schema` to the schema slug (the merged\n * context `schema` is the schema *object*, so an explicit slug prop wins).\n *\n * The `banner` key places a declarative notice banner (CnBannerWidget):\n * `props { variant, text, visibleWhen?, route? }` — see the component for\n * the visibleWhen predicate shape.\n *\n * The `audit-trail` key places the object change-log card\n * (CnAuditTrailWidget) — a detail-page widget whose register / schema /\n * objectId arrive via the detail-context merge (or explicit `props`).\n *\n * The `header` / `text` / `divider` keys reuse the dashboard catalog's\n * content-only presentation widgets on v2 pages: each takes a single\n * `props.content` object with the same shape their dashboard `content`\n * blob uses (see the components' docblocks).\n *\n * The `nav-card-grid` key (ADR-044 §4 cards-collapse) places CnNavCardGrid:\n * a grid of arbitrary navigation-link cards from `props.entries` (the\n * navCardEntry shape). Unlike `card-grid` (CnWidgetCardGrid, which renders\n * OpenRegister objects as CnObjectCard), `nav-card-grid` renders links, not\n * data — the intended remedy for a deep menu group collapsed into one\n * top-level entry via `menu-layout.json` relocations.\n *\n * @type {Record<string, import('vue').Component>}\n */\nexport const BUILT_IN_WIDGETS = {\n\t'object-table': CnWidgetObjectTable,\n\t'form-renderer': CnWidgetFormRenderer,\n\t'map-viewer': CnWidgetMapViewer,\n\t'object-geo': CnObjectGeoWidget,\n\t'card-grid': CnWidgetCardGrid,\n\t'nav-card-grid': CnNavCardGrid,\n\tdata: CnObjectDataWidget,\n\tmetadata: CnObjectMetadataWidget,\n\trelated: CnRelatedObjectsWidget,\n\tintegration: CnIntegrationWidget,\n\tbanner: CnBannerWidget,\n\tnotice: CnNoticeWidget,\n\t'audit-trail': CnAuditTrailWidget,\n\ttimeline: CnTimelineWidget,\n\theader: CnHeaderWidget,\n\ttext: CnTextWidget,\n\tdivider: CnDividerWidget,\n\t'saved-view-alert': CnSavedViewAlertWidget,\n\texports: CnExportsWidget,\n}\n"],"names":["CnWidgetObjectTable","CnWidgetFormRenderer","CnWidgetMapViewer","CnObjectGeoWidget","CnWidgetCardGrid","CnNavCardGrid","CnObjectDataWidget","CnObjectMetadataWidget","CnRelatedObjectsWidget","CnIntegrationWidget","CnBannerWidget","CnNoticeWidget","CnAuditTrailWidget","CnTimelineWidget","CnHeaderWidget","CnTextWidget","CnDividerWidget","CnSavedViewAlertWidget","CnExportsWidget"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAoBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,gBAAgB,GAAG;AAChC,CAAC,cAAc,EAAEA,UAAmB;AACpC,CAAC,eAAe,EAAEC,YAAoB;AACtC,CAAC,YAAY,EAAEC,YAAiB;AAChC,CAAC,YAAY,EAAEC,YAAiB;AAChC,CAAC,WAAW,EAAEC,YAAgB;AAC9B,CAAC,eAAe,EAAEC,YAAa;AAC/B,CAAC,IAAI,EAAEC,YAAkB;AACzB,CAAC,QAAQ,EAAEC,YAAsB;AACjC,CAAC,OAAO,EAAEC,YAAsB;AAChC,CAAC,WAAW,EAAEC,YAAmB;AACjC,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,aAAa,EAAEC,YAAkB;AAClC,CAAC,QAAQ,EAAEC,YAAgB;AAC3B,CAAC,MAAM,EAAEC,YAAc;AACvB,CAAC,IAAI,EAAEC,YAAY;AACnB,CAAC,OAAO,EAAEC,YAAe;AACzB,CAAC,kBAAkB,EAAEC,YAAsB;AAC3C,CAAC,OAAO,EAAEC,YAAe;AACzB;;;;"}
@@ -23,6 +23,7 @@ import __sfc_main$2 from '../CnStatsBlockWidget/CnStatsBlockWidget.vue.js';
23
23
  import __sfc_main$3 from '../CnStatsBlockWidgetForm/CnStatsBlockWidgetForm.vue.js';
24
24
  import __sfc_main$l from '../CnTabsWidget/CnTabsWidget.vue.js';
25
25
  import __sfc_main$m from '../CnTabsWidgetForm/CnTabsWidgetForm.vue.js';
26
+ import __sfc_main$r from '../CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js';
26
27
  import __sfc_main$n from '../CnWeekStripWidget/CnWeekStripWidget.vue.js';
27
28
  import __sfc_main$o from '../CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js';
28
29
  import { registerDashboardWidget } from './dashboardWidgetRegistry.js';
@@ -375,6 +376,17 @@ registerDashboardWidget('stacked-bar', {
375
376
  icon: 'ChartBar',
376
377
  });
377
378
 
379
+ // The team today: availability from the Nextcloud user status and each
380
+ // person's open count from the app (DqTeamwachtrij "Team vandaag"). Placed
381
+ // from the manifest: there is no config form yet.
382
+ registerDashboardWidget('team-workload', {
383
+ renderer: __sfc_main$r,
384
+ form: null,
385
+ defaultContent: { source: { url: '', responsePath: '', userField: 'userId', nameField: 'displayName', countField: 'count' } },
386
+ displayName: 'Team workload',
387
+ icon: 'AccountGroup',
388
+ });
389
+
378
390
  /**
379
391
  * Explicit no-op that guarantees this module (and therefore every widget's
380
392
  * self-registration side effect) is evaluated. Now optional: `CnDashboardPage`