@conduction/nextcloud-vue 2.62.0 → 2.64.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 (209) hide show
  1. package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue.js +10 -0
  2. package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue.js.map +1 -0
  3. package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue2.js +189 -0
  4. package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue2.js.map +1 -0
  5. package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue3.js +72 -0
  6. package/dist/esm/components/CnAdminActionCard/CnAdminActionCard.vue3.js.map +1 -0
  7. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +425 -39
  8. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +119 -42
  10. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  11. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +186 -9
  12. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  13. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +65 -42
  14. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  15. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +61 -16
  16. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  17. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  18. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +20 -0
  19. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
  20. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +3 -2
  21. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
  22. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -2
  23. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  24. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  25. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue2.js.map +1 -1
  26. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js +53 -37
  27. package/dist/esm/components/CnChoiceCards/CnChoiceCards.vue3.js.map +1 -1
  28. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +29 -0
  29. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  30. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +152 -135
  31. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  32. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue.js +10 -0
  33. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue.js.map +1 -0
  34. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js +293 -0
  35. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue2.js.map +1 -0
  36. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js +189 -0
  37. package/dist/esm/components/CnDataTable/CnColumnFilterPopover.vue3.js.map +1 -0
  38. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +253 -9
  39. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  40. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +126 -50
  41. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  42. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +66 -14
  43. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  44. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +23 -14
  45. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  46. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  47. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +2 -1
  48. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  49. package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue2.js +3 -1
  50. package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue2.js.map +1 -1
  51. package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue3.js +1 -1
  52. package/dist/esm/components/CnFieldHelper/CnFieldHelper.vue3.js.map +1 -1
  53. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +234 -9
  54. package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
  55. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +96 -57
  56. package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
  57. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +81 -4
  58. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +22 -5
  60. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +81 -2
  62. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  63. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +7 -3
  64. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  65. package/dist/esm/components/CnIndexPage/selfModeActions.js +3 -3
  66. package/dist/esm/components/CnIndexPage/selfModeActions.js.map +1 -1
  67. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +41 -2
  68. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  69. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +8 -3
  70. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  71. package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue2.js +121 -12
  72. package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue2.js.map +1 -1
  73. package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue3.js +3 -1
  74. package/dist/esm/components/CnResourceSelect/CnResourceSelect.vue3.js.map +1 -1
  75. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js +326 -1
  76. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  77. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +112 -26
  78. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  79. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +63 -2
  80. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  81. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +96 -37
  82. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  83. package/dist/esm/components/CnStagesWidget/stagesModel.js +5 -2
  84. package/dist/esm/components/CnStagesWidget/stagesModel.js.map +1 -1
  85. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +52 -2
  86. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  87. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -6
  88. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  89. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +14 -2
  90. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  91. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +2 -1
  92. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  93. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +10 -0
  94. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js.map +1 -0
  95. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +337 -0
  96. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -0
  97. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js +102 -0
  98. package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -0
  99. package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js +34 -0
  100. package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js.map +1 -0
  101. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js +131 -8
  102. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue2.js.map +1 -1
  103. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js +40 -38
  104. package/dist/esm/components/CnWalkthrough/CnWalkthrough.vue3.js.map +1 -1
  105. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +8 -6
  106. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
  107. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
  108. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  109. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +73 -1
  110. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
  111. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +14 -2
  112. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
  113. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js +19 -0
  114. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue2.js.map +1 -1
  115. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js +1 -1
  116. package/dist/esm/components/CnWizardDialog/CnWizardDialog.vue3.js.map +1 -1
  117. package/dist/esm/composables/useDependencyCheck.js +65 -0
  118. package/dist/esm/composables/useDependencyCheck.js.map +1 -0
  119. package/dist/esm/composables/useWalkthrough.js +218 -6
  120. package/dist/esm/composables/useWalkthrough.js.map +1 -1
  121. package/dist/esm/index.js +2 -0
  122. package/dist/esm/index.js.map +1 -1
  123. package/dist/esm/l10n/en.json.js +45 -1
  124. package/dist/esm/l10n/en.json.js.map +1 -1
  125. package/dist/esm/l10n/nl.json.js +45 -1
  126. package/dist/esm/l10n/nl.json.js.map +1 -1
  127. package/dist/esm/nextcloud-vue.css +780 -81
  128. package/dist/esm/store/useObjectStore.js +8 -0
  129. package/dist/esm/store/useObjectStore.js.map +1 -1
  130. package/dist/esm/utils/columnFilters.js +311 -0
  131. package/dist/esm/utils/columnFilters.js.map +1 -0
  132. package/dist/esm/utils/groupAutocomplete.js +123 -0
  133. package/dist/esm/utils/groupAutocomplete.js.map +1 -0
  134. package/dist/esm/utils/libraryWidgetKeys.js +2 -0
  135. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  136. package/dist/esm/utils/pickerOptions.js +198 -0
  137. package/dist/esm/utils/pickerOptions.js.map +1 -0
  138. package/dist/esm/utils/schema.js +83 -7
  139. package/dist/esm/utils/schema.js.map +1 -1
  140. package/dist/esm/utils/schemaRefSlug.js +19 -3
  141. package/dist/esm/utils/schemaRefSlug.js.map +1 -1
  142. package/dist/esm/utils/timelineEvents.js +174 -0
  143. package/dist/esm/utils/timelineEvents.js.map +1 -0
  144. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  145. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  146. package/dist/esm/utils/walkthroughSignals.js +88 -0
  147. package/dist/esm/utils/walkthroughSignals.js.map +1 -0
  148. package/dist/nextcloud-vue.cjs.js +13088 -7937
  149. package/dist/nextcloud-vue.cjs.js.map +2 -2
  150. package/dist/nextcloud-vue.css +780 -81
  151. package/l10n/en.json +45 -0
  152. package/l10n/nl.json +45 -0
  153. package/package.json +1 -1
  154. package/src/components/CnAdminActionCard/CnAdminActionCard.vue +234 -0
  155. package/src/components/CnAdminActionCard/index.js +4 -0
  156. package/src/components/CnAppNav/CnAppNav.vue +568 -43
  157. package/src/components/CnAppRoot/CnAppRoot.md +4 -0
  158. package/src/components/CnAppRoot/CnAppRoot.vue +223 -16
  159. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +61 -16
  160. package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +22 -1
  161. package/src/components/CnCellRenderer/CnCellRenderer.vue +33 -2
  162. package/src/components/CnChoiceCards/CnChoiceCards.vue +56 -31
  163. package/src/components/CnDashboardPage/CnDashboardPage.vue +45 -4
  164. package/src/components/CnDataTable/CnColumnFilterPopover.vue +524 -0
  165. package/src/components/CnDataTable/CnDataTable.md +3 -0
  166. package/src/components/CnDataTable/CnDataTable.vue +305 -5
  167. package/src/components/CnDetailPage/CnDetailPage.md +4 -0
  168. package/src/components/CnDetailPage/CnDetailPage.vue +60 -1
  169. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +2 -2
  170. package/src/components/CnFieldHelper/CnFieldHelper.vue +4 -2
  171. package/src/components/CnFormDialog/CnFormDialog.vue +290 -31
  172. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +116 -6
  173. package/src/components/CnIndexPage/CnIndexPage.vue +87 -4
  174. package/src/components/CnIndexPage/selfModeActions.js +3 -3
  175. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +46 -2
  176. package/src/components/CnResourceSelect/CnResourceSelect.vue +123 -12
  177. package/src/components/CnSetupWizard/CnSetupWizard.vue +392 -3
  178. package/src/components/CnStagesWidget/CnStagesWidget.vue +180 -2
  179. package/src/components/CnStagesWidget/stagesModel.js +5 -2
  180. package/src/components/CnStatWidget/CnStatWidget.vue +57 -3
  181. package/src/components/CnTabsWidget/CnTabsWidget.vue +15 -2
  182. package/src/components/CnTimelineWidget/CnTimelineWidget.vue +477 -0
  183. package/src/components/CnTimelineWidget/dashboardRegistration.js +32 -0
  184. package/src/components/CnTimelineWidget/index.js +4 -0
  185. package/src/components/CnWalkthrough/CnWalkthrough.vue +143 -10
  186. package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
  187. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +1 -0
  188. package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +4 -0
  189. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +107 -1
  190. package/src/components/CnWizardDialog/CnWizardDialog.vue +20 -1
  191. package/src/components/index.js +2 -0
  192. package/src/composables/useDependencyCheck.js +61 -0
  193. package/src/composables/useWalkthrough.js +217 -5
  194. package/src/css/dashboard.css +49 -0
  195. package/src/css/detail-page.css +29 -4
  196. package/src/css/kpi-card.css +24 -1
  197. package/src/css/table.css +99 -6
  198. package/src/index.js +2 -0
  199. package/src/schemas/app-manifest-v2.schema.json +135 -3
  200. package/src/store/useObjectStore.js +8 -0
  201. package/src/utils/columnFilters.js +324 -0
  202. package/src/utils/groupAutocomplete.js +119 -0
  203. package/src/utils/libraryWidgetKeys.js +2 -0
  204. package/src/utils/pickerOptions.js +194 -0
  205. package/src/utils/schema.js +83 -7
  206. package/src/utils/schemaRefSlug.js +19 -3
  207. package/src/utils/timelineEvents.js +171 -0
  208. package/src/utils/validateManifestV2.compiled.js +2 -2
  209. package/src/utils/walkthroughSignals.js +94 -0
