@conduction/nextcloud-vue 2.84.0 → 2.85.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 (166) hide show
  1. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
  2. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +131 -3
  3. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  4. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +54 -18
  5. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  6. package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
  7. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +232 -4
  8. package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
  9. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +95 -51
  10. package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
  11. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue.js +1 -1
  12. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +114 -0
  13. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
  14. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js +2 -2
  15. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
  16. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  17. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +45 -0
  18. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  19. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +22 -12
  20. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  21. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +23 -4
  22. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  23. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  24. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  25. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +3 -1
  26. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  28. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
  29. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +18 -5
  30. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  31. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  32. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +548 -77
  33. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  34. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +191 -82
  35. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  36. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +11 -2
  37. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  38. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  39. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +95 -0
  40. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +24 -2
  42. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  43. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  44. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +70 -2
  45. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  46. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  47. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
  48. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +67 -5
  49. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
  50. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js +181 -124
  51. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
  52. package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue.js +1 -1
  53. package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js +5 -1
  54. package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js.map +1 -1
  55. package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js.map +1 -1
  56. package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
  57. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +134 -10
  58. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  59. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -2
  60. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  61. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  62. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +6 -3
  63. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  64. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  65. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +1 -1
  66. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +140 -7
  67. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -1
  68. package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -1
  69. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
  70. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +37 -9
  71. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
  72. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +6 -5
  73. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
  74. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +1 -1
  75. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +2 -1
  76. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -1
  77. package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -1
  78. package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js +53 -1
  79. package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js.map +1 -1
  80. package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js +3 -2
  81. package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js.map +1 -1
  82. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
  83. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +135 -0
  84. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
  85. package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
  86. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
  87. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +19 -0
  88. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
  89. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +37 -19
  90. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
  91. package/dist/esm/composables/useListView.js +21 -0
  92. package/dist/esm/composables/useListView.js.map +1 -1
  93. package/dist/esm/index.js +1 -0
  94. package/dist/esm/index.js.map +1 -1
  95. package/dist/esm/l10n/en.json.js +23 -1
  96. package/dist/esm/l10n/en.json.js.map +1 -1
  97. package/dist/esm/l10n/nl.json.js +41 -1
  98. package/dist/esm/l10n/nl.json.js.map +1 -1
  99. package/dist/esm/library-style.js +1 -1
  100. package/dist/esm/nextcloud-vue.css +742 -397
  101. package/dist/esm/store/useObjectStore.js +16 -2
  102. package/dist/esm/store/useObjectStore.js.map +1 -1
  103. package/dist/esm/utils/boardColumns.js +8 -1
  104. package/dist/esm/utils/boardColumns.js.map +1 -1
  105. package/dist/esm/utils/boardReferenceColumns.js +278 -0
  106. package/dist/esm/utils/boardReferenceColumns.js.map +1 -0
  107. package/dist/esm/utils/buildManifest.js +4 -1
  108. package/dist/esm/utils/buildManifest.js.map +1 -1
  109. package/dist/esm/utils/gridStack.js +40 -1
  110. package/dist/esm/utils/gridStack.js.map +1 -1
  111. package/dist/esm/utils/humaniseKey.js +41 -0
  112. package/dist/esm/utils/humaniseKey.js.map +1 -0
  113. package/dist/esm/utils/notificationRuleLabel.js +6 -23
  114. package/dist/esm/utils/notificationRuleLabel.js.map +1 -1
  115. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  116. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  117. package/dist/esm/utils/widgetDispatch.js +8 -2
  118. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  119. package/dist/nextcloud-vue.cjs.js +15075 -12590
  120. package/dist/nextcloud-vue.cjs.js.map +2 -2
  121. package/dist/nextcloud-vue.css +742 -397
  122. package/l10n/en.json +23 -1
  123. package/l10n/nl.json +41 -1
  124. package/package.json +1 -1
  125. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +160 -8
  126. package/src/components/CnBoardView/CnBoardView.vue +262 -6
  127. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +116 -2
  128. package/src/components/CnDashboardPage/CnDashboardPage.vue +57 -2
  129. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  130. package/src/components/CnDetailPage/CnDetailPage.vue +23 -4
  131. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +3 -1
  132. package/src/components/CnFactsWidget/CnFactsWidget.vue +18 -5
  133. package/src/components/CnIndexPage/CnIndexPage.vue +586 -25
  134. package/src/components/CnIndexPage/useSelfFetchList.js +10 -1
  135. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +123 -3
  136. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +70 -2
  137. package/src/components/CnRegisterMapping/CnRegisterMapping.md +5 -0
  138. package/src/components/CnRegisterMapping/CnRegisterMapping.vue +231 -96
  139. package/src/components/CnSettingsPage/CnSettingsPage.vue +5 -1
  140. package/src/components/CnStatWidget/CnStatWidget.vue +136 -11
  141. package/src/components/CnTabsWidget/CnTabsWidget.vue +6 -3
  142. package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +140 -7
  143. package/src/components/CnVersionInfoCard/CnVersionInfoCard.md +2 -1
  144. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +42 -13
  145. package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +2 -1
  146. package/src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue +55 -2
  147. package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +135 -0
  148. package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +10 -0
  149. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +44 -1
  150. package/src/composables/useListView.js +21 -0
  151. package/src/css/board.css +65 -4
  152. package/src/css/dialog.css +4 -2
  153. package/src/css/index-page.css +49 -0
  154. package/src/css/kpi-card.css +13 -0
  155. package/src/css/look-board.css +96 -7
  156. package/src/index.js +2 -0
  157. package/src/schemas/app-manifest-v2.schema.json +115 -5
  158. package/src/store/useObjectStore.js +16 -2
  159. package/src/utils/boardColumns.js +8 -1
  160. package/src/utils/boardReferenceColumns.js +274 -0
  161. package/src/utils/buildManifest.js +4 -1
  162. package/src/utils/gridStack.js +39 -0
  163. package/src/utils/humaniseKey.js +38 -0
  164. package/src/utils/notificationRuleLabel.js +5 -23
  165. package/src/utils/validateManifestV2.compiled.js +3 -3
  166. package/src/utils/widgetDispatch.js +8 -2
@@ -1,5 +1,5 @@
1
1
  import { getCurrentUser } from '@nextcloud/auth';
