@conduction/nextcloud-vue 2.59.0 → 2.61.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.
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js +14 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsMenu/CnActionsMenu.vue3.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +80 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +46 -4
- package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +232 -10
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +79 -25
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js +42 -3
- package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue2.js.map +1 -1
- package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js +39 -6
- package/dist/esm/components/CnBannerWidgetForm/CnBannerWidgetForm.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +46 -0
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +11 -4
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js +10 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue.js.map +1 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js +39 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue2.js.map +1 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js +16 -0
- package/dist/esm/components/CnBrandStripe/CnBrandStripe.vue3.js.map +1 -0
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +117 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +147 -89
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +10 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +259 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js +131 -0
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js +10 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +116 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js +24 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +10 -2
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +503 -28
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +303 -144
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js +10 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js +237 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue2.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js +120 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewList.vue3.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js +10 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +77 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js +27 -0
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +171 -12
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +15 -7
- package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js +37 -3
- package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue2.js.map +1 -1
- package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js +44 -16
- package/dist/esm/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +132 -3
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +6 -3
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue.js +10 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue.js.map +1 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue2.js +316 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue2.js.map +1 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue3.js +105 -0
- package/dist/esm/components/CnLinkCardsPage/CnLinkCardsPage.vue3.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js +10 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js +150 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue2.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js +106 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepCard.vue3.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js +9 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +47 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js +17 -0
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +49 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js +6 -0
- package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js +46 -0
- package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js +15 -3
- package/dist/esm/components/CnObjectKanban/CnObjectKanban.vue3.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/pageTypes.js +1 -0
- package/dist/esm/components/CnPageRenderer/pageTypes.js.map +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js +37 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue2.js.map +1 -1
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js +29 -13
- package/dist/esm/components/CnQuickFilterBar/CnQuickFilterBar.vue3.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js +50 -3
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSavedViewsControl/CnSavedViewsControl.vue3.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js +10 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue.js.map +1 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js +186 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js +46 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js +11 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js +298 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js +77 -0
- package/dist/esm/components/CnStackedBarWidget/CnStackedBarWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js +10 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js +169 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue2.js.map +1 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js +48 -0
- package/dist/esm/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue3.js.map +1 -0
- package/dist/esm/components/CnTabs/CnTab.vue2.js +35 -0
- package/dist/esm/components/CnTabs/CnTab.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTab.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js +120 -7
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js +57 -5
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +59 -4
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +6 -2
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js +10 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js +484 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js +115 -0
- package/dist/esm/components/CnWeekStripWidget/CnWeekStripWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js +10 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js +189 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue2.js.map +1 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js +74 -0
- package/dist/esm/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue3.js.map +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +82 -8
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +55 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +55 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +1036 -19
- package/dist/esm/utils/dateVariant.js +124 -0
- package/dist/esm/utils/dateVariant.js.map +1 -0
- package/dist/esm/utils/detailActionModel.js +260 -0
- package/dist/esm/utils/detailActionModel.js.map +1 -0
- package/dist/esm/utils/dueRule.js +84 -0
- package/dist/esm/utils/dueRule.js.map +1 -0
- package/dist/esm/utils/fetchAggregate.js +37 -1
- package/dist/esm/utils/fetchAggregate.js.map +1 -1
- package/dist/esm/utils/fetchFilterCounts.js +186 -0
- package/dist/esm/utils/fetchFilterCounts.js.map +1 -0
- package/dist/esm/utils/headers.js +28 -2
- package/dist/esm/utils/headers.js.map +1 -1
- package/dist/esm/utils/libraryWidgetKeys.js +5 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/readPath.js +30 -0
- package/dist/esm/utils/readPath.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +16019 -9528
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1036 -19
- package/l10n/en.json +55 -1
- package/l10n/nl.json +55 -1
- package/package.json +1 -1
- package/scripts/.jsdoc-baselines.json +4 -0
- package/src/components/CnActionsMenu/CnActionsMenu.vue +14 -1
- package/src/components/CnAppNav/CnAppNav.md +26 -0
- package/src/components/CnAppNav/CnAppNav.vue +145 -2
- package/src/components/CnBannerWidget/CnBannerWidget.vue +373 -11
- package/src/components/CnBannerWidgetForm/CnBannerWidgetForm.vue +65 -3
- package/src/components/CnBoardView/CnBoardView.vue +77 -0
- package/src/components/CnBrandStripe/CnBrandStripe.md +22 -0
- package/src/components/CnBrandStripe/CnBrandStripe.vue +100 -0
- package/src/components/CnBrandStripe/index.js +4 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +207 -1
- package/src/components/CnConversationThread/CnConversationThread.md +51 -0
- package/src/components/CnConversationThread/CnConversationThread.vue +457 -0
- package/src/components/CnConversationThread/CnConversationWidget.vue +144 -0
- package/src/components/CnConversationThread/index.js +4 -0
- package/src/components/CnDashboardPage/CnDashboardPage.vue +10 -2
- package/src/components/CnDetailPage/CnDetailPage.md +16 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +687 -49
- package/src/components/CnDocumentReviewList/CnDocumentReviewList.md +55 -0
- package/src/components/CnDocumentReviewList/CnDocumentReviewList.vue +384 -0
- package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +108 -0
- package/src/components/CnDocumentReviewList/index.js +4 -0
- package/src/components/CnHeaderWidget/CnHeaderWidget.vue +191 -14
- package/src/components/CnHeaderWidgetForm/CnHeaderWidgetForm.vue +53 -3
- package/src/components/CnIndexPage/CnIndexPage.vue +135 -3
- package/src/components/CnLinkCardsPage/CnLinkCardsPage.vue +484 -0
- package/src/components/CnLinkCardsPage/index.js +4 -0
- package/src/components/CnNextStepCard/CnNextStepCard.md +40 -0
- package/src/components/CnNextStepCard/CnNextStepCard.vue +319 -0
- package/src/components/CnNextStepCard/CnNextStepWidget.vue +59 -0
- package/src/components/CnNextStepCard/index.js +4 -0
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +49 -0
- package/src/components/CnObjectDataWidgetForm/CnObjectDataWidgetForm.vue +6 -0
- package/src/components/CnObjectKanban/CnObjectKanban.vue +86 -2
- package/src/components/CnPageRenderer/pageTypes.js +1 -0
- package/src/components/CnQuickFilterBar/CnQuickFilterBar.md +3 -0
- package/src/components/CnQuickFilterBar/CnQuickFilterBar.vue +60 -1
- package/src/components/CnSavedViewsControl/CnSavedViewsControl.vue +50 -3
- package/src/components/CnSegmentedControl/CnSegmentedControl.md +46 -0
- package/src/components/CnSegmentedControl/CnSegmentedControl.vue +291 -0
- package/src/components/CnSegmentedControl/index.js +4 -0
- package/src/components/CnStackedBarWidget/CnStackedBarWidget.md +15 -0
- package/src/components/CnStackedBarWidget/CnStackedBarWidget.vue +414 -0
- package/src/components/CnStackedBarWidget/index.js +14 -0
- package/src/components/CnStackedBarWidgetForm/CnStackedBarWidgetForm.vue +224 -0
- package/src/components/CnStackedBarWidgetForm/index.js +4 -0
- package/src/components/CnTabs/CnTab.vue +35 -0
- package/src/components/CnTabs/CnTabs.vue +244 -10
- package/src/components/CnTabsWidget/CnTabsWidget.vue +63 -4
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.md +31 -0
- package/src/components/CnWeekStripWidget/CnWeekStripWidget.vue +668 -0
- package/src/components/CnWeekStripWidget/index.js +14 -0
- package/src/components/CnWeekStripWidgetForm/CnWeekStripWidgetForm.vue +265 -0
- package/src/components/CnWeekStripWidgetForm/index.js +4 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +74 -0
- package/src/components/index.js +12 -0
- package/src/css/detail-page.css +57 -2
- package/src/index.js +16 -0
- package/src/schemas/app-manifest-v2.schema.json +433 -3
- package/src/schemas/app-manifest.schema.json +2 -1
- package/src/types/manifest.d.ts +1 -1
- package/src/utils/dateVariant.js +120 -0
- package/src/utils/detailActionModel.js +256 -0
- package/src/utils/dueRule.js +94 -0
- package/src/utils/fetchAggregate.js +36 -0
- package/src/utils/fetchFilterCounts.js +182 -0
- package/src/utils/headers.js +28 -2
- package/src/utils/index.js +1 -0
- package/src/utils/libraryWidgetKeys.js +5 -0
- package/src/utils/readPath.js +27 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -240,6 +240,29 @@
|
|
|
240
240
|
"$ref": "#/$defs/primaryAction",
|
|
241
241
|
"description": "App-wide default primary action rendered as an NcAppNavigationNew button above the main menu list. A page-scoped pages[].primaryAction for the current route wins over this default."
|
|
242
242
|
},
|
|
243
|
+
"brand": {
|
|
244
|
+
"type": "object",
|
|
245
|
+
"additionalProperties": false,
|
|
246
|
+
"description": "A brand block at the very top of the app navigation, above the primary action: a logo, a name and a caption. Rendered by CnAppNav. Omitted, nothing renders there.",
|
|
247
|
+
"properties": {
|
|
248
|
+
"logo": {
|
|
249
|
+
"type": "string",
|
|
250
|
+
"description": "URL of the logo image. Decorative when `name` is set."
|
|
251
|
+
},
|
|
252
|
+
"name": {
|
|
253
|
+
"type": "string",
|
|
254
|
+
"description": "i18n key / text for the app or organisation name."
|
|
255
|
+
},
|
|
256
|
+
"caption": {
|
|
257
|
+
"type": "string",
|
|
258
|
+
"description": "i18n key / text for the line under the name, for example the organisation."
|
|
259
|
+
},
|
|
260
|
+
"alt": {
|
|
261
|
+
"type": "string",
|
|
262
|
+
"description": "i18n key / alternative text for the logo. Used only when no `name` is set."
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
},
|
|
243
266
|
"featureRequestRepo": {
|
|
244
267
|
"type": "string",
|
|
245
268
|
"description": "`<owner>/<repo>` slug on the forge that the in-product feature-request deep-link targets (provided to descendants as `cnFeatureRequestRepo`). Falls back to `Conduction/<appId>` when omitted."
|
|
@@ -976,6 +999,72 @@
|
|
|
976
999
|
"swimlaneField": {
|
|
977
1000
|
"type": "string",
|
|
978
1001
|
"description": "A second field to group the board into rows by, while the columns stay the stages. Cards with no value for it land in one named row, last, rather than being dropped: grouping by handler and hiding the unassigned work turns a board into a picture of what is already somebody's problem."
|
|
1002
|
+
},
|
|
1003
|
+
"dueRule": {
|
|
1004
|
+
"$ref": "#/$defs/dueRule",
|
|
1005
|
+
"description": "Marks late cards. A card whose date is before today gets an error edge and the label 'Overdue'; one due within `soonDays` gets 'Due soon'. Omitted, no card is marked."
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
"headerPill": {
|
|
1010
|
+
"type": "object",
|
|
1011
|
+
"additionalProperties": false,
|
|
1012
|
+
"required": ["field"],
|
|
1013
|
+
"description": "A pill in a detail page header, rendered through CnStatusBadge from one field of the record. Nothing renders while the field is empty.",
|
|
1014
|
+
"properties": {
|
|
1015
|
+
"field": {
|
|
1016
|
+
"type": "string",
|
|
1017
|
+
"minLength": 1,
|
|
1018
|
+
"description": "Dot-path to the value on the record."
|
|
1019
|
+
},
|
|
1020
|
+
"colorMap": {
|
|
1021
|
+
"type": "object",
|
|
1022
|
+
"description": "Raw value to badge variant. Keys are matched ignoring case.",
|
|
1023
|
+
"additionalProperties": { "type": "string", "enum": ["default", "primary", "success", "warning", "error", "info"] }
|
|
1024
|
+
},
|
|
1025
|
+
"labels": {
|
|
1026
|
+
"type": "object",
|
|
1027
|
+
"description": "Raw value to the i18n key / text to show. A value without an entry is shown as is.",
|
|
1028
|
+
"additionalProperties": { "type": "string" }
|
|
1029
|
+
},
|
|
1030
|
+
"variant": {
|
|
1031
|
+
"type": "string",
|
|
1032
|
+
"enum": ["default", "primary", "success", "warning", "error", "info"],
|
|
1033
|
+
"default": "default",
|
|
1034
|
+
"description": "Badge variant for a value `colorMap` does not name."
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
"dueRule": {
|
|
1039
|
+
"type": "object",
|
|
1040
|
+
"additionalProperties": false,
|
|
1041
|
+
"required": ["field"],
|
|
1042
|
+
"description": "How a surface decides that a dated item is late. One shape for boards and lists, so a list and its board agree. A date before today is overdue. Days are whole calendar days in the reader's own timezone.",
|
|
1043
|
+
"properties": {
|
|
1044
|
+
"field": {
|
|
1045
|
+
"type": "string",
|
|
1046
|
+
"minLength": 1,
|
|
1047
|
+
"description": "Dot-path to the due date on the row."
|
|
1048
|
+
},
|
|
1049
|
+
"soonDays": {
|
|
1050
|
+
"type": "integer",
|
|
1051
|
+
"minimum": 0,
|
|
1052
|
+
"default": 3,
|
|
1053
|
+
"description": "How many days ahead still counts as due soon. 0 marks only today."
|
|
1054
|
+
},
|
|
1055
|
+
"variantWhen": {
|
|
1056
|
+
"type": "array",
|
|
1057
|
+
"description": "The full rule list, in the shape a table's date cell uses, for a board that needs more than `soonDays`. Compared against the calendar days until the date (0 is today, negative is past); first match wins. `error` marks the card overdue, `warning` due soon. When set, `soonDays` is ignored.",
|
|
1058
|
+
"items": {
|
|
1059
|
+
"type": "object",
|
|
1060
|
+
"additionalProperties": false,
|
|
1061
|
+
"required": ["op", "value", "variant"],
|
|
1062
|
+
"properties": {
|
|
1063
|
+
"op": { "type": "string", "enum": ["eq", "neq", "gt", "gte", "lt", "lte"] },
|
|
1064
|
+
"value": { "type": "number" },
|
|
1065
|
+
"variant": { "type": "string", "enum": ["default", "success", "warning", "error", "danger"] }
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
979
1068
|
}
|
|
980
1069
|
}
|
|
981
1070
|
},
|
|
@@ -1239,6 +1328,29 @@
|
|
|
1239
1328
|
}
|
|
1240
1329
|
}
|
|
1241
1330
|
},
|
|
1331
|
+
"linkCard": {
|
|
1332
|
+
"type": "object",
|
|
1333
|
+
"required": ["id", "label"],
|
|
1334
|
+
"additionalProperties": false,
|
|
1335
|
+
"description": "One card on a type='links' page: a link to another page of the app, or to a URL. Same vocabulary as menuItem and navCardEntry.",
|
|
1336
|
+
"properties": {
|
|
1337
|
+
"id": { "type": "string", "minLength": 1, "description": "Unique within the page's cards." },
|
|
1338
|
+
"label": { "type": "string", "minLength": 1, "description": "i18n key / text of the card's title." },
|
|
1339
|
+
"description": { "type": "string", "description": "i18n key / one line under the title." },
|
|
1340
|
+
"icon": { "type": "string", "description": "MDI icon name (e.g. 'CashMultiple')." },
|
|
1341
|
+
"category": { "type": "string", "description": "Key in config.categories naming the group this card sits in. A card without one, or with an unknown one, renders first under no caption." },
|
|
1342
|
+
"route": { "type": "string", "minLength": 1, "description": "Route name (a pages[].id), or a router path when it starts with '/'. Resolved through the router, so it works with and without /index.php. Mutually exclusive with href." },
|
|
1343
|
+
"params": { "type": "object", "description": "Route params passed along with `route`.", "additionalProperties": { "type": ["string", "number"] } },
|
|
1344
|
+
"query": { "type": "object", "description": "Query passed along with `route`.", "additionalProperties": { "type": ["string", "number", "boolean"] } },
|
|
1345
|
+
"href": { "type": "string", "minLength": 1, "description": "External URL, opened in a new tab. Mutually exclusive with route." },
|
|
1346
|
+
"permission": { "type": "string", "description": "Permission the user must hold for the card to render. Same rule as menuItem.permission." },
|
|
1347
|
+
"visibleIf": { "$ref": "#/$defs/visibleIfCondition", "description": "Display condition, evaluated the way a menu entry's is." }
|
|
1348
|
+
},
|
|
1349
|
+
"allOf": [
|
|
1350
|
+
{ "not": { "required": ["route", "href"] } },
|
|
1351
|
+
{ "anyOf": [{ "required": ["route"] }, { "required": ["href"] }] }
|
|
1352
|
+
]
|
|
1353
|
+
},
|
|
1242
1354
|
"navCardEntry": {
|
|
1243
1355
|
"type": "object",
|
|
1244
1356
|
"required": ["id", "label"],
|
|
@@ -1575,6 +1687,47 @@
|
|
|
1575
1687
|
{ "type": "string" },
|
|
1576
1688
|
{ "type": "object", "additionalProperties": true }
|
|
1577
1689
|
]
|
|
1690
|
+
},
|
|
1691
|
+
"layout": {
|
|
1692
|
+
"type": "string",
|
|
1693
|
+
"enum": ["banner", "attention"],
|
|
1694
|
+
"default": "banner",
|
|
1695
|
+
"description": "How the banner renders. `banner` (default) is the note card. `attention` is a card with a severity edge, a kicker, a title, a reason line and up to two actions."
|
|
1696
|
+
},
|
|
1697
|
+
"kicker": {
|
|
1698
|
+
"type": "string",
|
|
1699
|
+
"description": "Attention card: the small label above the title."
|
|
1700
|
+
},
|
|
1701
|
+
"title": {
|
|
1702
|
+
"type": "string",
|
|
1703
|
+
"description": "Attention card: the title. Falls back to `text`."
|
|
1704
|
+
},
|
|
1705
|
+
"reason": {
|
|
1706
|
+
"type": "string",
|
|
1707
|
+
"description": "Attention card: the line that says why this needs attention. `{value}` is replaced by the value visibleWhen read."
|
|
1708
|
+
},
|
|
1709
|
+
"actions": {
|
|
1710
|
+
"type": "array",
|
|
1711
|
+
"maxItems": 2,
|
|
1712
|
+
"description": "Attention card: at most two actions. The first is the primary one unless an action sets `primary: true`.",
|
|
1713
|
+
"items": {
|
|
1714
|
+
"type": "object",
|
|
1715
|
+
"required": ["label"],
|
|
1716
|
+
"additionalProperties": false,
|
|
1717
|
+
"properties": {
|
|
1718
|
+
"id": { "type": "string", "description": "Identifier passed with the `action` event of an action that has no route or href." },
|
|
1719
|
+
"label": { "type": "string", "description": "The text on the action." },
|
|
1720
|
+
"route": {
|
|
1721
|
+
"description": "A vue-router route NAME (string) or a full location object.",
|
|
1722
|
+
"oneOf": [
|
|
1723
|
+
{ "type": "string" },
|
|
1724
|
+
{ "type": "object", "additionalProperties": true }
|
|
1725
|
+
]
|
|
1726
|
+
},
|
|
1727
|
+
"href": { "type": "string", "description": "An URL, used when there is no route." },
|
|
1728
|
+
"primary": { "type": "boolean", "description": "Render this action as the primary one." }
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1578
1731
|
}
|
|
1579
1732
|
}
|
|
1580
1733
|
}
|
|
@@ -1875,6 +2028,125 @@
|
|
|
1875
2028
|
}
|
|
1876
2029
|
}
|
|
1877
2030
|
}
|
|
2031
|
+
},
|
|
2032
|
+
{
|
|
2033
|
+
"description": "week-strip catalog widget (CnWeekStripWidget): the current week as day columns with the dated items under each day. Takes a `props.content` blob. Items come from an OpenRegister `source` (one request for the week, bucketed by `dateField`) or from static `items`.",
|
|
2034
|
+
"if": {
|
|
2035
|
+
"properties": { "widgetKey": { "const": "week-strip" } },
|
|
2036
|
+
"required": ["widgetKey"]
|
|
2037
|
+
},
|
|
2038
|
+
"then": {
|
|
2039
|
+
"properties": {
|
|
2040
|
+
"props": {
|
|
2041
|
+
"type": "object",
|
|
2042
|
+
"properties": {
|
|
2043
|
+
"content": {
|
|
2044
|
+
"type": "object",
|
|
2045
|
+
"additionalProperties": true,
|
|
2046
|
+
"properties": {
|
|
2047
|
+
"days": { "type": "integer", "enum": [5, 7], "default": 5, "description": "5 working days (default) or the whole week. The week starts on Monday." },
|
|
2048
|
+
"source": {
|
|
2049
|
+
"type": "object",
|
|
2050
|
+
"additionalProperties": false,
|
|
2051
|
+
"required": ["register", "schema"],
|
|
2052
|
+
"description": "OpenRegister object query; `filter` supports the shared @-token grammar.",
|
|
2053
|
+
"properties": {
|
|
2054
|
+
"register": { "type": "string" },
|
|
2055
|
+
"schema": { "type": "string" },
|
|
2056
|
+
"filter": { "type": "object", "additionalProperties": true },
|
|
2057
|
+
"limit": { "type": "integer", "minimum": 1, "description": "Cap on the records fetched for the week (default 100)." }
|
|
2058
|
+
}
|
|
2059
|
+
},
|
|
2060
|
+
"dateField": { "type": "string", "description": "The field the items are bucketed by. Required with a source." },
|
|
2061
|
+
"titleField": { "type": "string", "description": "The field shown as the item title. Defaults to the object's display name." },
|
|
2062
|
+
"metaFields": { "type": "array", "items": { "type": "string" }, "description": "Fields shown under the title." },
|
|
2063
|
+
"itemRoute": { "type": "string", "description": "Route name an item links to; the record id goes in params.id." },
|
|
2064
|
+
"lateWhen": {
|
|
2065
|
+
"type": "object",
|
|
2066
|
+
"additionalProperties": false,
|
|
2067
|
+
"description": "Rule on the number of days until the date that marks an item late. Default: before today ({ op: 'lt', value: 0 }).",
|
|
2068
|
+
"properties": {
|
|
2069
|
+
"op": { "type": "string", "enum": ["eq", "neq", "gt", "gte", "lt", "lte"] },
|
|
2070
|
+
"value": { "type": "number" }
|
|
2071
|
+
}
|
|
2072
|
+
},
|
|
2073
|
+
"lateField": { "type": "string", "description": "A boolean field that marks a record late, whatever its date." },
|
|
2074
|
+
"items": {
|
|
2075
|
+
"type": "array",
|
|
2076
|
+
"description": "Static items, used when there is no source.",
|
|
2077
|
+
"items": {
|
|
2078
|
+
"type": "object",
|
|
2079
|
+
"required": ["title", "date"],
|
|
2080
|
+
"additionalProperties": false,
|
|
2081
|
+
"properties": {
|
|
2082
|
+
"title": { "type": "string" },
|
|
2083
|
+
"meta": { "type": "string" },
|
|
2084
|
+
"date": { "type": "string", "description": "ISO date or date-time." },
|
|
2085
|
+
"route": { "oneOf": [{ "type": "string" }, { "type": "object", "additionalProperties": true }] },
|
|
2086
|
+
"href": { "type": "string" },
|
|
2087
|
+
"late": { "type": "boolean" }
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
},
|
|
2091
|
+
"emptyText": { "type": "string", "description": "Text of a day without items." },
|
|
2092
|
+
"weekOffset": { "type": "integer", "description": "Whole weeks from the current one (1 = next week)." }
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
"description": "stacked-bar catalog widget (CnStackedBarWidget): one segmented bar with a legend that carries the label and count of every segment. Takes a `props.content` blob. Segments come from one grouped count request (`source.groupBy`) or from static `segments`.",
|
|
2102
|
+
"if": {
|
|
2103
|
+
"properties": { "widgetKey": { "const": "stacked-bar" } },
|
|
2104
|
+
"required": ["widgetKey"]
|
|
2105
|
+
},
|
|
2106
|
+
"then": {
|
|
2107
|
+
"properties": {
|
|
2108
|
+
"props": {
|
|
2109
|
+
"type": "object",
|
|
2110
|
+
"properties": {
|
|
2111
|
+
"content": {
|
|
2112
|
+
"type": "object",
|
|
2113
|
+
"additionalProperties": true,
|
|
2114
|
+
"properties": {
|
|
2115
|
+
"source": {
|
|
2116
|
+
"type": "object",
|
|
2117
|
+
"additionalProperties": false,
|
|
2118
|
+
"required": ["register", "schema", "groupBy"],
|
|
2119
|
+
"description": "OpenRegister grouped count; `filter` supports the shared @-token grammar.",
|
|
2120
|
+
"properties": {
|
|
2121
|
+
"register": { "type": "string" },
|
|
2122
|
+
"schema": { "type": "string" },
|
|
2123
|
+
"groupBy": { "type": "string", "description": "The field the records are counted per." },
|
|
2124
|
+
"filter": { "type": "object", "additionalProperties": true }
|
|
2125
|
+
}
|
|
2126
|
+
},
|
|
2127
|
+
"segments": {
|
|
2128
|
+
"type": "array",
|
|
2129
|
+
"description": "Static segments, used when there is no source.",
|
|
2130
|
+
"items": {
|
|
2131
|
+
"type": "object",
|
|
2132
|
+
"required": ["label", "value"],
|
|
2133
|
+
"additionalProperties": false,
|
|
2134
|
+
"properties": {
|
|
2135
|
+
"key": { "type": "string" },
|
|
2136
|
+
"label": { "type": "string" },
|
|
2137
|
+
"value": { "type": "number", "minimum": 0 }
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
},
|
|
2141
|
+
"order": { "type": "array", "items": { "type": "string" }, "description": "Group keys in the order they render. Unlisted groups follow; a listed key without records shows 0." },
|
|
2142
|
+
"labels": { "type": "object", "additionalProperties": { "type": "string" }, "description": "The label of a group key." },
|
|
2143
|
+
"emptyText": { "type": "string", "description": "Shown when the total is 0." }
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
1878
2150
|
}
|
|
1879
2151
|
]
|
|
1880
2152
|
},
|
|
@@ -2264,6 +2536,16 @@
|
|
|
2264
2536
|
"type": "string",
|
|
2265
2537
|
"description": "i18n key naming the `children` dropdown. Falls back to the parent action's own label, so the chevron is never announced unlabelled."
|
|
2266
2538
|
},
|
|
2539
|
+
"group": {
|
|
2540
|
+
"type": "string",
|
|
2541
|
+
"minLength": 1,
|
|
2542
|
+
"description": "Detail page header actions only. i18n key / text naming the group this action sits in inside the overflow menu. Grouped actions render under a caption with this name, in first appearance order, after the ungrouped ones. Ignored on other surfaces."
|
|
2543
|
+
},
|
|
2544
|
+
"adminOnly": {
|
|
2545
|
+
"type": "boolean",
|
|
2546
|
+
"default": false,
|
|
2547
|
+
"description": "Detail page header actions only. Shows the action to instance admins alone, in the last group of the overflow menu. Hides a control and nothing more: the endpoint behind the action still decides who may call it. Ignored on other surfaces."
|
|
2548
|
+
},
|
|
2267
2549
|
"visibleWhen": {
|
|
2268
2550
|
"$ref": "#/$defs/visibleWhen",
|
|
2269
2551
|
"description": "#91 Wave 3: an optional predicate gating whether the action renders — the shared banner shape ({ endpoint | source | field, op, value }). The `field`-only LOCAL form evaluates against the page object context (a detail action shown only in the right lifecycle state); endpoint / source forms fetch. Fail-safe: a broken predicate hides the action."
|
|
@@ -2599,8 +2881,8 @@
|
|
|
2599
2881
|
"type": {
|
|
2600
2882
|
"type": "string",
|
|
2601
2883
|
"enum": ["index", "detail", "dashboard", "logs", "settings", "chat", "files", "form", "map", "roadmap", "reports",
|
|
2602
|
-
"store", "search", "wiki", "flow", "flows", "flow-detail", "custom"],
|
|
2603
|
-
"description": "Page type. Closed enum of
|
|
2884
|
+
"links", "store", "search", "wiki", "flow", "flows", "flow-detail", "custom"],
|
|
2885
|
+
"description": "Page type. Closed enum of 18 supported types. 'links' mounts CnLinkCardsPage: a page of link cards grouped under captions, declared with config.categories + config.cards ($defs/linkCard). Use it for the pages a short menu leaves out; unlike 'reports' an app may have several. 'flow' opens ONE flow in the editor; the flow LIST is an ordinary 'index' with config.entitySource='flows'. 'flows' and 'flow-detail' are DEPRECATED aliases kept for migration — 'flows' predates named index sources and 'flow-detail' is the old name for 'flow'. 'roadmap' mounts CnFeaturesAndRoadmapPage (features + GitHub-issue-backed roadmap). 'search' mounts CnSearchPage (cross-schema query + facet sidebar + results list; consumers wire the actual search via @search). 'wiki' mounts CnWikiPage (manifest-declared markdown article + optional sidebar tree; MUST declare config.register + config.schema). 'flow' and the deprecated 'flow-detail' both mount CnFlowEditorPage (the shared node/edge canvas) and take config.app to scope to the owning app. A flow lives in OpenRegister's native flow store rather than a register/schema pair, so a single flow cannot be a 'detail' page — but the LIST is a plain 'index' once a named entitySource supplies it, which is why 'flows' is deprecated (ADR-110 Decision 4). 'custom' requires a _note field explaining why a standard type was not feasible."
|
|
2604
2886
|
},
|
|
2605
2887
|
"title": {
|
|
2606
2888
|
"type": "string",
|
|
@@ -2887,7 +3169,7 @@
|
|
|
2887
3169
|
},
|
|
2888
3170
|
"columns": {
|
|
2889
3171
|
"type": "array",
|
|
2890
|
-
"description": "Table columns (for type='index' and type='logs'). Items may be strings (legacy shorthand) or column objects ({ key, label, sortable?, width?, formatter?, formatterOptions?, widget?, widgetProps?, format?, aggregate? }). `formatter` resolves against cnFormatters (built-ins incl. currency / conditionalPhrase — configured via `formatterOptions`); `widget` resolves against cnCellWidgets (built-ins incl. badge / fkResolve / link).",
|
|
3172
|
+
"description": "Table columns (for type='index' and type='logs'). Items may be strings (legacy shorthand) or column objects ({ key, label, sortable?, width?, formatter?, formatterOptions?, widget?, widgetProps?, format?, aggregate? }). `formatter` resolves against cnFormatters (built-ins incl. currency / conditionalPhrase — configured via `formatterOptions`); `widget` resolves against cnCellWidgets (built-ins incl. badge / fkResolve / link / avatar / date).",
|
|
2891
3173
|
"items": {
|
|
2892
3174
|
"oneOf": [
|
|
2893
3175
|
{ "type": "string" },
|
|
@@ -2936,6 +3218,127 @@
|
|
|
2936
3218
|
"additionalProperties": true
|
|
2937
3219
|
}
|
|
2938
3220
|
},
|
|
3221
|
+
"stageField": {
|
|
3222
|
+
"type": "string",
|
|
3223
|
+
"minLength": 1,
|
|
3224
|
+
"default": "status",
|
|
3225
|
+
"description": "type='detail': dot-path to the field holding the record's stage. Read by `primaryActionByStage` and `nextStep`."
|
|
3226
|
+
},
|
|
3227
|
+
"primaryActionByStage": {
|
|
3228
|
+
"type": "object",
|
|
3229
|
+
"description": "type='detail': the page's primary button per stage. Keys are values of `stageField` (matched exactly first, then ignoring case). A value is an action in the header action shape, or the id of a `headerActions` entry, which then leaves the overflow menu. A stage without an entry falls back to the page's `primaryAction`.",
|
|
3230
|
+
"additionalProperties": {
|
|
3231
|
+
"oneOf": [
|
|
3232
|
+
{ "type": "string", "minLength": 1 },
|
|
3233
|
+
{ "$ref": "#/$defs/action" }
|
|
3234
|
+
]
|
|
3235
|
+
}
|
|
3236
|
+
},
|
|
3237
|
+
"quickActions": {
|
|
3238
|
+
"type": "array",
|
|
3239
|
+
"maxItems": 3,
|
|
3240
|
+
"description": "type='detail': at most three always visible buttons in the header, for the actions a handler uses on every record. An item is an action in the header action shape, or the id of a `headerActions` entry, which then leaves the overflow menu.",
|
|
3241
|
+
"items": {
|
|
3242
|
+
"oneOf": [
|
|
3243
|
+
{ "type": "string", "minLength": 1 },
|
|
3244
|
+
{ "$ref": "#/$defs/action" }
|
|
3245
|
+
]
|
|
3246
|
+
}
|
|
3247
|
+
},
|
|
3248
|
+
"actionsMenu": {
|
|
3249
|
+
"type": "object",
|
|
3250
|
+
"additionalProperties": false,
|
|
3251
|
+
"description": "type='detail': what the header's overflow menu itself shows. Omitted, the menu keeps Refresh and the three help links.",
|
|
3252
|
+
"properties": {
|
|
3253
|
+
"showRefresh": {
|
|
3254
|
+
"type": "boolean",
|
|
3255
|
+
"description": "false removes Refresh from the menu."
|
|
3256
|
+
},
|
|
3257
|
+
"showHelpLinks": {
|
|
3258
|
+
"type": "boolean",
|
|
3259
|
+
"description": "false removes Request a feature, Report a bug and Documentation, for an app that offers them in its own help menu."
|
|
3260
|
+
},
|
|
3261
|
+
"label": {
|
|
3262
|
+
"type": "string",
|
|
3263
|
+
"minLength": 1,
|
|
3264
|
+
"description": "i18n key / text naming the menu, for example 'More'. Defaults to 'Actions'."
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
},
|
|
3268
|
+
"nextStep": {
|
|
3269
|
+
"type": "object",
|
|
3270
|
+
"additionalProperties": false,
|
|
3271
|
+
"required": ["stages"],
|
|
3272
|
+
"description": "type='detail': the 'what now' card above the body. For the record's stage it shows a short checklist next to the primary button. A stage without an entry shows no card. Rendered by CnNextStepCard.",
|
|
3273
|
+
"properties": {
|
|
3274
|
+
"field": {
|
|
3275
|
+
"type": "string",
|
|
3276
|
+
"minLength": 1,
|
|
3277
|
+
"description": "Dot-path to the stage, when it differs from `stageField`."
|
|
3278
|
+
},
|
|
3279
|
+
"title": {
|
|
3280
|
+
"type": "string",
|
|
3281
|
+
"description": "i18n key / heading used by a stage that names none."
|
|
3282
|
+
},
|
|
3283
|
+
"stages": {
|
|
3284
|
+
"type": "object",
|
|
3285
|
+
"description": "Keys are stage values.",
|
|
3286
|
+
"additionalProperties": {
|
|
3287
|
+
"type": "object",
|
|
3288
|
+
"additionalProperties": false,
|
|
3289
|
+
"required": ["checklist"],
|
|
3290
|
+
"properties": {
|
|
3291
|
+
"title": { "type": "string", "description": "i18n key / heading of the card for this stage." },
|
|
3292
|
+
"after": { "type": "string", "description": "i18n key / one line under the button saying what follows." },
|
|
3293
|
+
"checklist": {
|
|
3294
|
+
"type": "array",
|
|
3295
|
+
"description": "What this stage still needs. An empty list shows no card.",
|
|
3296
|
+
"items": {
|
|
3297
|
+
"type": "object",
|
|
3298
|
+
"additionalProperties": false,
|
|
3299
|
+
"required": ["label"],
|
|
3300
|
+
"properties": {
|
|
3301
|
+
"label": { "type": "string", "minLength": 1, "description": "i18n key / text of the item." },
|
|
3302
|
+
"hint": { "type": "string", "description": "i18n key / short note after the label, for example '2 of 5 done'." },
|
|
3303
|
+
"doneField": { "type": "string", "minLength": 1, "description": "Dot-path on the record. The item is done when it holds a value; a list counts when it is not empty." },
|
|
3304
|
+
"doneWhen": { "type": "object", "description": "A local visibleWhen condition ({ field, op, value } or { all | any }). The item is done when it is true. Wins over `doneField`." },
|
|
3305
|
+
"done": { "type": "boolean", "description": "A fixed state, for an item the record cannot answer." }
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
},
|
|
3314
|
+
"typePill": {
|
|
3315
|
+
"$ref": "#/$defs/headerPill",
|
|
3316
|
+
"description": "type='detail': a pill above the title saying what kind of record this is."
|
|
3317
|
+
},
|
|
3318
|
+
"statusPill": {
|
|
3319
|
+
"$ref": "#/$defs/headerPill",
|
|
3320
|
+
"description": "type='detail': a pill above the title saying where the record stands."
|
|
3321
|
+
},
|
|
3322
|
+
"sideColumn": {
|
|
3323
|
+
"type": "array",
|
|
3324
|
+
"description": "type='detail': a column of cards beside the body, for the record's facts. An item is a widget definition, or the id of a widget declared on the page. The column stacks under the body on a narrow page.",
|
|
3325
|
+
"items": {
|
|
3326
|
+
"oneOf": [
|
|
3327
|
+
{ "type": "string", "minLength": 1 },
|
|
3328
|
+
{
|
|
3329
|
+
"type": "object",
|
|
3330
|
+
"additionalProperties": true,
|
|
3331
|
+
"required": ["type"],
|
|
3332
|
+
"properties": {
|
|
3333
|
+
"id": { "type": "string" },
|
|
3334
|
+
"type": { "type": "string", "minLength": 1 },
|
|
3335
|
+
"title": { "type": "string" },
|
|
3336
|
+
"content": { "type": "object", "additionalProperties": true }
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
]
|
|
3340
|
+
}
|
|
3341
|
+
},
|
|
2939
3342
|
"headerActions": {
|
|
2940
3343
|
"type": "array",
|
|
2941
3344
|
"description": "Page-level header actions rendered inside CnActionsBar's overflow dropdown (between the built-in Refresh action and the `#action-items` slot). On a `type:'detail'` page the same entries render in the header's Actions menu, above the Request-a-feature / Report-a-bug / Documentation trio. Same shape as the row-level `actions[]` ($ref action), but handlers receive NO row context — they are page-level. Reserved ids (`refresh`, `import`, `export`, `copy`, `delete`) are dropped at render time to avoid shadowing built-ins. See manifest-icons-and-page-actions for the dispatch semantics.",
|
|
@@ -2992,6 +3395,14 @@
|
|
|
2992
3395
|
},
|
|
2993
3396
|
"description": "type='index': saved view ids this page renders as tabs instead of as entries in the views control. A view appears in one place or the other, never both. An id naming a view that no longer exists produces no tab, rather than a tab that opens nothing. Maps to CnIndexPage `viewTabs`."
|
|
2994
3397
|
},
|
|
3398
|
+
"viewCounts": {
|
|
3399
|
+
"description": "type='index': which saved views show how many records they match. `true` counts every saved view (tabs and the entries in the views control), an array counts only the view ids it lists. Off by default, so no count request is made. Quick filters opt in per entry with `showCount: true`. Maps to CnIndexPage `viewCounts`.",
|
|
3400
|
+
"oneOf": [
|
|
3401
|
+
{ "type": "boolean" },
|
|
3402
|
+
{ "type": "array", "items": { "type": "string", "minLength": 1 } }
|
|
3403
|
+
],
|
|
3404
|
+
"default": false
|
|
3405
|
+
},
|
|
2995
3406
|
"priorityField": {
|
|
2996
3407
|
"type": "string",
|
|
2997
3408
|
"description": "type='index': the field carrying a record's DERIVED priority. The list reads the value and sorts on it; it never computes one. A record with no priority, or one outside `priorityLevels`, sorts after every ranked record in BOTH directions and stays in the list. Maps to CnIndexPage `priorityField`."
|
|
@@ -3264,6 +3675,25 @@
|
|
|
3264
3675
|
"required": ["config"]
|
|
3265
3676
|
}
|
|
3266
3677
|
},
|
|
3678
|
+
{
|
|
3679
|
+
"description": "type='links' (CnLinkCardsPage) renders config.cards as link cards grouped by config.categories. It MUST declare a non-empty cards list, and every card is a $defs/linkCard, so a card that can go nowhere is refused here and not dropped in silence at render time (link-cards-page).",
|
|
3680
|
+
"if": { "properties": { "type": { "const": "links" } }, "required": ["type"] },
|
|
3681
|
+
"then": {
|
|
3682
|
+
"properties": {
|
|
3683
|
+
"config": {
|
|
3684
|
+
"type": "object",
|
|
3685
|
+
"required": ["cards"],
|
|
3686
|
+
"properties": {
|
|
3687
|
+
"description": { "type": "string" },
|
|
3688
|
+
"emptyLabel": { "type": "string" },
|
|
3689
|
+
"categories": { "type": "object", "additionalProperties": { "type": "string", "minLength": 1 } },
|
|
3690
|
+
"cards": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/linkCard" } }
|
|
3691
|
+
}
|
|
3692
|
+
}
|
|
3693
|
+
},
|
|
3694
|
+
"required": ["config"]
|
|
3695
|
+
}
|
|
3696
|
+
},
|
|
3267
3697
|
{
|
|
3268
3698
|
"description": "type='custom' requires _note documenting why decomposition into a standard page type was not feasible. Relaxed by ConductionNL/nextcloud-vue#315: when `component` matches the lib `Cn[A-Z]\\w+` pattern, the component name already documents the choice and _note is optional. When `component` is absent or non-Cn (host-app SFC), _note remains required.",
|
|
3269
3699
|
"if": {
|
|
@@ -342,7 +342,8 @@
|
|
|
342
342
|
"label": { "type": "string", "description": "i18n key or plain text rendered on the tab." },
|
|
343
343
|
"filter": { "type": "object", "additionalProperties": true, "description": "Filter map merged into the fetch when this tab is active." },
|
|
344
344
|
"default": { "type": "boolean", "default": false, "description": "Pre-selected on mount." },
|
|
345
|
-
"icon": { "type": "string", "description": "Optional MDI icon name displayed alongside the label." }
|
|
345
|
+
"icon": { "type": "string", "description": "Optional MDI icon name displayed alongside the label." },
|
|
346
|
+
"showCount": { "type": "boolean", "default": false, "description": "Show how many records this tab matches, after its label. Off by default: no count request is made for a tab that does not ask. Tabs that filter the same single field share one grouped request." }
|
|
346
347
|
}
|
|
347
348
|
}
|
|
348
349
|
},
|
package/src/types/manifest.d.ts
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
export type TPageType =
|
|
29
29
|
| 'index' | 'detail' | 'dashboard' | 'logs' | 'settings' | 'chat'
|
|
30
|
-
| 'files' | 'form' | 'map' | 'roadmap' | 'reports' | 'store' | 'search' | 'wiki'
|
|
30
|
+
| 'files' | 'form' | 'map' | 'roadmap' | 'reports' | 'links' | 'store' | 'search' | 'wiki'
|
|
31
31
|
| 'flow'
|
|
32
32
|
/** @deprecated `flows` predates named index sources — use `index` with `config.source: 'flows'`. */
|
|
33
33
|
| 'flows'
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* dateVariant: turn "how far away is this date" into a colour variant.
|
|
6
|
+
*
|
|
7
|
+
* A deadline reads differently depending on how close it is. The rules are the
|
|
8
|
+
* `variantWhen` shape the stat tile already uses (`[{ op, value, variant }]`,
|
|
9
|
+
* first match wins), compared against the number of CALENDAR days from today
|
|
10
|
+
* until the date: `0` is today, a negative number is overdue.
|
|
11
|
+
*
|
|
12
|
+
* ```js
|
|
13
|
+
* resolveDateVariant('2026-10-01', [
|
|
14
|
+
* { op: 'lt', value: 0, variant: 'error' }, // overdue
|
|
15
|
+
* { op: 'lte', value: 5, variant: 'warning' }, // within five days
|
|
16
|
+
* ])
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Shared by the `date` cell widget (CnCellRenderer) and the week strip, and
|
|
20
|
+
* meant for board cards too, so a deadline is coloured by one rule everywhere.
|
|
21
|
+
*
|
|
22
|
+
* @module utils/dateVariant
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { compareVisibleWhen } from './visibleWhen.js'
|
|
26
|
+
|
|
27
|
+
/** Variants a date rule may name. `danger` is accepted as an alias of `error`. */
|
|
28
|
+
export const DATE_VARIANTS = Object.freeze(['default', 'success', 'warning', 'error'])
|
|
29
|
+
|
|
30
|
+
const MS_PER_DAY = 86400000
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parse a value into a Date. A date-only string (`2026-10-05`) is read as a
|
|
34
|
+
* LOCAL day, so it does not slide to the day before in a timezone west of UTC.
|
|
35
|
+
*
|
|
36
|
+
* @param {unknown} value A Date, a timestamp, or an ISO string.
|
|
37
|
+
* @return {Date|null} The date, or null when the value is not one.
|
|
38
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
39
|
+
*/
|
|
40
|
+
export function parseDateValue(value) {
|
|
41
|
+
if (value === null || value === undefined || value === '') {
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
if (value instanceof Date) {
|
|
45
|
+
return Number.isNaN(value.getTime()) ? null : value
|
|
46
|
+
}
|
|
47
|
+
if (typeof value === 'string') {
|
|
48
|
+
const dateOnly = value.match(/^(\d{4})-(\d{2})-(\d{2})$/)
|
|
49
|
+
if (dateOnly) {
|
|
50
|
+
return new Date(Number(dateOnly[1]), Number(dateOnly[2]) - 1, Number(dateOnly[3]))
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (typeof value !== 'string' && typeof value !== 'number') {
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
56
|
+
const parsed = new Date(value)
|
|
57
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The local calendar day of a date as `YYYY-MM-DD`.
|
|
62
|
+
*
|
|
63
|
+
* @param {Date} date The date.
|
|
64
|
+
* @return {string} The day key.
|
|
65
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-week-strip-widget
|
|
66
|
+
*/
|
|
67
|
+
export function dayKey(date) {
|
|
68
|
+
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
69
|
+
const day = String(date.getDate()).padStart(2, '0')
|
|
70
|
+
return `${date.getFullYear()}-${month}-${day}`
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Whole calendar days from `now` until `value`: 0 today, negative when past.
|
|
75
|
+
*
|
|
76
|
+
* @param {unknown} value The date.
|
|
77
|
+
* @param {Date} [now] The reference moment (defaults to the current time).
|
|
78
|
+
* @return {number|null} The day count, or null when `value` is not a date.
|
|
79
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
80
|
+
*/
|
|
81
|
+
export function daysUntil(value, now = new Date()) {
|
|
82
|
+
const date = parseDateValue(value)
|
|
83
|
+
if (date === null) {
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
86
|
+
// UTC midnights of the two LOCAL days, so a daylight-saving hour never
|
|
87
|
+
// turns one day into zero or two.
|
|
88
|
+
const target = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())
|
|
89
|
+
const today = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())
|
|
90
|
+
return Math.round((target - today) / MS_PER_DAY)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The variant of the first rule the date matches, or '' when none does.
|
|
95
|
+
*
|
|
96
|
+
* @param {unknown} value The date.
|
|
97
|
+
* @param {Array<{op: string, value: number, variant: string}>} rules The `variantWhen` rules.
|
|
98
|
+
* @param {Date} [now] The reference moment (defaults to the current time).
|
|
99
|
+
* @return {string} `success | warning | error | default`, or '' for no match.
|
|
100
|
+
* @spec openspec/changes/workplace-dashboard-primitives/specs/workplace-dashboard-primitives/spec.md#requirement-avatar-and-date-cells
|
|
101
|
+
*/
|
|
102
|
+
export function resolveDateVariant(value, rules, now = new Date()) {
|
|
103
|
+
if (!Array.isArray(rules) || rules.length === 0) {
|
|
104
|
+
return ''
|
|
105
|
+
}
|
|
106
|
+
const days = daysUntil(value, now)
|
|
107
|
+
if (days === null) {
|
|
108
|
+
return ''
|
|
109
|
+
}
|
|
110
|
+
for (const rule of rules) {
|
|
111
|
+
if (!rule || typeof rule !== 'object') {
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
if (compareVisibleWhen(days, rule.op || 'eq', rule.value) === true) {
|
|
115
|
+
const variant = rule.variant === 'danger' ? 'error' : rule.variant
|
|
116
|
+
return DATE_VARIANTS.includes(variant) ? variant : ''
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return ''
|
|
120
|
+
}
|