@@ -15,39 +15,51 @@
15
15
  </NcNoteCard>
16
16
 
17
17
  <div v-else class="cn-choice-cards__grid" :style="gridStyle">
18
- <label
18
+ <!-- One cell per option: the card's label, and below it whatever the
19
+ `#option-actions` slot adds. The slot sits OUTSIDE the label on
20
+ purpose: a button inside a label is interactive content inside
21
+ interactive content, and a click on it would toggle the radio. -->
22
+ <div
19
23
  v-for="option in normalizedOptions"
20
24
  :key="String(option.value)"
21
- class="cn-choice-cards__option"
22
- :class="{ 'cn-choice-cards__option--selected': isSelected(option) }">
23
- <!-- A REAL, VISIBLE input, not a styled div with a click handler.
24
- It carries the checked state to assistive technology and to
25
- Windows high-contrast mode for free, and it keeps the
26
- selection perceivable without colour (WCAG 1.4.1) — the
27
- card's active border alone would not be. -->
28
- <input
29
- class="cn-choice-cards__input"
30
- :type="multiple ? 'checkbox' : 'radio'"
31
- :name="groupName"
32
- :value="String(option.value)"
33
- :checked="isSelected(option)"
34
- :disabled="disabled"
35
- @change="onToggle(option)">
36
- <CnCard
37
- class="cn-choice-cards__card"
38
- :title="option.label"
39
- titleTag="span"
40
- :description="option.description"
41
- :stats="option.stats || []"
42
- :tags="option.tags || []"
43
- :active="isSelected(option)"
44
- activeVariant="primary"
45
- :descriptionLines="descriptionLines">
46
- <template v-if="option.icon" #icon>
47
- <CnIcon :name="option.icon" :size="20" />
48
- </template>
49
- </CnCard>
50
- </label>
25
+ class="cn-choice-cards__cell">
26
+ <label
27
+ class="cn-choice-cards__option"
28
+ :class="{ 'cn-choice-cards__option--selected': isSelected(option) }">
29
+ <!-- A REAL, VISIBLE input, not a styled div with a click handler.
30
+ It carries the checked state to assistive technology and to
31
+ Windows high-contrast mode for free, and it keeps the
32
+ selection perceivable without colour (WCAG 1.4.1) — the
33
+ card's active border alone would not be. -->
34
+ <input
35
+ class="cn-choice-cards__input"
36
+ :type="multiple ? 'checkbox' : 'radio'"
37
+ :name="groupName"
38
+ :value="String(option.value)"
39
+ :checked="isSelected(option)"
40
+ :disabled="disabled"
41
+ @change="onToggle(option)">
42
+ <CnCard
43
+ class="cn-choice-cards__card"
44
+ :title="option.label"
45
+ titleTag="span"
46
+ :description="option.description"
47
+ :stats="option.stats || []"
48
+ :tags="option.tags || []"
49
+ :active="isSelected(option)"
50
+ activeVariant="primary"
51
+ :descriptionLines="descriptionLines">
52
+ <template v-if="option.icon" #icon>
53
+ <CnIcon :name="option.icon" :size="20" />
54
+ </template>
55
+ </CnCard>
56
+ </label>
57
+ <div v-if="$slots['option-actions']" class="cn-choice-cards__actions">
58
+ <!-- @slot option-actions Content below one card, outside its label
59
+ (e.g. a per-option Load button). Scope: `{ option, selected }`. -->
60
+ <slot name="option-actions" :option="option" :selected="isSelected(option)" />
61
+ </div>
62
+ </div>
51
63
  </div>