2
- import { translate } from '@nextcloud/l10n';
2
+ import { translate, translatePlural } from '@nextcloud/l10n';
3
3
  import { NcLoadingIcon, NcActions, NcActionLink, NcActionButton, NcActionCaption, NcActionSeparator, NcActionCheckbox, NcButton, NcCheckboxRadioSwitch } from '@nextcloud/vue';
4
4
  import { ref, getCurrentInstance, markRaw, inject } from 'vue';
5
5
  import AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue';
@@ -14,8 +14,8 @@ import ImportIcon from 'vue-material-design-icons/Import.vue';
14
14
  import TrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue';
15
15
  import Tune from 'vue-material-design-icons/Tune.vue';
16
16
  import ViewColumnOutline from 'vue-material-design-icons/ViewColumnOutline.vue';
17
- import __sfc_main$w from '../../dialogs/CnConfirmDialog.vue.js';
18
- import __sfc_main$x from '../../dialogs/CnQuickEditDialog.vue.js';
17
+ import __sfc_main$x from '../../dialogs/CnConfirmDialog.vue.js';
18
+ import __sfc_main$y from '../../dialogs/CnQuickEditDialog.vue.js';
19
19
  import __sfc_main$1 from '../CnBuildiqEditButton/CnBuildiqEditButton.vue.js';
20
20
  import __sfc_main$3 from '../CnEmptyContent/CnEmptyContent.vue.js';
21
21
  import __sfc_main$2 from '../CnFollowToggle/CnFollowToggle.vue.js';
@@ -28,6 +28,7 @@ import { METADATA_COLUMNS } from '../../constants/metadata.js';
28
28
  import { useObjectStore } from '../../store/useObjectStore.js';
29
29
  import { routeHref, followItemActionLink, resolveItemActionLink } from '../../utils/actionLink.js';
30
30
  import { resolveRegisteredHandler, buildOnSuccessRoute } from '../../utils/actionsDispatcher.js';
31
+ import { columnFieldsOf, refIdOf, buildValueStages, buildReferenceStages, columnKeyOfRow, resolveDropValue, referenceTargetOf, fetchReferenceObjects } from '../../utils/boardReferenceColumns.js';
31
32
  import { reportBindingProblems } from '../../utils/diagnostics.js';
32
33
  import { fetchFilterCounts } from '../../utils/fetchFilterCounts.js';
33
34
  import { buildExportUrl } from '../../utils/indexExportHelpers.js';
@@ -37,6 +38,7 @@ import { resolveClaimedTeams, splitViewsIntoTabs, viewAsTab, resolveClaimTokens,
37
38
  import { LIST_SHORTCUTS, listPaletteCommands, shortcutFor } from '../../utils/listShortcuts.js';
38
39
  import { multiKeySort } from '../../utils/multiKeySort.js';
39
40
  import { OBJECTS_CHANGED_EVENT } from '../../utils/objectSignals.js';
41
+ import { objectUrlOf, patchObject } from '../../utils/objectWrite.js';
40
42
  import { withPersonalLenses } from '../../utils/personalLenses.js';
41
43
  import { resolveDeepTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js';
42
44
  import { resolveRowActions } from '../../utils/resolveRowActions.js';
@@ -49,37 +51,38 @@ import { viewMatchesScope, extractViewState, buildRouteQueryFromViewState, extra
49
51
  import { fieldsFromSchema, columnsFromSchema } from '../../utils/schema.js';
50
52
  import { resolveScopeLayout } from '../../utils/scopeListLayout.js';
51
53
  import { dispatchObjectCreated } from '../../utils/walkthroughSignals.js';
52
- import __sfc_main$6 from '../CnActionsBar/CnActionsBar.vue.js';
53
- import __sfc_main$p from '../CnAdvancedFormDialog/CnAdvancedFormDialog.vue.js';
54
+ import __sfc_main$6 from '../CnActionButtons/CnActionButtons.vue.js';
55
+ import __sfc_main$7 from '../CnActionsBar/CnActionsBar.vue.js';
56
+ import __sfc_main$q from '../CnAdvancedFormDialog/CnAdvancedFormDialog.vue.js';
54
57
  import '../CnAdvancedFormDialog/CnMetadataTab.vue.js';
55
58
  import '../CnAdvancedFormDialog/CnPropertiesTab.vue.js';
56
59
  import '../CnAdvancedFormDialog/CnPropertyValueCell.vue.js';
57
- import __sfc_main$a from '../CnBoardView/CnBoardView.vue.js';
58
- import __sfc_main$9 from '../CnCardGrid/CnCardGrid.vue.js';
59
- import __sfc_main$q from '../CnContextMenu/CnContextMenu.vue.js';
60
- import __sfc_main$n from '../CnCopyDialog/CnCopyDialog.vue.js';
61
- import __sfc_main$8 from '../CnDataTable/CnDataTable.vue.js';
62
- import __sfc_main$b from '../CnDateAxisView/CnDateAxisView.vue.js';
63
- import __sfc_main$m from '../CnDeleteDialog/CnDeleteDialog.vue.js';
64
- import __sfc_main$f from '../CnFolderSidebar/CnFolderSidebar.vue.js';
65
- import __sfc_main$o from '../CnFormDialog/CnFormDialog.vue.js';
66
- import __sfc_main$7 from '../CnIcon/CnIcon.vue.js';
67
- import __sfc_main$r from '../CnIndexSidebar/CnIndexSidebar.vue.js';
68
- import __sfc_main$d from '../CnMapWidget/CnMapWidget.vue.js';
69
- import __sfc_main$j from '../CnMassCopyDialog/CnMassCopyDialog.vue.js';
70
- import __sfc_main$i from '../CnMassDeleteDialog/CnMassDeleteDialog.vue.js';
71
- import __sfc_main$k from '../CnMassExportDialog/CnMassExportDialog.vue.js';
72
- import __sfc_main$l from '../CnMassImportDialog/CnMassImportDialog.vue.js';
73
- import __sfc_main$c from '../CnObjectCalendar/CnObjectCalendar.vue.js';
74
- import __sfc_main$e from '../CnObjectList/CnObjectList.vue.js';
60
+ import __sfc_main$b from '../CnBoardView/CnBoardView.vue.js';
61
+ import __sfc_main$a from '../CnCardGrid/CnCardGrid.vue.js';
62
+ import __sfc_main$r from '../CnContextMenu/CnContextMenu.vue.js';
63
+ import __sfc_main$o from '../CnCopyDialog/CnCopyDialog.vue.js';
64
+ import __sfc_main$9 from '../CnDataTable/CnDataTable.vue.js';
65
+ import __sfc_main$c from '../CnDateAxisView/CnDateAxisView.vue.js';
66
+ import __sfc_main$n from '../CnDeleteDialog/CnDeleteDialog.vue.js';
67
+ import __sfc_main$g from '../CnFolderSidebar/CnFolderSidebar.vue.js';
68
+ import __sfc_main$p from '../CnFormDialog/CnFormDialog.vue.js';
69
+ import __sfc_main$8 from '../CnIcon/CnIcon.vue.js';
70
+ import __sfc_main$s from '../CnIndexSidebar/CnIndexSidebar.vue.js';
71
+ import __sfc_main$e from '../CnMapWidget/CnMapWidget.vue.js';
72
+ import __sfc_main$k from '../CnMassCopyDialog/CnMassCopyDialog.vue.js';
73
+ import __sfc_main$j from '../CnMassDeleteDialog/CnMassDeleteDialog.vue.js';
74
+ import __sfc_main$l from '../CnMassExportDialog/CnMassExportDialog.vue.js';
75
+ import __sfc_main$m from '../CnMassImportDialog/CnMassImportDialog.vue.js';
76
+ import __sfc_main$d from '../CnObjectCalendar/CnObjectCalendar.vue.js';
77
+ import __sfc_main$f from '../CnObjectList/CnObjectList.vue.js';
75
78
  import __sfc_main$4 from '../CnPageHeader/CnPageHeader.vue.js';
76
- import __sfc_main$g from '../CnPagination/CnPagination.vue.js';
79
+ import __sfc_main$h from '../CnPagination/CnPagination.vue.js';
77
80
  import __sfc_main$5 from '../CnQuickFilterBar/CnQuickFilterBar.vue.js';
78
- import __sfc_main$h from '../CnRowActions/CnRowActions.vue.js';
79
- import __sfc_main$t from '../CnSavedViewPresentationDialog/CnSavedViewPresentationDialog.vue.js';
80
- import __sfc_main$s from '../CnSavedViewsControl/CnSavedViewsControl.vue.js';
81
- import __sfc_main$u from '../CnSavedViewShareDialog/CnSavedViewShareDialog.vue.js';
82
- import __sfc_main$v from '../CnSaveViewDialog/CnSaveViewDialog.vue.js';
81
+ import __sfc_main$i from '../CnRowActions/CnRowActions.vue.js';
82
+ import __sfc_main$u from '../CnSavedViewPresentationDialog/CnSavedViewPresentationDialog.vue.js';
83
+ import __sfc_main$t from '../CnSavedViewsControl/CnSavedViewsControl.vue.js';
84
+ import __sfc_main$v from '../CnSavedViewShareDialog/CnSavedViewShareDialog.vue.js';
85
+ import __sfc_main$w from '../CnSaveViewDialog/CnSaveViewDialog.vue.js';
83
86
  import { applyAiContext } from './aiContext.js';
84
87
  import { buildDefaultActions } from './defaultActions.js';
85
88
  import { dispatchAction } from './manifestActionDispatch.js';
@@ -88,7 +91,7 @@ import { reconcilePersonalColumns, orderColumns, personalColumnsKey } from './pe
88
91
  import { createSelfModeActions, resolveRowTarget } from './selfModeActions.js';
89
92
  import { applyRowPatches, splitLayoutFor, normalisePaneWidth, rowIdOf } from './splitView.js';
90
93
  import { useNamedSource } from './useNamedSource.js';
91
- import { useSelfFetchList } from './useSelfFetchList.js';
94
+ import { useSelfFetchList, BOARD_PAGE_SIZE } from './useSelfFetchList.js';
92
95
  import { useContextMenu } from '../../composables/useContextMenu.js';
93
96
 
94
97
  /** Rows fetched for one month in calendar mode. */
@@ -343,35 +346,36 @@ var script = {
343
346
  NcCheckboxRadioSwitch,
344
347
  CnPageHeader: __sfc_main$4,
345
348
  CnQuickFilterBar: __sfc_main$5,
346
- CnActionsBar: __sfc_main$6,
349
+ CnActionButtons: __sfc_main$6,
350
+ CnActionsBar: __sfc_main$7,
347
351
  DotsHorizontal,
348
- CnIcon: __sfc_main$7,
349
- CnDataTable: __sfc_main$8,
350
- CnCardGrid: __sfc_main$9,
351
- CnBoardView: __sfc_main$a,
352
- CnDateAxisView: __sfc_main$b,
353
- CnObjectCalendar: __sfc_main$c,
354
- CnMapWidget: __sfc_main$d,
355
- CnObjectList: __sfc_main$e,
356
- CnFolderSidebar: __sfc_main$f,
357
- CnPagination: __sfc_main$g,
358
- CnRowActions: __sfc_main$h,
359
- CnMassDeleteDialog: __sfc_main$i,
360
- CnMassCopyDialog: __sfc_main$j,
361
- CnMassExportDialog: __sfc_main$k,
362
- CnMassImportDialog: __sfc_main$l,
363
- CnDeleteDialog: __sfc_main$m,
364
- CnCopyDialog: __sfc_main$n,
365
- CnFormDialog: __sfc_main$o,
366
- CnAdvancedFormDialog: __sfc_main$p,
367
- CnContextMenu: __sfc_main$q,
368
- CnIndexSidebar: __sfc_main$r,
369
- CnSavedViewsControl: __sfc_main$s,
370
- CnSavedViewPresentationDialog: __sfc_main$t,
371
- CnSavedViewShareDialog: __sfc_main$u,
372
- CnSaveViewDialog: __sfc_main$v,
373
- CnConfirmDialog: __sfc_main$w,
374
- CnQuickEditDialog: __sfc_main$x,
352
+ CnIcon: __sfc_main$8,
353
+ CnDataTable: __sfc_main$9,
354
+ CnCardGrid: __sfc_main$a,
355
+ CnBoardView: __sfc_main$b,
356
+ CnDateAxisView: __sfc_main$c,
357
+ CnObjectCalendar: __sfc_main$d,
358
+ CnMapWidget: __sfc_main$e,
359
+ CnObjectList: __sfc_main$f,
360
+ CnFolderSidebar: __sfc_main$g,
361
+ CnPagination: __sfc_main$h,
362
+ CnRowActions: __sfc_main$i,
363
+ CnMassDeleteDialog: __sfc_main$j,
364
+ CnMassCopyDialog: __sfc_main$k,
365
+ CnMassExportDialog: __sfc_main$l,
366
+ CnMassImportDialog: __sfc_main$m,
367
+ CnDeleteDialog: __sfc_main$n,
368
+ CnCopyDialog: __sfc_main$o,
369
+ CnFormDialog: __sfc_main$p,
370
+ CnAdvancedFormDialog: __sfc_main$q,
371
+ CnContextMenu: __sfc_main$r,
372
+ CnIndexSidebar: __sfc_main$s,
373
+ CnSavedViewsControl: __sfc_main$t,
374
+ CnSavedViewPresentationDialog: __sfc_main$u,
375
+ CnSavedViewShareDialog: __sfc_main$v,
376
+ CnSaveViewDialog: __sfc_main$w,
377
+ CnConfirmDialog: __sfc_main$x,
378
+ CnQuickEditDialog: __sfc_main$y,
375
379
  },
376
380
 
377
381
  /**
@@ -389,6 +393,8 @@ var script = {
389
393
  */
390
394
  inject: {
391
395
  cnCustomComponents: { default: () => ({}) },
396
+ /** The app id CnAppRoot provides, for the plural form of `countSubtitle`. */
397
+ cnAppId: { default: '' },
392
398
  /**
393
399
  * The app manifest, provided by CnAppRoot. A column with `labelField`
394
400
  * and `link: true` finds the referenced schema's detail page here.
@@ -475,10 +481,17 @@ var script = {
475
481
  * shows. Manifest key `config.countSubtitle`. Goes through the host
476
482
  * translate function.
477
483
  *
484
+ * `{ singular, plural }` picks the form by the total ("1 invoice",
485
+ * "12 invoices") through the app's plural translation
486
+ * (`translatePlural` with the app id CnAppRoot provides), so a
487
+ * language with other plural rules gets its own forms.
488
+ *
478
489
  * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-an-index-page-title-is-a-manifest-key
490
+ * @spec openspec/changes/index-count-plural/specs/index-header/spec.md#requirement-the-count-line-takes-a-singular-and-a-plural-form
491
+ * @type {string|{singular: string, plural: string}}
479
492
  */
480
493
  countSubtitle: {
481
- type: String,
494
+ type: [String, Object],
482
495
  default: '',
483
496
  },
484
497
 
@@ -1259,10 +1272,14 @@ var script = {
1259
1272
  default: () => [],
1260
1273
  },
1261
1274
 
1262
- /** Text shown when no items found */
1275
+ /**
1276
+ * Text shown when no items found. The default is the library's own
1277
+ * string, so it reads in the user's language; a page's own text goes
1278
+ * through the app's translate function.
1279
+ */
1263
1280
  emptyText: {
1264
1281
  type: String,
1265
- default: 'No items found',
1282
+ default: () => translate('nextcloud-vue', 'No items found'),
1266
1283
  },
1267
1284
 
1268
1285
  /**
@@ -2284,6 +2301,7 @@ var script = {
2284
2301
  'add',
2285
2302
  'apply-view',
2286
2303
  'board-move',
2304
+ 'board-column-field-change',
2287
2305
  'bulk-action',
2288
2306
  'clear-filters',
2289
2307
  'columns-change',
@@ -2395,10 +2413,21 @@ var script = {
2395
2413
  data() {
2396
2414
  return {
2397
2415
  currentViewMode: this.viewMode,
2416
+ /** The column field the reader picked in the board's column switch; '' = the default. */
2417
+ boardColumnFieldChoice: '',
2418
+ /** The rows a reference column field is built from, by field. */
2419
+ boardRefs: {},
2420
+ /** The options of the board's narrowing select (`board.narrow`). */
2421
+ boardNarrowOptions: [],
2422
+ /** The menu entries CnActionButtons reports for the dialog header actions, each with its `run()`. */
2423
+ dialogHeaderRuns: [],
2398
2424
  /** The visible calendar window `{ rangeStart, rangeEnd }` (ISO dates), or null outside calendar mode. */
2399
2425
  calendarRange: null,
2400
2426
  /** The page size to restore when leaving calendar mode. */
2401
2427
  calendarPrevPageSize: null,
2428
+ // The table's page size while the board view holds the list at
2429
+ // BOARD_PAGE_SIZE; restored on leaving the board.
2430
+ boardPrevPageSize: this.viewMode === 'board' ? ((this.pagination && this.pagination.limit) || 20) : null,
2402
2431
  /** Resolved labels of reference columns: `{ [columnKey]: { [id]: label|null } }`. */
2403
2432
  refLabels: {},
2404
2433
  /** Count per tab-strip index, for the entries that asked for one; null = none. */
@@ -2619,6 +2648,24 @@ var script = {
2619
2648
  *
2620
2649
  * @return {Array<object>}
2621
2650
  */
2651
+ /**
2652
+ * The header actions that open a dialog: `type: "open-form"` (the
2653
+ * schema-driven create form, as the navigation's primary action opens
2654
+ * it) or `type: "open-modal"`, without a `handler` of their own.
2655
+ * Reserved ids are left out, as in `mergedHeaderActions`.
2656
+ *
2657
+ * @spec openspec/changes/index-header-open-form/specs/index-header/spec.md#requirement-an-index-header-action-can-open-the-create-form
2658
+ * @return {Array<object>}
2659
+ */
2660
+ dialogHeaderActions() {
2661
+ const reserved = new Set(['refresh', 'import', 'export', 'copy', 'delete']);
2662
+ return (this.headerActions || []).filter((entry) => entry
2663
+ && typeof entry.id === 'string'
2664
+ && !reserved.has(entry.id)
2665
+ && (entry.handler === undefined || entry.handler === null || entry.handler === '')
2666
+ && (entry.type === 'open-form' || entry.type === 'open-modal'))
2667
+ },
2668
+
2622
2669
  mergedHeaderActions() {
2623
2670
  const reserved = new Set(['refresh', 'import', 'export', 'copy', 'delete']);
2624
2671
  const merged = [];
@@ -2971,6 +3018,241 @@ var script = {
2971
3018
  })
2972
3019
  },
2973
3020
 
3021
+ /**
3022
+ * The column fields the board offers (`board.columnFields`), for the
3023
+ * column switch (screens-board-reference-columns).
3024
+ *
3025
+ * @return {Array<object>} The normalised fields; empty for a board on `statusField` only.
3026
+ * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-board-can-switch-the-field-its-columns-come-from
3027
+ */
3028
+ boardColumnFields() {
3029
+ return columnFieldsOf(this.board)
3030
+ },
3031
+
3032
+ /**
3033
+ * The column field in use: the reader's pick, else the one on
3034
+ * `statusField`, else the first. Null on a board without `columnFields`.
3035
+ *
3036
+ * @return {object|null} The normalised column field.
3037
+ */
3038
+ boardActiveColumnField() {
3039
+ const fields = this.boardColumnFields;
3040
+ if (fields.length === 0) {
3041
+ return null
3042
+ }
3043
+ return fields.find((entry) => entry.field === this.boardColumnFieldChoice)
3044
+ || fields.find((entry) => entry.field === this.board?.statusField)
3045
+ || fields[0]
3046
+ },
3047
+
3048
+ /** @return {string} The row field the columns come from. */
3049
+ boardColumnField() {
3050
+ return this.boardActiveColumnField?.field || this.board?.statusField || 'status'
3051
+ },
3052
+
3053
+ /**
3054
+ * The parent the board is narrowed to: the single value of the page
3055
+ * filter on the reference's `narrowBy.rowField`, '' when none or several.
3056
+ *
3057
+ * @return {string} The parent id.
3058
+ */
3059
+ boardNarrowValue() {
3060
+ const field = this.board?.narrow?.field || this.boardActiveColumnField?.source?.narrowBy?.rowField;
3061
+ if (!field) {
3062
+ return ''
3063
+ }
3064
+ const current = this.effectiveActiveFilters?.[field];
3065
+ const values = Array.isArray(current) ? current : (current === undefined || current === null || current === '' ? [] : [current]);
3066
+ return values.length === 1 ? refIdOf(values[0]) : ''
3067
+ },
3068
+
3069
+ /**
3070
+ * The stages of a reference or values column field, or null for a
3071
+ * field the schema's enum or lifecycle states back.
3072
+ *
3073
+ * @return {object|null} `{ states, keyByValue, refsByKey }`.
3074
+ * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references
3075
+ */
3076
+ boardStages() {
3077
+ const active = this.boardActiveColumnField;
3078
+ if (!active) {
3079
+ return null
3080
+ }
3081
+ if (active.kind === 'values') {
3082
+ return buildValueStages({
3083
+ rows: this.displayObjects,
3084
+ field: active.field,
3085
+ valueLabels: active.valueLabels,
3086
+ emptyLabel: active.emptyLabel ? this.cnTranslate(active.emptyLabel) : translate('nextcloud-vue', 'Nobody'),
3087
+ })
3088
+ }
3089
+ if (active.kind !== 'reference') {
3090
+ return null
3091
+ }
3092
+ const source = active.source || {};
3093
+ const narrowBy = source.narrowBy && typeof source.narrowBy === 'object' ? source.narrowBy : null;
3094
+ return buildReferenceStages({
3095
+ refs: this.boardRefs[active.field] || [],
3096
+ labelField: source.labelField || '',
3097
+ orderField: source.orderField || '',
3098
+ colorField: source.colorField || '',
3099
+ mergeBy: source.mergeBy || '',
3100
+ narrowBy,
3101
+ narrowValue: narrowBy ? this.boardNarrowValue : '',
3102
+ })
3103
+ },
3104
+
3105
+ /**
3106
+ * The field schema the board reads its columns from: the stages of a
3107
+ * reference or values field as lifecycle `states`, else the schema's
3108
+ * own property.
3109
+ *
3110
+ * @return {?object} The field schema, or null.
3111
+ */
3112
+ boardFieldSchema() {
3113
+ if (this.boardStages) {
3114
+ return { states: this.boardStages.states }
3115
+ }
3116
+ const field = this.boardColumnField;
3117
+ return this.effectiveSchema?.properties?.[field] || null
3118
+ },
3119
+
3120
+ /**
3121
+ * The column a card sits in, for a reference or values field.
3122
+ *
3123
+ * @return {((row: object) => string)|null} The mapper, or null.
3124
+ */
3125
+ boardColumnKeyOf() {
3126
+ const stages = this.boardStages;
3127
+ if (!stages) {
3128
+ return null
3129
+ }
3130
+ const field = this.boardColumnField;
3131
+ return (row) => columnKeyOfRow(row, field, stages.keyByValue)
3132
+ },
3133
+
3134
+ /**
3135
+ * The move the board runs on a drop or a menu pick.
3136
+ *
3137
+ * A named handler (`moveHandler`, from the app's registry) gets
3138
+ * `{ card, toKey, field, value, target }` and owns the write; the
3139
+ * status of a case goes through the app's transition this way. A
3140
+ * reference or values field without one has its value written on the
3141
+ * row (PATCH). `readOnly` gives no move. A board on `statusField` with
3142
+ * neither keeps the `runTransition` prop.
3143
+ *
3144
+ * @return {((move: {card: object, toKey: string}) => Promise<object>)|null} The move, or null for a read-only board.
3145
+ * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-drop-writes-the-reference
3146
+ */
3147
+ boardRunTransition() {
3148
+ const active = this.boardActiveColumnField;
3149
+ if (active?.readOnly) {
3150
+ return null
3151
+ }
3152
+ const onStatusField = !active || active.field === this.board?.statusField;
3153
+ const name = active?.moveHandler || (onStatusField ? (this.board?.moveHandler || '') : '');
3154
+ const handler = name ? resolveRegisteredHandler(name, this.effectiveRegistry, this.resolvedCustomComponents) : null;
3155
+ if (name && typeof handler !== 'function') {
3156
+ return null
3157
+ }
3158
+ const stages = this.boardStages;
3159
+ if (!handler && !stages) {
3160
+ return this.runTransition
3161
+ }
3162
+ const field = this.boardColumnField;
3163
+ const kind = active?.kind || 'schema';
3164
+ const narrowBy = active?.source?.narrowBy || null;
3165
+ return async ({ card, toKey }) => {
3166
+ const drop = stages
3167
+ ? resolveDropValue({ card, toKey, kind, refsByKey: stages.refsByKey, narrowBy })
3168
+ : { value: toKey, target: null };
3169
+ if (drop === null) {
3170
+ throw new Error(translate('nextcloud-vue', 'This card cannot move to that column.'))
3171
+ }
3172
+ if (handler) {
3173
+ return handler({ card, toKey, field, value: drop.value, target: drop.target })
3174
+ }
3175
+ const id = card?.id ?? card?.['@self']?.id ?? card?.[this.rowKey];
3176
+ const url = objectUrlOf(this.register, this.exportSchemaSlug, id);
3177
+ if (url === '') {
3178
+ throw new Error(translate('nextcloud-vue', 'This card cannot move to that column.'))
3179
+ }
3180
+ return patchObject(url, { [field]: drop.value })
3181
+ }
3182
+ },
3183
+
3184
+ /**
3185
+ * Where a card may go, from the app's `moveTargetsHandler`: it gets
3186
+ * `{ card, field }` and answers the values (referenced ids) the card
3187
+ * can reach; the board maps them to its columns.
3188
+ *
3189
+ * @return {((card: object) => Promise<Array<string>|null>)|null} The question, or null.
3190
+ * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-the-board-shows-where-a-card-can-go
3191
+ */
3192
+ boardAllowedMoves() {
3193
+ const active = this.boardActiveColumnField;
3194
+ const onStatusField = !active || active.field === this.board?.statusField;
3195
+ const name = active?.moveTargetsHandler || (onStatusField ? (this.board?.moveTargetsHandler || '') : '');
3196
+ const handler = name ? resolveRegisteredHandler(name, this.effectiveRegistry, this.resolvedCustomComponents) : null;
3197
+ if (typeof handler !== 'function' || this.boardRunTransition === null) {
3198
+ return null
3199
+ }
3200
+ const field = this.boardColumnField;
3201
+ const stages = this.boardStages;
3202
+ return async (card) => {
3203
+ const values = await handler({ card, field });
3204
+ if (!Array.isArray(values)) {
3205
+ return null
3206
+ }
3207
+ return values.map((value) => {
3208
+ const id = refIdOf(value);
3209
+ return stages && stages.keyByValue.has(id) ? stages.keyByValue.get(id) : id
3210
+ })
3211
+ }
3212
+ },
3213
+
3214
+ /** @return {object|null} The board's narrowing select (`board.narrow`). */
3215
+ boardNarrow() {
3216
+ const narrow = this.board?.narrow;
3217
+ return narrow && typeof narrow === 'object' && typeof narrow.field === 'string' && narrow.field !== '' ? narrow : null
3218
+ },
3219
+
3220
+ /** @return {string} The narrowing select's label, with its colon. */
3221
+ boardNarrowLabel() {
3222
+ const narrow = this.boardNarrow || {};
3223
+ const prop = (this.effectiveSchema?.properties || {})[narrow.field] || {};
3224
+ return translate('nextcloud-vue', '{label}:', { label: this.cnTranslate(narrow.label || prop.title || narrow.field || '') })
3225
+ },
3226
+
3227
+ /** @return {string} The narrowing select's "all" option. */
3228
+ boardNarrowAllLabel() {
3229
+ return this.boardNarrow?.allLabel ? this.cnTranslate(this.boardNarrow.allLabel) : translate('nextcloud-vue', 'All')
3230
+ },
3231
+
3232
+ /** @return {string} The column switch's label, with its colon. */
3233
+ boardColumnSwitchLabel() {
3234
+ const label = this.board?.columnSwitchLabel ? this.cnTranslate(this.board.columnSwitchLabel) : translate('nextcloud-vue', 'Columns');
3235
+ return translate('nextcloud-vue', '{label}:', { label })
3236
+ },
3237
+
3238
+ /** @return {boolean} Whether the board view draws its controls row. */
3239
+ boardControlsShown() {
3240
+ return this.currentViewMode === 'board'
3241
+ && (this.boardColumnFields.length > 1 || this.boardNarrow !== null || Boolean(this.board?.hint))
3242
+ },
3243
+
3244
+ /**
3245
+ * What the board needs fetched, as one key the watcher reacts to.
3246
+ *
3247
+ * @return {string} The key, '' outside the board view.
3248
+ */
3249
+ boardFetchKey() {
3250
+ if (this.currentViewMode !== 'board') {
3251
+ return ''
3252
+ }
3253
+ return [this.boardColumnField, this.boardActiveColumnField?.kind || '', this.effectiveSchema ? 1 : 0, this.boardNarrow ? this.boardNarrow.field : ''].join('|')
3254
+ },
3255
+
2974
3256
  /**
2975
3257
  * The status field's schema, for the board's columns.
2976
3258
  *
@@ -3017,9 +3299,36 @@ var script = {
3017
3299
  * @return {boolean} True when there is more than this page.
3018
3300
  */
3019
3301
  isPaged() {
3302
+ if (this.boardLoadsAll) {
3303
+ const loaded = this.effectivePagination || {};
3304
+ return Number(loaded.page || 1) < Number(loaded.pages || 1)
3305
+ }
3020
3306
  return Number(this.pagination?.pages || 1) > 1
3021
3307
  },
3022
3308
 
3309
+ /**
3310
+ * Whether the board view gathers every row itself: in self-fetch mode
3311
+ * it adds page after page (`list.loadMore`) instead of paging, and
3312
+ * draws its own footer in place of the pagination.
3313
+ *
3314
+ * @return {boolean} True for a self-fetching page in board view.
3315
+ * @spec openspec/changes/board-loads-every-row/specs/board-view/spec.md#requirement-the-index-board-shows-every-matching-row
3316
+ */
3317
+ boardLoadsAll() {
3318
+ return this.currentViewMode === 'board' && this.isSelfFetchMode && !this.isNamedSource && typeof this.list.loadMore === 'function'
3319
+ },
3320
+
3321
+ /**
3322
+ * The rows the board holds against the rows that match, for the
3323
+ * board's footer.
3324
+ *
3325
+ * @return {{shown: number, total: number}} The counts.
3326
+ */
3327
+ boardLoadCounts() {
3328
+ const shown = this.effectiveObjects.length;
3329
+ return { shown, total: Math.max(shown, Number(this.effectivePagination?.total || 0)) }
3330
+ },
3331
+
3023
3332
  /**
3024
3333
  * The CnFolderSidebar source. A `register` source is fetched by this
3025
3334
  * component and handed to CnFolderSidebar as a `custom` folder list.
@@ -4822,13 +5131,15 @@ var script = {
4822
5131
  if (!this.countText && !this.countSubtitle) {
4823
5132
  return translate('nextcloud-vue', '{shown} of {total}', { shown, total })
4824
5133
  }
4825
- const template = this.countText || this.countSubtitle;
4826
- return this.cnTranslate(template)
4827
- .replace('{shown}', String(shown))
4828
- .replace('{total}', String(total))
5134
+ if (this.countText) {
5135
+ return this.cnTranslate(this.countText)
5136
+ .replace('{shown}', String(shown))
5137
+ .replace('{total}', String(total))
5138
+ }
5139
+ return this.countLine(this.countSubtitle, total, shown)
4829
5140
  }
4830
5141
  if (this.countSubtitle && typeof total === 'number' && total >= 0) {
4831
- return this.cnTranslate(this.countSubtitle).replace('{total}', String(total))
5142
+ return this.countLine(this.countSubtitle, total, null)
4832
5143
  }
4833
5144
  return this.description
4834
5145
  },
@@ -4994,6 +5305,19 @@ var script = {
4994
5305
  },
4995
5306
 
4996
5307
  watch: {
5308
+ '$route.query._view': function() {
5309
+ this.applyViewModeFromRoute();
5310
+ },
5311
+
5312
+ boardFetchKey: {
5313
+ immediate: true,
5314
+ handler(key) {
5315
+ if (key !== '') {
5316
+ this.loadBoardSources();
5317
+ }
5318
+ },
5319
+ },
5320
+
4997
5321
  effectiveObjects: {
4998
5322
  immediate: true,
4999
5323
  handler(rows) {
@@ -5067,22 +5391,33 @@ var script = {
5067
5391
  // Entering calendar mode fetches one page sized to the month; leaving
5068
5392
  // removes the month range and restores the page size, so the table is
5069
5393
  // never left narrowed.
5394
+ // The board does the same at BOARD_PAGE_SIZE, so it shows every row
5395
+ // rather than the table's first page.
5070
5396
  currentViewMode(mode, previous) {
5071
5397
  if (!this.isSelfFetchMode) {
5072
5398
  return
5073
5399
  }
5074
- if (mode === 'calendar') {
5075
- this.calendarPrevPageSize = this.list.pageSize.value;
5076
- if (typeof this.list.onPageSizeChange === 'function') {
5077
- this.list.onPageSizeChange(CALENDAR_PAGE_SIZE);
5078
- }
5079
- } else if (previous === 'calendar') {
5400
+ let listSize = this.list.pageSize.value;
5401
+ if (previous === 'calendar') {
5080
5402
  this.calendarRange = null;
5081
- const restore = this.calendarPrevPageSize || 20;
5403
+ listSize = this.calendarPrevPageSize || 20;
5082
5404
  this.calendarPrevPageSize = null;
5083
- if (typeof this.list.onPageSizeChange === 'function') {
5084
- this.list.onPageSizeChange(restore);
5085
- }
5405
+ } else if (previous === 'board') {
5406
+ listSize = this.boardPrevPageSize || 20;
5407
+ this.boardPrevPageSize = null;
5408
+ }
5409
+ let size = null;
5410
+ if (mode === 'calendar') {
5411
+ this.calendarPrevPageSize = listSize;
5412
+ size = CALENDAR_PAGE_SIZE;
5413
+ } else if (mode === 'board') {
5414
+ this.boardPrevPageSize = listSize;
5415
+ size = BOARD_PAGE_SIZE;
5416
+ } else if (previous === 'calendar' || previous === 'board') {
5417
+ size = listSize;
5418
+ }
5419
+ if (size !== null && typeof this.list.onPageSizeChange === 'function') {
5420
+ this.list.onPageSizeChange(size);
5086
5421
  }
5087
5422
  },
5088
5423
 
@@ -5237,6 +5572,7 @@ var script = {
5237
5572
  },
5238
5573
 
5239
5574
  created() {
5575
+ this.applyViewModeFromRoute();
5240
5576
  this.pushAiContext();
5241
5577
  if (this.allowSavedViews) {
5242
5578
  this.fetchSavedViews();
@@ -6019,6 +6355,11 @@ var script = {
6019
6355
  const entry = this.mergedHeaderActions.find((e) => e.id === id);
6020
6356
  if (entry && typeof entry.handler === 'function') {
6021
6357
  entry.handler();
6358
+ } else {
6359
+ const dialogRun = this.dialogHeaderRuns.find((e) => e.id === id);
6360
+ if (dialogRun && typeof dialogRun.run === 'function') {
6361
+ dialogRun.run();
6362
+ }
6022
6363
  }
6023
6364
  if (entry && entry._dispatchSuppress) {
6024
6365
  return
@@ -6026,6 +6367,49 @@ var script = {
6026
6367
  this.$emit('header-action', { action: id, id });
6027
6368
  },
6028
6369
 
6370
+ /**
6371
+ * The `countSubtitle` line for a total. A string goes through the host
6372
+ * translate; `{ singular, plural }` takes the form for the total
6373
+ * through the app's plural translation, or by `total === 1` when no app
6374
+ * id is provided. `{total}` (and `{shown}` when given) are filled in.
6375
+ *
6376
+ * @spec openspec/changes/index-count-plural/specs/index-header/spec.md#requirement-the-count-line-takes-a-singular-and-a-plural-form
6377
+ * @param {string|{singular: string, plural: string}} subtitle The declared line.
6378
+ * @param {number} total The collection's total.
6379
+ * @param {number|null} shown The rows on this page, or null to leave `{shown}` alone.
6380
+ * @return {string} The line, '' for a declaration without both forms.
6381
+ */
6382
+ countLine(subtitle, total, shown) {
6383
+ const fill = (text) => {
6384
+ const out = String(text).replace('{total}', String(total));
6385
+ return shown === null ? out : out.replace('{shown}', String(shown))
6386
+ };
6387
+ if (typeof subtitle === 'string') {
6388
+ return fill(this.cnTranslate(subtitle))
6389
+ }
6390
+ const singular = subtitle && typeof subtitle.singular === 'string' ? subtitle.singular : '';
6391
+ const plural = subtitle && typeof subtitle.plural === 'string' ? subtitle.plural : '';
6392
+ if (singular === '' || plural === '') {
6393
+ return ''
6394
+ }
6395
+ if (typeof this.cnAppId === 'string' && this.cnAppId !== '') {
6396
+ const vars = shown === null ? { total } : { total, shown };
6397
+ return translatePlural(this.cnAppId, singular, plural, total, vars)
6398
+ }
6399
+ return fill(this.cnTranslate(total === 1 ? singular : plural))
6400
+ },
6401
+
6402
+ /**
6403
+ * An `open-form` header action saved a record: the list reloads so the
6404
+ * new row shows.
6405
+ *
6406
+ * @spec openspec/changes/index-header-open-form/specs/index-header/spec.md#requirement-an-index-header-action-can-open-the-create-form
6407
+ * @return {void}
6408
+ */
6409
+ onHeaderActionCreated() {
6410
+ this.onRefreshEvent();
6411
+ },
6412
+
6029
6413
  pushAiContext() {
6030
6414
  applyAiContext(this.cnAiContext, 'index', {
6031
6415
  register: this.register,
@@ -6241,6 +6625,72 @@ var script = {
6241
6625
  this.$emit('clear-filters');
6242
6626
  },
6243
6627
 
6628
+ /**
6629
+ * Fetch what the board view needs: the rows of a reference column
6630
+ * field (once per field) and the narrowing select's options.
6631
+ *
6632
+ * @return {Promise<void>}
6633
+ * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-columns-can-be-the-rows-a-field-references
6634
+ */
6635
+ async loadBoardSources() {
6636
+ const active = this.boardActiveColumnField;
6637
+ if (active && active.kind === 'reference' && !Object.hasOwn(this.boardRefs, active.field)) {
6638
+ const property = this.effectiveSchema?.properties?.[active.field] || null;
6639
+ const target = referenceTargetOf(active.source, { register: this.register, property });
6640
+ if (target.register && target.schema) {
6641
+ let rows;
6642
+ try {
6643
+ rows = await fetchReferenceObjects({ ...target, filter: active.source?.filter || {} });
6644
+ } catch {
6645
+ rows = [];
6646
+ }
6647
+ this.boardRefs = { ...this.boardRefs, [active.field]: rows };
6648
+ }
6649
+ }
6650
+ const narrow = this.boardNarrow;
6651
+ if (narrow && this.boardNarrowOptions.length === 0) {
6652
+ const property = this.effectiveSchema?.properties?.[narrow.field] || null;
6653
+ const target = referenceTargetOf(narrow.source || {}, { register: this.register, property });
6654
+ let rows;
6655
+ try {
6656
+ rows = await fetchReferenceObjects({ ...target, filter: narrow.source?.filter || {} });
6657
+ } catch {
6658
+ rows = [];
6659
+ }
6660
+ const labelField = narrow.source?.labelField || 'title';
6661
+ this.boardNarrowOptions = rows
6662
+ .map((row) => ({ value: refIdOf(row), label: String(row?.[labelField] ?? row?.name ?? row?.title ?? refIdOf(row)) }))
6663
+ .filter((option) => option.value !== '')
6664
+ .sort((a, b) => a.label.localeCompare(b.label));
6665
+ }
6666
+ },
6667
+
6668
+ /**
6669
+ * The column switch changed.
6670
+ *
6671
+ * @param {string} field The column field picked.
6672
+ * @return {void}
6673
+ * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-board-can-switch-the-field-its-columns-come-from
6674
+ */
6675
+ onBoardColumnFieldChange(field) {
6676
+ this.boardColumnFieldChoice = field;
6677
+ /**
6678
+ * @event board-column-field-change The board's column switch picked another field. Payload: the field name.
6679
+ */
6680
+ this.$emit('board-column-field-change', field);
6681
+ },
6682
+
6683
+ /**
6684
+ * The narrowing select changed: it sets the page filter on its field,
6685
+ * so the cards narrow with the columns and the active filter shows.
6686
+ *
6687
+ * @param {string} value The parent id, '' for all.
6688
+ * @return {void}
6689
+ */
6690
+ onBoardNarrowChange(value) {
6691
+ this.onFilterEvent({ key: this.boardNarrow.field, values: value === '' ? [] : [value] });
6692
+ },
6693
+
6244
6694
  /**
6245
6695
  * A paged board's "Show N more": ask for the next page.
6246
6696
  *
@@ -6248,6 +6698,10 @@ var script = {
6248
6698
  * @spec openspec/changes/screens-kanban-parity/specs/board-view/spec.md#requirement-a-long-column-is-cut-with-a-show-more-button
6249
6699
  */
6250
6700
  onBoardLoadMore() {
6701
+ if (this.boardLoadsAll) {
6702
+ this.list.loadMore();
6703
+ return
6704
+ }
6251
6705
  const page = Number(this.pagination?.page || 1);
6252
6706
  if (page < Number(this.pagination?.pages || 1)) {
6253
6707
  this.onPageEvent(page + 1);
@@ -7069,7 +7523,7 @@ var script = {
7069
7523
  this.cnIndexSidebarConfig.value = {
7070
7524
  // markRaw: the holder is CnAppRoot `data()`, so it is deeply
7071
7525
  // reactive and would proxy the component definition itself.
7072
- component: markRaw(__sfc_main$r),
7526
+ component: markRaw(__sfc_main$s),
7073
7527
  props: this.hoistedSidebarProps,
7074
7528
  listeners: {
7075
7529
  'update:open': (val) => {
@@ -7586,6 +8040,23 @@ var script = {
7586
8040
  this.$emit('view-mode-change', mode);
7587
8041
  },
7588
8042
 
8043
+ /**
8044
+ * Open in the mode the address names (`?_view=board`), when the page
8045
+ * offers it. The key starts with `_`, like `_search` and `_page`, so it
8046
+ * is never read as a list filter. A menu entry's `query` can so open a
8047
+ * list as its board, on the one page that lists the schema
8048
+ * (screens-board-reference-columns).
8049
+ *
8050
+ * @return {void}
8051
+ * @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-the-address-can-open-a-list-in-a-view-mode
8052
+ */
8053
+ applyViewModeFromRoute() {
8054
+ const wanted = this.$route?.query?._view;
8055
+ if (typeof wanted === 'string' && wanted !== this.currentViewMode && this.effectiveToggleModes.includes(wanted)) {
8056
+ this.currentViewMode = wanted;
8057
+ }
8058
+ },
8059
+
7589
8060
  /**
7590
8061
  * Handle selection changes from CnDataTable/CnCardGrid.
7591
8062
  * Updates internal state and re-emits for parent.