52
64
  </fieldset>
53
65
  </template>
@@ -298,6 +310,19 @@ export default {
298
310
  padding: 12px;
299
311
  }
300
312
 
313
+ .cn-choice-cards__cell {
314
+ display: flex;
315
+ flex-direction: column;
316
+ gap: 8px;
317
+ min-inline-size: 0;
318
+ }
319
+
320
+ .cn-choice-cards__actions {
321
+ display: flex;
322
+ flex-direction: column;
323
+ gap: 4px;
324
+ }
325
+
301
326
  .cn-choice-cards__option {
302
327
  position: relative;
303
328
  display: block;
@@ -11,8 +11,14 @@
11
11
  -->
12
12
  <template>
13
13
  <div class="cn-dashboard-page" data-testid="cn-dashboard-page">
14
- <!-- Header -->
15
- <div class="cn-dashboard-page__header" data-testid="cn-dashboard-page-header">
14
+ <!-- Header. `showHeader: false` drops the whole row (title, description,
15
+ header actions, edit toggle) for a page that opens with its own
16
+ heading, such as a greeting; the title then stays as a visually
17
+ hidden heading so the main landmark keeps its name. -->
18
+ <h2 v-if="!showHeader && title" class="hidden-visually" data-testid="cn-dashboard-page-hidden-title">
19
+ {{ resolvedTitle }}
20
+ </h2>
21
+ <div v-if="showHeader" class="cn-dashboard-page__header" data-testid="cn-dashboard-page-header">
16
22
  <div class="cn-dashboard-page__header-left">
17
23
  <div v-if="title || $slots['title-meta']" class="cn-dashboard-page__title-row">
18
24
  <h2 v-if="title" class="cn-dashboard-page__title">
@@ -282,9 +288,9 @@
282
288
  <NcEmptyContent
283
289
  :name="installAppLabel(missingRequiredApp(item))"
284
290
  :description="t('nextcloud-vue', 'This widget shows data from another app that isn\'t installed yet.')"
285
- class="cn-dashboard-page__requires-app">
291
+ class="cn-dashboard-page__requires-app cn-requires-app">
286
292
  <template #icon>
287
- <Download :size="32" />
293
+ <Download :size="24" />
288
294
  </template>
289
295
  <template #action>
290
296
  <NcButton
@@ -320,6 +326,7 @@
320
326
  :borderless="widgetBorderless(item)"
321
327
  :flush="item.flush !== false"
322
328
  :buttons="getWidgetButtons(item)"
329
+ :headerLink="getWidgetHeaderLink(item)"
323
330
  :styleConfig="item.styleConfig || {}"
324
331
  :titleIconPosition="getWidgetTitleIconPosition(item)"
325
332
  :titleIconColor="getWidgetTitleIconColor(item)"
@@ -400,6 +407,7 @@
400
407
  :borderless="widgetBorderless(item)"
401
408
  :flush="item.flush !== false"
402
409
  :buttons="getWidgetButtons(item)"
410
+ :headerLink="getWidgetHeaderLink(item)"
403
411
  :styleConfig="item.styleConfig || {}"
404
412
  :titleIconPosition="getWidgetTitleIconPosition(item)"
405
413
  :titleIconColor="getWidgetTitleIconColor(item)"
@@ -478,6 +486,7 @@
478
486
  :flush="item.flush !== false"
479
487
  :class="{ 'cn-dashboard-page__card-fit': isCardWidget(item) }"
480
488
  :buttons="getWidgetButtons(item)"
489
+ :headerLink="getWidgetHeaderLink(item)"
481
490
  :styleConfig="item.styleConfig || {}"
482
491
  :documentationUrl="getWidgetDocumentationUrl(item)"
483
492
  :docsAnchor="getWidgetDocsAnchor(item)"
@@ -502,6 +511,7 @@
502
511
  :borderless="widgetBorderless(item)"
503
512
  :flush="item.flush !== false"
504
513
  :buttons="getWidgetButtons(item)"
514
+ :headerLink="getWidgetHeaderLink(item)"
505
515
  :styleConfig="item.styleConfig || {}"
506
516
  :titleIconPosition="getWidgetTitleIconPosition(item)"
507
517
  :titleIconColor="getWidgetTitleIconColor(item)"
@@ -537,6 +547,7 @@
537
547
  :iconClass="getWidgetIconClass(item)"
538
548
  :showTitle="widgetShowTitle(item)"
539
549
  :buttons="getWidgetButtons(item)"
550
+ :headerLink="getWidgetHeaderLink(item)"
540
551
  :styleConfig="item.styleConfig || {}"
541
552
  :showRefresh="getWidgetShowRefresh(item)"
542
553
  :documentationUrl="getWidgetDocumentationUrl(item)"
@@ -566,6 +577,7 @@
566
577
  :titleIconVariant="getWidgetTitleIconVariant(item)"
567
578
  :class="{ 'cn-dashboard-page__card-fit': isCardWidget(item) }"
568
579
  :buttons="getWidgetButtons(item)"
580
+ :headerLink="getWidgetHeaderLink(item)"
569
581
  :styleConfig="item.styleConfig || {}"
570
582
  :documentationUrl="getWidgetDocumentationUrl(item)"
571
583
  :docsAnchor="getWidgetDocsAnchor(item)"
@@ -921,6 +933,19 @@ export default {
921
933
  default: '',
922
934
  },
923
935
 
936
+ /**
937
+ * Whether the header row renders: title, description, header actions
938
+ * and the edit toggle. `false` (manifest `config.showHeader: false`)
939
+ * drops it for a page whose first widget is its heading; the title
940
+ * then renders visually hidden so the page keeps an accessible name.
941
+ *
942
+ * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-dashboard-page-can-hide-its-header
943
+ */
944
+ showHeader: {
945
+ type: Boolean,
946
+ default: true,
947
+ },
948
+
924
949
  /**
925
950
  * Widget definitions array. Each widget defines metadata for rendering.
926
951
  *
@@ -3410,6 +3435,22 @@ export default {
3410
3435
  return def?.buttons || []
3411
3436
  },
3412
3437
 
3438
+ /**
3439
+ * The widget's header text link (`headerLink` on the layout entry,
3440
+ * else on the widget definition), forwarded to CnWidgetWrapper.
3441
+ *
3442
+ * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-widget-header-carries-a-text-link
3443
+ * @param {object} item Layout placement entry.
3444
+ * @return {object|null}
3445
+ */
3446
+ getWidgetHeaderLink(item) {
3447
+ if (item?.headerLink && typeof item.headerLink === 'object') {
3448
+ return item.headerLink
3449
+ }
3450
+ const def = this.getWidgetDef(item.widgetId)
3451
+ return (def?.headerLink && typeof def.headerLink === 'object') ? def.headerLink : null
3452
+ },
3453
+
3413
3454
  /**
3414
3455
  * Whether a widget's overflow Actions menu shows the Refresh item.
3415
3456
  * An explicit per-widget flag wins — on the widget definition or