@conduction/nextcloud-vue 2.79.0 → 2.81.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/CnActionButtons/CnActionButtons.vue2.js.map +1 -1
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js +3 -1
- package/dist/esm/components/CnActionButtons/CnActionButtons.vue3.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js +32 -3
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +13 -11
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +80 -4
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +95 -91
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js +179 -13
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js +52 -16
- package/dist/esm/components/CnBannerWidget/CnBannerWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +96 -4
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +158 -110
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js +10 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue.js.map +1 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js +252 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js +140 -0
- package/dist/esm/components/CnChipsFieldWidget/CnChipsFieldWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnChipsFieldWidget/index.js +26 -0
- package/dist/esm/components/CnChipsFieldWidget/index.js.map +1 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js +10 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue.js.map +1 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js +354 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js +172 -0
- package/dist/esm/components/CnChoicePickerWidget/CnChoicePickerWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnChoicePickerWidget/index.js +27 -0
- package/dist/esm/components/CnChoicePickerWidget/index.js.map +1 -0
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +2 -2
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +65 -5
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +19 -11
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +4 -2
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +134 -4
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +21 -4
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +24 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +43 -4
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js +1 -1
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnDocumentReviewList/CnDocumentReviewWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue2.js +7 -7
- package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnFacetSidebar/CnFacetSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +11 -0
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +867 -0
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +238 -0
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnFactsWidget/index.js +30 -0
- package/dist/esm/components/CnFactsWidget/index.js.map +1 -0
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +10 -0
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js.map +1 -0
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +626 -0
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +396 -0
- package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnFieldListWidget/index.js +29 -0
- package/dist/esm/components/CnFieldListWidget/index.js.map +1 -0
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +302 -4
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +417 -244
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js +101 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowser.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js +141 -1
- package/dist/esm/components/CnFilesBrowser/filesBrowserColumns.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js +65 -17
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js +4 -4
- package/dist/esm/components/CnFormDialog/CnFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnFormPage/CnFormPage.vue2.js +78 -3
- package/dist/esm/components/CnFormPage/CnFormPage.vue2.js.map +1 -1
- package/dist/esm/components/CnFormPage/CnFormPage.vue3.js +74 -49
- package/dist/esm/components/CnFormPage/CnFormPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +333 -73
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +79 -17
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +10 -0
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js.map +1 -0
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +99 -0
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -0
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +48 -0
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -0
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +7 -7
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js +1 -1
- package/dist/esm/components/CnNextStepCard/CnNextStepWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +65 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +6 -2
- package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +63 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +8 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +14 -0
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js +5 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js +29 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnPageRenderer/CnPageRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js +10 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js +174 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js +75 -0
- package/dist/esm/components/CnRadioCardsWidget/CnRadioCardsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnRadioCardsWidget/index.js +28 -0
- package/dist/esm/components/CnRadioCardsWidget/index.js.map +1 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +10 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js.map +1 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +411 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +178 -0
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnRecordListWidget/index.js +31 -0
- package/dist/esm/components/CnRecordListWidget/index.js.map +1 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js +10 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js +222 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js +64 -0
- package/dist/esm/components/CnSavedViewsWidget/CnSavedViewsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSavedViewsWidget/index.js +30 -0
- package/dist/esm/components/CnSavedViewsWidget/index.js.map +1 -0
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js +10 -0
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js +351 -0
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js +71 -0
- package/dist/esm/components/CnSectionsWidget/CnSectionsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSectionsWidget/index.js +35 -0
- package/dist/esm/components/CnSectionsWidget/index.js.map +1 -0
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue2.js.map +1 -1
- package/dist/esm/components/CnSegmentedControl/CnSegmentedControl.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js +10 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js +347 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js +184 -0
- package/dist/esm/components/CnSettingsFormWidget/CnSettingsFormWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSettingsFormWidget/index.js +27 -0
- package/dist/esm/components/CnSettingsFormWidget/index.js.map +1 -0
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +81 -2
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +87 -6
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +1 -0
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js +84 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js +85 -41
- package/dist/esm/components/CnStatsBlockWidget/CnStatsBlockWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js +10 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue.js.map +1 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js +159 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js +60 -0
- package/dist/esm/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnSwitchRowsWidget/index.js +26 -0
- package/dist/esm/components/CnSwitchRowsWidget/index.js.map +1 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +168 -7
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +86 -23
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js +80 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js +75 -32
- package/dist/esm/components/CnTasksWidget/CnTasksWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js +10 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue.js.map +1 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +269 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js +106 -0
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnToggleTableWidget/index.js +27 -0
- package/dist/esm/components/CnToggleTableWidget/index.js.map +1 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +11 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +7 -2
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/dashboardRegistration.js +5 -0
- package/dist/esm/components/CnWidgetObjectTable/dashboardRegistration.js.map +1 -1
- package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js +301 -6
- package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js +153 -55
- package/dist/esm/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue3.js.map +1 -1
- package/dist/esm/composables/useFormDraft.js +140 -9
- package/dist/esm/composables/useFormDraft.js.map +1 -1
- package/dist/esm/composables/useListView.js +4 -4
- package/dist/esm/composables/useListView.js.map +1 -1
- package/dist/esm/index.js +21 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +28 -20
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js +9 -0
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection.js +21 -0
- package/dist/esm/integrations/builtin/field-inspection.js.map +1 -1
- package/dist/esm/integrations/offline/checklistSubmission.js +141 -0
- package/dist/esm/integrations/offline/checklistSubmission.js.map +1 -0
- package/dist/esm/integrations/offline/fieldCollectionHelpers.js +70 -5
- package/dist/esm/integrations/offline/fieldCollectionHelpers.js.map +1 -1
- package/dist/esm/integrations/offline/index.js +2 -1
- package/dist/esm/integrations/offline/index.js.map +1 -1
- package/dist/esm/integrations/offline/offlineDb.js +6 -1
- package/dist/esm/integrations/offline/offlineDb.js.map +1 -1
- package/dist/esm/integrations/offline/syncReplayService.js +8 -2
- package/dist/esm/integrations/offline/syncReplayService.js.map +1 -1
- package/dist/esm/l10n/en.json.js +20 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +70 -2
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/nextcloud-vue.css +2192 -222
- package/dist/esm/utils/contentHeaderLink.js +51 -0
- package/dist/esm/utils/contentHeaderLink.js.map +1 -0
- package/dist/esm/utils/detailActionModel.js +60 -3
- package/dist/esm/utils/detailActionModel.js.map +1 -1
- package/dist/esm/utils/facets.js +75 -3
- package/dist/esm/utils/facets.js.map +1 -1
- package/dist/esm/utils/fetchFilterCounts.js +40 -5
- package/dist/esm/utils/fetchFilterCounts.js.map +1 -1
- package/dist/esm/utils/fillTemplate.js +120 -0
- package/dist/esm/utils/fillTemplate.js.map +1 -0
- package/dist/esm/utils/initials.js +32 -0
- package/dist/esm/utils/initials.js.map +1 -0
- package/dist/esm/utils/libraryWidgetKeys.js +11 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/objectWrite.js +59 -0
- package/dist/esm/utils/objectWrite.js.map +1 -0
- package/dist/esm/utils/pageControls.js +81 -0
- package/dist/esm/utils/pageControls.js.map +1 -0
- package/dist/esm/utils/personalLenses.js +40 -3
- package/dist/esm/utils/personalLenses.js.map +1 -1
- package/dist/esm/utils/queryPresets.js +96 -0
- package/dist/esm/utils/queryPresets.js.map +1 -0
- package/dist/esm/utils/resolveFilterTokens.js +12 -1
- package/dist/esm/utils/resolveFilterTokens.js.map +1 -1
- package/dist/esm/utils/resolveManifestTokens.js +2 -0
- package/dist/esm/utils/resolveManifestTokens.js.map +1 -1
- package/dist/esm/utils/schema.js +21 -0
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/sentinelTokens.js +22 -4
- package/dist/esm/utils/sentinelTokens.js.map +1 -1
- package/dist/esm/utils/userGroupsPeek.js +91 -0
- package/dist/esm/utils/userGroupsPeek.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/visibleWhen.js +57 -5
- package/dist/esm/utils/visibleWhen.js.map +1 -1
- package/dist/esm/utils/widgetDispatch.js +7 -1
- package/dist/esm/utils/widgetDispatch.js.map +1 -1
- package/dist/esm/utils/widgetVisibility.js +4 -57
- package/dist/esm/utils/widgetVisibility.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +19708 -9301
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +2192 -222
- package/l10n/en.json +20 -1
- package/l10n/nl.json +70 -2
- package/package.json +2 -1
- package/scripts/check-docs-mdx.mjs +108 -0
- package/src/components/CnActionButtons/CnActionButtons.vue +2 -0
- package/src/components/CnActionsBar/CnActionsBar.md +4 -0
- package/src/components/CnActionsBar/CnActionsBar.vue +48 -11
- package/src/components/CnAppRoot/CnAppRoot.md +4 -2
- package/src/components/CnAppRoot/CnAppRoot.vue +151 -59
- package/src/components/CnBannerWidget/CnBannerWidget.vue +244 -23
- package/src/components/CnCellRenderer/CnCellRenderer.md +2 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +235 -5
- package/src/components/CnChipsFieldWidget/CnChipsFieldWidget.vue +433 -0
- package/src/components/CnChipsFieldWidget/index.js +25 -0
- package/src/components/CnChoicePickerWidget/CnChoicePickerWidget.vue +556 -0
- package/src/components/CnChoicePickerWidget/index.js +26 -0
- package/src/components/CnConversationThread/CnConversationWidget.vue +1 -1
- package/src/components/CnDashboardGrid/CnDashboardGrid.vue +2 -2
- package/src/components/CnDashboardPage/CnDashboardPage.vue +78 -5
- package/src/components/CnDataTable/CnDataTable.vue +22 -12
- package/src/components/CnDetailPage/CnDetailPage.md +1 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +152 -6
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +66 -0
- package/src/components/CnDocumentReviewList/CnDocumentReviewWidget.vue +1 -1
- package/src/components/CnFacetSidebar/CnFacetSidebar.vue +7 -7
- package/src/components/CnFactsWidget/CnFactsWidget.vue +1190 -0
- package/src/components/CnFactsWidget/index.js +29 -0
- package/src/components/CnFieldListWidget/CnFieldListWidget.vue +1008 -0
- package/src/components/CnFieldListWidget/index.js +28 -0
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +588 -117
- package/src/components/CnFilesBrowser/filesBrowser.js +100 -0
- package/src/components/CnFilesBrowser/filesBrowserColumns.js +140 -0
- package/src/components/CnFormDialog/CnFormDialog.md +9 -3
- package/src/components/CnFormDialog/CnFormDialog.vue +69 -21
- package/src/components/CnFormPage/CnFormPage.vue +99 -3
- package/src/components/CnIndexPage/CnIndexPage.vue +309 -9
- package/src/components/CnIndexPage/CnIndexPageWidgets.vue +169 -0
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +7 -7
- package/src/components/CnNextStepCard/CnNextStepWidget.vue +1 -1
- package/src/components/CnObjectListWidget/CnObjectListWidget.vue +69 -2
- package/src/components/CnObjectSidebar/CnFilesTab.vue +70 -1
- package/src/components/CnObjectSidebar/CnNotesTab.vue +16 -0
- package/src/components/CnPageRenderer/CnPageRenderer.vue +29 -1
- package/src/components/CnRadioCardsWidget/CnRadioCardsWidget.vue +313 -0
- package/src/components/CnRadioCardsWidget/index.js +27 -0
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +652 -0
- package/src/components/CnRecordListWidget/index.js +30 -0
- package/src/components/CnSavedViewsWidget/CnSavedViewsWidget.vue +296 -0
- package/src/components/CnSavedViewsWidget/index.js +29 -0
- package/src/components/CnSectionsWidget/CnSectionsWidget.vue +489 -0
- package/src/components/CnSectionsWidget/index.js +34 -0
- package/src/components/CnSegmentedControl/CnSegmentedControl.vue +13 -0
- package/src/components/CnSettingsFormWidget/CnSettingsFormWidget.vue +555 -0
- package/src/components/CnSettingsFormWidget/index.js +26 -0
- package/src/components/CnStagesWidget/CnStagesWidget.vue +81 -2
- package/src/components/CnStatWidget/CnStatWidget.vue +88 -7
- package/src/components/CnStatsBlockWidget/CnStatsBlockWidget.vue +180 -3
- package/src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue +226 -0
- package/src/components/CnSwitchRowsWidget/index.js +25 -0
- package/src/components/CnTabsWidget/CnTabsWidget.vue +263 -8
- package/src/components/CnTasksWidget/CnTasksWidget.vue +175 -15
- package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +386 -0
- package/src/components/CnToggleTableWidget/index.js +26 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +11 -0
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +7 -2
- package/src/components/CnWidgetObjectTable/dashboardRegistration.js +5 -0
- package/src/components/CnWorkspaceFilterWidget/CnWorkspaceFilterWidget.vue +493 -11
- package/src/components/index.js +19 -0
- package/src/composables/__tests__/useFormDraft.spec.js +69 -0
- package/src/composables/useFormDraft.js +139 -8
- package/src/composables/useListView.js +4 -4
- package/src/css/form-field.css +14 -0
- package/src/css/index-page.css +71 -0
- package/src/css/kpi-card.css +32 -0
- package/src/css/look-board-detail.css +113 -2
- package/src/css/look-board-index.css +90 -8
- package/src/css/look-board.css +109 -2
- package/src/css/table.css +19 -0
- package/src/index.js +19 -0
- package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +35 -20
- package/src/integrations/builtin/field-inspection.js +21 -0
- package/src/integrations/offline/checklistSubmission.js +137 -0
- package/src/integrations/offline/fieldCollectionHelpers.js +69 -4
- package/src/integrations/offline/index.js +3 -0
- package/src/integrations/offline/offlineDb.js +6 -1
- package/src/integrations/offline/syncReplayService.js +8 -2
- package/src/schemas/app-manifest-v2.schema.json +196 -13
- package/src/utils/contentHeaderLink.js +48 -0
- package/src/utils/detailActionModel.js +59 -2
- package/src/utils/facets.js +74 -2
- package/src/utils/fetchFilterCounts.js +39 -4
- package/src/utils/fillTemplate.js +116 -0
- package/src/utils/initials.js +29 -0
- package/src/utils/libraryWidgetKeys.js +11 -0
- package/src/utils/objectWrite.js +55 -0
- package/src/utils/pageControls.js +78 -0
- package/src/utils/personalLenses.js +39 -2
- package/src/utils/queryPresets.js +93 -0
- package/src/utils/resolveFilterTokens.js +14 -1
- package/src/utils/resolveManifestTokens.js +2 -0
- package/src/utils/schema.js +21 -0
- package/src/utils/sentinelTokens.js +22 -4
- package/src/utils/userGroupsPeek.js +87 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/visibleWhen.js +56 -4
- package/src/utils/widgetDispatch.js +7 -1
- package/src/utils/widgetVisibility.js +7 -56
|
@@ -46,11 +46,71 @@ export function classifyGps(fix, available = true) {
|
|
|
46
46
|
return { quality: 'good', source: 'sensor', warning: null }
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Read a checklist template into the leaf's flat item contract.
|
|
51
|
+
*
|
|
52
|
+
* A consuming app's template does not have to carry `items[]` with
|
|
53
|
+
* `questionId` / `text` / `type`. Its `offlineConfig` names where those live:
|
|
54
|
+
* `sectionsField` when the items sit inside ordered sections, and the
|
|
55
|
+
* `item*Field` keys for the item's key, text and type. `itemTypeMap` translates
|
|
56
|
+
* the app's own type words onto the leaf's (`yes_no`, `photo_required`, or any
|
|
57
|
+
* other word, which renders as free text). `photoRequiredField` and
|
|
58
|
+
* `photoRequiredValue` mark an item whose answer also needs a photo.
|
|
59
|
+
*
|
|
60
|
+
* The template's own keys are kept, so the id and version stay readable; only
|
|
61
|
+
* `items` is replaced by the normalised list.
|
|
62
|
+
*
|
|
63
|
+
* @param {object|null} template The template as cached.
|
|
64
|
+
* @param {object} [config] The leaf's offline config.
|
|
65
|
+
*
|
|
66
|
+
* @return {object|null} The template with flat `items[]`, or null.
|
|
67
|
+
*/
|
|
68
|
+
export function normaliseChecklistTemplate(template, config = {}) {
|
|
69
|
+
if (template === null || typeof template !== 'object') {
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const keyField = config.itemKeyField || 'questionId'
|
|
74
|
+
const textField = config.itemTextField || 'text'
|
|
75
|
+
const typeField = config.itemTypeField || 'type'
|
|
76
|
+
const typeMap = (config.itemTypeMap && typeof config.itemTypeMap === 'object') ? config.itemTypeMap : {}
|
|
77
|
+
|
|
78
|
+
const sections = config.sectionsField ? template[config.sectionsField] : null
|
|
79
|
+
const raw = Array.isArray(sections)
|
|
80
|
+
? sections.flatMap((section) => (Array.isArray(section?.items) ? section.items : []))
|
|
81
|
+
: (Array.isArray(template.items) ? template.items : [])
|
|
82
|
+
|
|
83
|
+
const items = []
|
|
84
|
+
for (const item of raw) {
|
|
85
|
+
if (item === null || typeof item !== 'object') {
|
|
86
|
+
continue
|
|
87
|
+
}
|
|
88
|
+
const questionId = String(item[keyField] ?? '')
|
|
89
|
+
if (questionId === '') {
|
|
90
|
+
continue
|
|
91
|
+
}
|
|
92
|
+
const ownType = item[typeField]
|
|
93
|
+
const photoRequired = Boolean(config.photoRequiredField)
|
|
94
|
+
&& item[config.photoRequiredField] === config.photoRequiredValue
|
|
95
|
+
items.push({
|
|
96
|
+
...item,
|
|
97
|
+
questionId,
|
|
98
|
+
text: item[textField] ?? item.text ?? questionId,
|
|
99
|
+
type: typeMap[ownType] ?? ownType ?? 'text',
|
|
100
|
+
required: item.required === true,
|
|
101
|
+
photoRequired,
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { ...template, items }
|
|
106
|
+
}
|
|
107
|
+
|
|
49
108
|
/**
|
|
50
109
|
* Validate a set of checklist answers against the template's required items.
|
|
51
110
|
*
|
|
52
|
-
* A `required` item must have a non-empty answer; a `photo_required` item
|
|
53
|
-
*
|
|
111
|
+
* A `required` item must have a non-empty answer; a `photo_required` item, and
|
|
112
|
+
* any item flagged `photoRequired` by {@link normaliseChecklistTemplate}, must
|
|
113
|
+
* have at least one evidence reference. Returns the per-question
|
|
54
114
|
* blocking errors so the UI can prevent save (and the engine never queues an
|
|
55
115
|
* invalid result).
|
|
56
116
|
*
|
|
@@ -66,7 +126,7 @@ export function validateChecklistAnswers(template, answersByQuestion) {
|
|
|
66
126
|
const errors = []
|
|
67
127
|
|
|
68
128
|
for (const item of items) {
|
|
69
|
-
if (item?.required !== true) {
|
|
129
|
+
if (item?.required !== true && item?.photoRequired !== true) {
|
|
70
130
|
continue
|
|
71
131
|
}
|
|
72
132
|
const entry = answers[item.questionId] ?? {}
|
|
@@ -80,7 +140,12 @@ export function validateChecklistAnswers(template, answersByQuestion) {
|
|
|
80
140
|
continue
|
|
81
141
|
}
|
|
82
142
|
|
|
83
|
-
if (
|
|
143
|
+
if (item.photoRequired === true && evidenceRefs.length === 0) {
|
|
144
|
+
errors.push({ questionId: item.questionId, message: t('nextcloud-vue', 'Photo required for this question') })
|
|
145
|
+
continue
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (item.required === true && (answer === undefined || answer === null || String(answer).trim() === '')) {
|
|
84
149
|
errors.push({ questionId: item.questionId, message: t('nextcloud-vue', 'This question is required') })
|
|
85
150
|
}
|
|
86
151
|
}
|
|
@@ -60,10 +60,13 @@ export {
|
|
|
60
60
|
checklistProgress,
|
|
61
61
|
classifyGps,
|
|
62
62
|
GPS_POOR_ACCURACY_M,
|
|
63
|
+
normaliseChecklistTemplate,
|
|
63
64
|
syncIndicator,
|
|
64
65
|
validateChecklistAnswers,
|
|
65
66
|
} from './fieldCollectionHelpers.js'
|
|
66
67
|
|
|
68
|
+
export { buildChecklistSubmission, fillEndpoint } from './checklistSubmission.js'
|
|
69
|
+
|
|
67
70
|
export {
|
|
68
71
|
CACHE_PREFIX,
|
|
69
72
|
cacheNameFor,
|
|
@@ -257,10 +257,12 @@ export async function getPlanningMeta(register, schema, collection = 'planning')
|
|
|
257
257
|
*
|
|
258
258
|
* @param {object} operation The mutation operation.
|
|
259
259
|
* @param {string} operation.deviceId Owning device id (IDOR scope).
|
|
260
|
-
* @param {string} operation.operationType create / update / delete.
|
|
260
|
+
* @param {string} operation.operationType create / update / delete / submit.
|
|
261
261
|
* @param {string} operation.register Target register slug or id.
|
|
262
262
|
* @param {string} operation.schema Target schema slug or id.
|
|
263
263
|
* @param {string} [operation.targetId] Existing object id (update/delete).
|
|
264
|
+
* @param {string} [operation.endpoint] Path under the Nextcloud root a
|
|
265
|
+
* `submit` row is POSTed to.
|
|
264
266
|
* @param {object} [operation.payload] The object body (create/update).
|
|
265
267
|
*
|
|
266
268
|
* @return {Promise<string>} The queued operation id.
|
|
@@ -275,6 +277,9 @@ export async function enqueueMutation(operation) {
|
|
|
275
277
|
register: operation.register,
|
|
276
278
|
schema: operation.schema,
|
|
277
279
|
targetId: operation.targetId ?? null,
|
|
280
|
+
// A `submit` operation replays to an app's own endpoint instead of the
|
|
281
|
+
// object API (see checklistSubmission.js); every other row has none.
|
|
282
|
+
endpoint: operation.endpoint ?? null,
|
|
278
283
|
payload: operation.payload ?? {},
|
|
279
284
|
queuedAt: operation.queuedAt || new Date().toISOString(),
|
|
280
285
|
attemptCount: 0,
|
|
@@ -35,7 +35,8 @@ function objectsUrl(register, schema) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Replay one queued mutation against the OR object API
|
|
38
|
+
* Replay one queued mutation against the OR object API, or, for a row that
|
|
39
|
+
* names an `endpoint`, as one POST to that endpoint.
|
|
39
40
|
*
|
|
40
41
|
* @param {object} operation The queue operation row.
|
|
41
42
|
* @param {object} [offlineConfig] The leaf's offline config (`register`,
|
|
@@ -54,7 +55,12 @@ export async function replayOperation(operation, offlineConfig = {}) {
|
|
|
54
55
|
|
|
55
56
|
try {
|
|
56
57
|
let response
|
|
57
|
-
if (operation.
|
|
58
|
+
if (typeof operation.endpoint === 'string' && operation.endpoint !== '') {
|
|
59
|
+
// A run the app checks and stores itself (a completed task, say):
|
|
60
|
+
// one POST to its endpoint under the Nextcloud root. The endpoint
|
|
61
|
+
// decides access from what it has stored, as the object API does.
|
|
62
|
+
response = await axios.post(generateUrl(operation.endpoint), payload)
|
|
63
|
+
} else if (operation.operationType === 'create' || operation.operationType === 'upload') {
|
|
58
64
|
response = await axios.post(base, payload)
|
|
59
65
|
} else if (operation.operationType === 'update') {
|
|
60
66
|
response = await axios.put(`${base}/${operation.targetId}`, payload)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"$id": "https://raw.githubusercontent.com/ConductionNL/nextcloud-vue/main/src/schemas/app-manifest-v2.schema.json",
|
|
4
4
|
"title": "Conduction App Manifest v2",
|
|
5
5
|
"description": "v2 schema for the JSON-driven page and navigation manifest consumed by @conduction/nextcloud-vue. Introduces a uniform widgets[] array on every page type with a per-slot grid coordinate system, a typed actions[] discriminator, and the required $schema field for version detection. v1 manifests continue to validate against app-manifest.schema.json (unchanged).",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.89.0",
|
|
7
7
|
"type": "object",
|
|
8
8
|
"required": ["$schema", "version"],
|
|
9
9
|
"allOf": [
|
|
@@ -760,8 +760,8 @@
|
|
|
760
760
|
},
|
|
761
761
|
"sentinelFilterToken": {
|
|
762
762
|
"type": "string",
|
|
763
|
-
"pattern": "^@(?:me(?:\\.(?:displayName|email))?|myGroups|now|today|monthStart|quarterStart|yearStart)$|^@today[+-][0-9]+d$",
|
|
764
|
-
"description": "Filter-value context: relative fetch-time tokens resolved by resolveFilterTokens (@me, @me.displayName, @me.email, @myGroups (the current user's group ids, an IN list), @now, @today, @today±Nd, @monthStart, @quarterStart, @yearStart). Mirrors SENTINEL_TOKEN_PATTERNS.filter in src/utils/sentinelTokens.js (byte-equality enforced by a unit test)."
|
|
763
|
+
"pattern": "^@(?:me(?:\\.(?:displayName|email))?|myGroups|now|today|monthStart|monthEnd|nextMonthStart|quarterStart|yearStart)$|^@today[+-][0-9]+d$",
|
|
764
|
+
"description": "Filter-value context: relative fetch-time tokens resolved by resolveFilterTokens (@me, @me.displayName, @me.email, @myGroups (the current user's group ids, an IN list), @now, @today, @today±Nd, @monthStart, @monthEnd, @nextMonthStart, @quarterStart, @yearStart). Mirrors SENTINEL_TOKEN_PATTERNS.filter in src/utils/sentinelTokens.js (byte-equality enforced by a unit test)."
|
|
765
765
|
},
|
|
766
766
|
"sentinelConfigToken": {
|
|
767
767
|
"type": "string",
|
|
@@ -803,6 +803,16 @@
|
|
|
803
803
|
"pattern": "^@answer\\.[A-Za-z][A-Za-z0-9_]*$",
|
|
804
804
|
"description": "form-live-values: another answer in the same form (@answer.<field>), read by a form field's assign rule and resolved client-side by CnFormPage / CnFormDialog. Mirrors SENTINEL_TOKEN_PATTERNS.answer."
|
|
805
805
|
},
|
|
806
|
+
"sentinelRowToken": {
|
|
807
|
+
"type": "string",
|
|
808
|
+
"pattern": "^@row\\.[A-Za-z][A-Za-z0-9_.@]*$",
|
|
809
|
+
"description": "Row context: a field of the row a row action runs on (@row.<field>, dot path allowed), read by the field-list widget's rowActions request url and payload (payload values resolve at any depth). Mirrors SENTINEL_TOKEN_PATTERNS.row."
|
|
810
|
+
},
|
|
811
|
+
"sentinelSubjectToken": {
|
|
812
|
+
"type": "string",
|
|
813
|
+
"pattern": "^@subject\\.[A-Za-z][A-Za-z0-9_.]*$",
|
|
814
|
+
"description": "Subject context: a field of the record an attention card names (the first row of its ordered `visibleWhen` source query), read by the banner widget's action route params and query (@subject.<field>, dot path allowed). Mirrors SENTINEL_TOKEN_PATTERNS.subject."
|
|
815
|
+
},
|
|
806
816
|
"sentinelTokenAny": {
|
|
807
817
|
"$comment": "Union of every canonical context plus the deprecated-during-window overlay. Single source the shared resolver + gate import.",
|
|
808
818
|
"anyOf": [
|
|
@@ -814,6 +824,8 @@
|
|
|
814
824
|
{ "$ref": "#/$defs/sentinelDeclarativeToken" },
|
|
815
825
|
{ "$ref": "#/$defs/sentinelVisibleWhenToken" },
|
|
816
826
|
{ "$ref": "#/$defs/sentinelAnswerToken" },
|
|
827
|
+
{ "$ref": "#/$defs/sentinelRowToken" },
|
|
828
|
+
{ "$ref": "#/$defs/sentinelSubjectToken" },
|
|
817
829
|
{ "$ref": "#/$defs/sentinelDeprecatedToken" }
|
|
818
830
|
]
|
|
819
831
|
},
|
|
@@ -1132,14 +1144,43 @@
|
|
|
1132
1144
|
"headerPill": {
|
|
1133
1145
|
"type": "object",
|
|
1134
1146
|
"additionalProperties": false,
|
|
1135
|
-
"
|
|
1136
|
-
|
|
1147
|
+
"anyOf": [
|
|
1148
|
+
{ "required": ["field"] },
|
|
1149
|
+
{ "required": ["text"] },
|
|
1150
|
+
{ "required": ["countFrom"] }
|
|
1151
|
+
],
|
|
1152
|
+
"description": "A pill in a detail page header, rendered through CnStatusBadge: from one field of the record (`field`; nothing renders while it is empty), a constant (`text`), or a count of a related list (`countFrom` with `countLabel`; nothing renders at 0, while counting or after a failed count). screens-relation-pages, 2.85.0.",
|
|
1137
1153
|
"properties": {
|
|
1138
1154
|
"field": {
|
|
1139
1155
|
"type": "string",
|
|
1140
1156
|
"minLength": 1,
|
|
1141
1157
|
"description": "Dot-path to the value on the record."
|
|
1142
1158
|
},
|
|
1159
|
+
"text": {
|
|
1160
|
+
"type": "string",
|
|
1161
|
+
"minLength": 1,
|
|
1162
|
+
"description": "A constant label (an i18n key), such as \"Inwoner\" or \"Klant\". Used when `field` is not set."
|
|
1163
|
+
},
|
|
1164
|
+
"countFrom": {
|
|
1165
|
+
"type": "object",
|
|
1166
|
+
"additionalProperties": false,
|
|
1167
|
+
"required": ["register", "schema"],
|
|
1168
|
+
"description": "The list the pill counts with one list request (`_limit=1`, the response's `total`). `filter` values take the `@objectId` and `@object.<field>` tokens. Used when `field` is not set.",
|
|
1169
|
+
"properties": {
|
|
1170
|
+
"register": { "type": "string", "minLength": 1 },
|
|
1171
|
+
"schema": { "type": "string", "minLength": 1 },
|
|
1172
|
+
"filter": { "type": "object", "additionalProperties": true }
|
|
1173
|
+
}
|
|
1174
|
+
},
|
|
1175
|
+
"countLabel": {
|
|
1176
|
+
"type": "object",
|
|
1177
|
+
"additionalProperties": false,
|
|
1178
|
+
"description": "The count pill's label for one and for more, i18n keys with `{count}`: `{ \"one\": \"{count} lopende zaak\", \"other\": \"{count} lopende zaken\" }`.",
|
|
1179
|
+
"properties": {
|
|
1180
|
+
"one": { "type": "string", "minLength": 1 },
|
|
1181
|
+
"other": { "type": "string", "minLength": 1 }
|
|
1182
|
+
}
|
|
1183
|
+
},
|
|
1143
1184
|
"colorMap": {
|
|
1144
1185
|
"type": "object",
|
|
1145
1186
|
"description": "Raw value to badge variant. Keys are matched ignoring case.",
|
|
@@ -1662,7 +1703,7 @@
|
|
|
1662
1703
|
"sizeToContent": {
|
|
1663
1704
|
"type": ["boolean", "integer"],
|
|
1664
1705
|
"minimum": 1,
|
|
1665
|
-
"description": "Opt-in: hand this placement's height to whatever it renders, so a widget that decides AT RUNTIME it has nothing to show costs no row. `true` sizes purely to content; an integer
|
|
1706
|
+
"description": "Opt-in: hand this placement's height to whatever it renders, so a widget that decides AT RUNTIME it has nothing to show costs no row. `true` sizes purely to content; an integer sizes to content too but caps the height at that many rows (GridStack's maximum, NOT a minimum: content shorter than N rows is as short as it is, content taller is clipped at N). It makes gridHeight advisory for this widget — right for anything whose height is whatever it turned out to be (a banner whose condition is false, a list that came back empty), wrong for anything with a deliberate size. Maps to CnDashboardGrid's per-item `sizeToContent`."
|
|
1666
1707
|
},
|
|
1667
1708
|
"props": {
|
|
1668
1709
|
"type": "object",
|
|
@@ -1869,11 +1910,16 @@
|
|
|
1869
1910
|
"properties": {
|
|
1870
1911
|
"register": { "type": "string" },
|
|
1871
1912
|
"schema": { "type": "string" },
|
|
1872
|
-
"filter": { "type": "object", "additionalProperties": true }
|
|
1913
|
+
"filter": { "type": "object", "additionalProperties": true },
|
|
1914
|
+
"order": {
|
|
1915
|
+
"type": "object",
|
|
1916
|
+
"additionalProperties": { "type": "string", "enum": ["asc", "desc"] },
|
|
1917
|
+
"description": "Order of the query (`{ field: \"asc\" | \"desc\" }`), so the first result is the first of an ordered list. With it an attention card names that row: `{subject.<field>}` in its title, reason and kicker and `@subject.<field>` in an action route read it (screens-start-here-banner, 2.89.0)."
|
|
1918
|
+
}
|
|
1873
1919
|
}
|
|
1874
1920
|
},
|
|
1875
1921
|
"field": { "type": "string", "description": "Dot-path into the response ('@total' or omitted = collection total for a source)." },
|
|
1876
|
-
"op": { "type": "string", "enum": ["eq", "neq", "gt", "gte", "lt", "lte"], "default": "eq", "description": "Comparison operator." },
|
|
1922
|
+
"op": { "type": "string", "enum": ["eq", "neq", "gt", "gte", "lt", "lte", "empty", "notEmpty"], "default": "eq", "description": "Comparison operator. `notEmpty` on `id` is the \"there is a first row\" test of a card that names one." },
|
|
1877
1923
|
"value": { "description": "Literal right-hand side of the comparison." }
|
|
1878
1924
|
}
|
|
1879
1925
|
},
|
|
@@ -1890,6 +1936,11 @@
|
|
|
1890
1936
|
"default": "banner",
|
|
1891
1937
|
"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."
|
|
1892
1938
|
},
|
|
1939
|
+
"stacked": {
|
|
1940
|
+
"type": "boolean",
|
|
1941
|
+
"default": false,
|
|
1942
|
+
"description": "Attention card: put the actions under the text instead of beside it, with a 16px title (PqMijnWerk \"Begin hier\"; screens-start-here-banner, 2.89.0)."
|
|
1943
|
+
},
|
|
1893
1944
|
"kicker": {
|
|
1894
1945
|
"type": "string",
|
|
1895
1946
|
"description": "Attention card: the small label above the title."
|
|
@@ -2155,9 +2206,27 @@
|
|
|
2155
2206
|
},
|
|
2156
2207
|
"style": {
|
|
2157
2208
|
"type": "string",
|
|
2158
|
-
"enum": ["radio", "select"],
|
|
2209
|
+
"enum": ["radio", "select", "chips", "toggle"],
|
|
2159
2210
|
"default": "radio",
|
|
2160
|
-
"description": "Choice style: 'radio' (default) list
|
|
2211
|
+
"description": "Choice style: 'radio' (default) list, 'select' dropdown, 'chips' (one compact segmented group with a count after each label; screens-page-lenses, 2.87.0) or 'toggle' (a switch writing `onValue` / `offValue`; screens-page-controls, 2.88.0)."
|
|
2212
|
+
},
|
|
2213
|
+
"layout": {
|
|
2214
|
+
"type": "string",
|
|
2215
|
+
"enum": ["start", "bar"],
|
|
2216
|
+
"description": "'start' draws the start card; 'bar' draws `controls` side by side in one row (screens-page-controls, 2.88.0)."
|
|
2217
|
+
},
|
|
2218
|
+
"controls": {
|
|
2219
|
+
"type": "array",
|
|
2220
|
+
"items": { "type": "object", "additionalProperties": true },
|
|
2221
|
+
"description": "With `layout: \"bar\"`: the bar's controls, each a workspace-filter content (chips, a toggle, a select) with its own `writes`. `align: \"end\"` pushes a control to the right edge (2.88.0)."
|
|
2222
|
+
},
|
|
2223
|
+
"onValue": { "description": "style 'toggle': the value written while the switch is on. Default true (2.88.0)." },
|
|
2224
|
+
"offValue": { "description": "style 'toggle': the value written while the switch is off. Default false (2.88.0)." },
|
|
2225
|
+
"align": { "type": "string", "enum": ["start", "end"], "description": "In a bar: 'end' pushes this control to the right edge (2.88.0)." },
|
|
2226
|
+
"urlKey": {
|
|
2227
|
+
"type": "string",
|
|
2228
|
+
"minLength": 1,
|
|
2229
|
+
"description": "Keep the choice in the address as `?<urlKey>=<value>` (replacing the history entry, keeping other query keys). The address wins over `default` on load, so a chip is linkable (screens-page-lenses, 2.87.0)."
|
|
2161
2230
|
},
|
|
2162
2231
|
"allLabel": {
|
|
2163
2232
|
"type": "string",
|
|
@@ -2170,7 +2239,7 @@
|
|
|
2170
2239
|
},
|
|
2171
2240
|
"options": {
|
|
2172
2241
|
"type": "array",
|
|
2173
|
-
"description": "Static options — each { value, label, count? } (or { id, name } / bare strings, normalised).",
|
|
2242
|
+
"description": "Static options — each { value, label, count?, countFrom? } (or { id, name } / bare strings, normalised). `countFrom` is `{ register, schema, filter? }`, or a list of those that are added up; the option shows that list's total (one list request each; none when it fails). screens-page-lenses, 2.87.0.",
|
|
2174
2243
|
"items": { "type": ["object", "string", "number"] }
|
|
2175
2244
|
},
|
|
2176
2245
|
"source": {
|
|
@@ -2582,6 +2651,14 @@
|
|
|
2582
2651
|
"type": "string",
|
|
2583
2652
|
"description": "open-form: overrides the create dialog's heading. Defaults to 'Create {schema title}'."
|
|
2584
2653
|
},
|
|
2654
|
+
"formEyebrow": {
|
|
2655
|
+
"type": "string",
|
|
2656
|
+
"description": "open-form: the context line above the create dialog's heading (board look), e.g. the list the record joins. Through the host translate. Absent: no line."
|
|
2657
|
+
},
|
|
2658
|
+
"formSubtitle": {
|
|
2659
|
+
"type": "string",
|
|
2660
|
+
"description": "open-form: the sentence under the create dialog's heading (board look), e.g. which fields are required and what happens on save. Through the host translate. Absent: no sentence."
|
|
2661
|
+
},
|
|
2585
2662
|
"size": {
|
|
2586
2663
|
"type": "string",
|
|
2587
2664
|
"enum": ["small", "normal", "large", "full"],
|
|
@@ -2888,15 +2965,20 @@
|
|
|
2888
2965
|
"filter": { "type": "object", "additionalProperties": true }
|
|
2889
2966
|
}
|
|
2890
2967
|
},
|
|
2968
|
+
"workspace": {
|
|
2969
|
+
"type": "string",
|
|
2970
|
+
"minLength": 1,
|
|
2971
|
+
"description": "WORKSPACE mode (screens-page-lenses, 2.87.0): the key of the page workspace context to compare, read at once with no request. A page control (a `workspace-filter` with `writes`) sets the key, and a dashboard widget carrying this condition appears and disappears as it changes. Honoured on a dashboard widget or KPI-row tile only, and as a top-level condition (not inside `all` / `any`)."
|
|
2972
|
+
},
|
|
2891
2973
|
"field": {
|
|
2892
2974
|
"type": "string",
|
|
2893
2975
|
"description": "Dot-path to the compared value — into the endpoint body, the source's first result, or (LOCAL mode) the caller's object context."
|
|
2894
2976
|
},
|
|
2895
2977
|
"op": {
|
|
2896
2978
|
"type": "string",
|
|
2897
|
-
"enum": ["eq", "neq", "gt", "gte", "lt", "lte", "empty", "notEmpty"],
|
|
2979
|
+
"enum": ["eq", "neq", "gt", "gte", "lt", "lte", "empty", "notEmpty", "in"],
|
|
2898
2980
|
"default": "eq",
|
|
2899
|
-
"description": "Comparison operator (default eq). eq/neq compare loosely-normalised primitives; ordering operators coerce both sides to Number. `empty` / `notEmpty` take no `value` and treat undefined, null, '' and an empty array alike — the one question eq cannot ask, because an unset field arrives in a shape that depends on the store and String(null) is the word 'null' rather than blank."
|
|
2981
|
+
"description": "Comparison operator (default eq). eq/neq compare loosely-normalised primitives; ordering operators coerce both sides to Number. `in` holds when the value is one of the listed `value` array (2.87.0). `empty` / `notEmpty` take no `value` and treat undefined, null, '' and an empty array alike — the one question eq cannot ask, because an unset field arrives in a shape that depends on the store and String(null) is the word 'null' rather than blank."
|
|
2900
2982
|
},
|
|
2901
2983
|
"value": {
|
|
2902
2984
|
"description": "The right-hand side of the comparison, resolved through the shared @-token grammar so `@me` names the signed-in reader rather than a literal only the server knows. Omitted for `empty` / `notEmpty`."
|
|
@@ -2948,6 +3030,45 @@
|
|
|
2948
3030
|
"type": "array",
|
|
2949
3031
|
"items": { "type": "string" },
|
|
2950
3032
|
"description": "OpenRegister `_extend[]` values forwarded on the fetch (e.g. [\"calculations\"]) so read-time virtual/derived fields are hydrated and available as columns. Each entry is passed through verbatim."
|
|
3033
|
+
},
|
|
3034
|
+
"pageControls": { "$ref": "#/$defs/pageControls" }
|
|
3035
|
+
}
|
|
3036
|
+
},
|
|
3037
|
+
"pageControls": {
|
|
3038
|
+
"type": "object",
|
|
3039
|
+
"additionalProperties": false,
|
|
3040
|
+
"description": "screens-page-controls (2.88.0): which page controls a list widget (`record-list`, `object-table`) listens to, and what they mean for it. A page control is a `workspace-filter` select or switch that writes a workspace key. `sort` picks the list's sort from the key's value; `toggle` drops filter keys while the key is on. Without it the list ignores the page's controls.",
|
|
3041
|
+
"properties": {
|
|
3042
|
+
"sort": {
|
|
3043
|
+
"type": "object",
|
|
3044
|
+
"required": ["key", "map"],
|
|
3045
|
+
"additionalProperties": false,
|
|
3046
|
+
"description": "The workspace key a sort select writes, and what each of its values sorts by. A value with no entry leaves the list's own sort.",
|
|
3047
|
+
"properties": {
|
|
3048
|
+
"key": { "type": "string", "minLength": 1 },
|
|
3049
|
+
"map": {
|
|
3050
|
+
"type": "object",
|
|
3051
|
+
"additionalProperties": {
|
|
3052
|
+
"type": "object",
|
|
3053
|
+
"required": ["field"],
|
|
3054
|
+
"additionalProperties": false,
|
|
3055
|
+
"properties": {
|
|
3056
|
+
"field": { "type": "string", "minLength": 1 },
|
|
3057
|
+
"dir": { "type": "string", "enum": ["asc", "desc"], "default": "asc" }
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
},
|
|
3063
|
+
"toggle": {
|
|
3064
|
+
"type": "object",
|
|
3065
|
+
"required": ["key", "removes"],
|
|
3066
|
+
"additionalProperties": false,
|
|
3067
|
+
"description": "The workspace key a switch writes. While it is on (true, 1, \"1\", \"true\") the filter keys in `removes` are dropped, so a list that hides finished work shows it.",
|
|
3068
|
+
"properties": {
|
|
3069
|
+
"key": { "type": "string", "minLength": 1 },
|
|
3070
|
+
"removes": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1 } }
|
|
3071
|
+
}
|
|
2951
3072
|
}
|
|
2952
3073
|
}
|
|
2953
3074
|
},
|
|
@@ -4072,6 +4193,36 @@
|
|
|
4072
4193
|
"minLength": 1,
|
|
4073
4194
|
"description": "type='index', board look: free text after the footer's count, e.g. \"click a column header to sort\" (screens-index-list-parity). Maps to CnIndexPage `footerNote`."
|
|
4074
4195
|
},
|
|
4196
|
+
"queryPresets": {
|
|
4197
|
+
"type": "array",
|
|
4198
|
+
"minItems": 1,
|
|
4199
|
+
"description": "type='index': per-query overlays of this page (screens-index-query-presets). A menu entry that deep-links here with a query (`menu[].query`, e.g. { caseType: '<uuid>' }, the shape hydra gate-68 asks for instead of a second page) gets its own lenses, columns and copy: the first preset whose every `match` pair is in the route query replaces those keys of this config. Only the listed keys can be replaced; register, schema and permissions stay the page's. Switching preset remounts the list.",
|
|
4200
|
+
"items": {
|
|
4201
|
+
"type": "object",
|
|
4202
|
+
"required": ["match"],
|
|
4203
|
+
"additionalProperties": false,
|
|
4204
|
+
"properties": {
|
|
4205
|
+
"id": { "type": "string", "minLength": 1, "description": "A name for the preset, for people reading the manifest." },
|
|
4206
|
+
"match": { "type": "object", "minProperties": 1, "additionalProperties": { "type": ["string", "number", "boolean"] }, "description": "Route query pairs that must ALL be present, e.g. { \"caseType\": \"<uuid>\" }. A repeated parameter matches when it holds the value." },
|
|
4207
|
+
"title": { "type": "string", "minLength": 1, "description": "The page title while the preset applies." },
|
|
4208
|
+
"quickFilters": { "type": "array", "description": "The lenses while the preset applies; same shape as config.quickFilters." },
|
|
4209
|
+
"columns": { "type": "array", "description": "The columns while the preset applies; same shape as config.columns." },
|
|
4210
|
+
"cardFields": { "type": "array", "items": { "type": "string" }, "description": "The card facts while the preset applies." },
|
|
4211
|
+
"countText": { "type": "string", "minLength": 1, "description": "The count line while the preset applies." },
|
|
4212
|
+
"searchPlaceholder": { "type": "string", "minLength": 1, "description": "The search placeholder while the preset applies." },
|
|
4213
|
+
"footerNote": { "type": "string", "minLength": 1, "description": "The footer note while the preset applies." },
|
|
4214
|
+
"defaultSort": { "type": "array", "description": "The default sort while the preset applies; same shape as config.defaultSort." },
|
|
4215
|
+
"viewSwitch": { "type": "array", "items": { "type": "string", "enum": ["table", "cards", "board", "map"] }, "description": "The drawn view segments while the preset applies." }
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
},
|
|
4219
|
+
"viewSwitch": {
|
|
4220
|
+
"type": "array",
|
|
4221
|
+
"minItems": 1,
|
|
4222
|
+
"uniqueItems": true,
|
|
4223
|
+
"items": { "type": "string", "enum": ["table", "cards", "board", "map"] },
|
|
4224
|
+
"description": "type='index', board look: the segments the view switch draws, e.g. [\"table\", \"cards\", \"board\", \"map\"] as the boards do. A listed mode the page can open is an ordinary segment; one it cannot (no board columns, no map) is drawn disabled and named \"<mode>: not available on this list\". Order is always table, cards, board, map. Ignored without the board look (screens-view-switch-parity). Maps to CnIndexPage `viewSwitch`."
|
|
4225
|
+
},
|
|
4075
4226
|
"searchPlaceholder": {
|
|
4076
4227
|
"type": "string",
|
|
4077
4228
|
"minLength": 1,
|
|
@@ -4087,6 +4238,38 @@
|
|
|
4087
4238
|
"description": "type='index': the property keys the cards view shows as the facts list of each card, in order; defaults to the first four list columns under the board look (screens-card-parity). Maps to CnIndexPage `cardFields`.",
|
|
4088
4239
|
"items": { "type": "string", "minLength": 1 }
|
|
4089
4240
|
},
|
|
4241
|
+
"statRow": {
|
|
4242
|
+
"type": "array",
|
|
4243
|
+
"default": [],
|
|
4244
|
+
"description": "type='index': KPI tiles above the list, between the header and the toolbar, in an auto-fit row (each at least 200px). Each entry is a widget definition, usually `type: \"stat\"`; the type resolves through the app's widget registry, then the dashboard catalog (screens-index-stat-row). Maps to CnIndexPage `statRow`.",
|
|
4245
|
+
"items": {
|
|
4246
|
+
"type": "object",
|
|
4247
|
+
"required": ["id", "type"],
|
|
4248
|
+
"properties": {
|
|
4249
|
+
"id": { "type": "string", "minLength": 1 },
|
|
4250
|
+
"type": { "type": "string", "minLength": 1 },
|
|
4251
|
+
"title": { "type": "string" },
|
|
4252
|
+
"content": { "type": "object" },
|
|
4253
|
+
"headerLink": { "type": "object" }
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4256
|
+
},
|
|
4257
|
+
"sidePanel": {
|
|
4258
|
+
"type": "array",
|
|
4259
|
+
"default": [],
|
|
4260
|
+
"description": "type='index': titled cards in a 300px column right of the toolbar and the list (above them below 1024px). Each entry is a widget definition with an optional `title` (i18n key) and `headerLink`; the type resolves as for `statRow` (screens-index-stat-row). Maps to CnIndexPage `sidePanel`.",
|
|
4261
|
+
"items": {
|
|
4262
|
+
"type": "object",
|
|
4263
|
+
"required": ["id", "type"],
|
|
4264
|
+
"properties": {
|
|
4265
|
+
"id": { "type": "string", "minLength": 1 },
|
|
4266
|
+
"type": { "type": "string", "minLength": 1 },
|
|
4267
|
+
"title": { "type": "string" },
|
|
4268
|
+
"content": { "type": "object" },
|
|
4269
|
+
"headerLink": { "type": "object" }
|
|
4270
|
+
}
|
|
4271
|
+
}
|
|
4272
|
+
},
|
|
4090
4273
|
"headerButtons": {
|
|
4091
4274
|
"type": "array",
|
|
4092
4275
|
"description": "type='index': buttons beside the page title, as the board's \"Export\" and \"New case\" (zuiddrecht-pixel-gaps-3). `action` is `add` (the Add flow; the label defaults to the Add label), `export` (the export leaf in `format`, else the export dialog; under the board look it reads \"Download\" by default), `actions-menu` (the page's header actions as one labelled menu button, absent when the page has none), `import`, `refresh`, or the id of a `headerActions` entry. Under the board look the buttons render in a fixed order whatever the manifest declares: export, actions-menu, other secondary buttons, the buildiq square, then the primary button. Shown only with `showTitle`; when they show, the actions bar drops its Views and Actions menus, and the Add button and Export menu when a button takes their action. Maps to CnIndexPage `headerButtons`.",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* contentHeaderLink — the text link a widget's content asks its card header
|
|
6
|
+
* to carry: `content.headerLink`, or the shorter `viewAllRoute` (with an
|
|
7
|
+
* optional `viewAllLabel`) that an inbox-style widget uses for its "View all".
|
|
8
|
+
*
|
|
9
|
+
* @module utils/contentHeaderLink
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The header link a widget's `content` declares, in the shape
|
|
14
|
+
* CnWidgetWrapper's `headerLink` takes, or null when it declares none.
|
|
15
|
+
* The label is left as written: the wrapper translates it.
|
|
16
|
+
*
|
|
17
|
+
* `viewAllRoute` is a route name, or a location `{ name, params?, query? }`.
|
|
18
|
+
*
|
|
19
|
+
* @param {object|null|undefined} content The widget's content.
|
|
20
|
+
* @return {{label: string, route?: string, params?: object, query?: object, href?: string}|null}
|
|
21
|
+
*/
|
|
22
|
+
export function contentHeaderLink(content) {
|
|
23
|
+
if (!content || typeof content !== 'object') {
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
const declared = content.headerLink
|
|
27
|
+
if (declared && typeof declared === 'object' && typeof declared.label === 'string' && declared.label !== '') {
|
|
28
|
+
return declared
|
|
29
|
+
}
|
|
30
|
+
const view = content.viewAllRoute
|
|
31
|
+
const name = typeof view === 'string' ? view : (view && typeof view === 'object' ? view.name : '')
|
|
32
|
+
if (typeof name !== 'string' || name === '') {
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
const link = {
|
|
36
|
+
label: typeof content.viewAllLabel === 'string' && content.viewAllLabel !== '' ? content.viewAllLabel : 'View all',
|
|
37
|
+
route: name,
|
|
38
|
+
}
|
|
39
|
+
if (view && typeof view === 'object') {
|
|
40
|
+
if (view.params && typeof view.params === 'object') {
|
|
41
|
+
link.params = view.params
|
|
42
|
+
}
|
|
43
|
+
if (view.query && typeof view.query === 'object') {
|
|
44
|
+
link.query = view.query
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return link
|
|
48
|
+
}
|
|
@@ -201,13 +201,29 @@ export function resolveNextStep(config, object, stageField = 'status') {
|
|
|
201
201
|
/**
|
|
202
202
|
* Resolve a header pill from the record.
|
|
203
203
|
*
|
|
204
|
-
*
|
|
204
|
+
* A pill with `field` reads it off the record; one without `field` and with
|
|
205
|
+
* `text` is a constant. A count pill (`countFrom`) is resolved by
|
|
206
|
+
* {@link resolveCountPill} once its count is known.
|
|
207
|
+
*
|
|
208
|
+
* @param {{field?: string, text?: string, colorMap?: object, labels?: object, variant?: string}|null} config The pill config.
|
|
205
209
|
* @param {object|null} object The record.
|
|
206
210
|
* @return {{label: string, colorKey: string, colorMap: object|null, variant: string}|null} What CnStatusBadge needs, or null when the field is empty.
|
|
207
211
|
* @spec openspec/changes/detail-action-model-and-case-surfaces/specs/detail-action-model/spec.md#requirement-header-pills
|
|
208
212
|
*/
|
|
209
213
|
export function resolvePill(config, object) {
|
|
210
|
-
if (!config || typeof config !== 'object'
|
|
214
|
+
if (!config || typeof config !== 'object') {
|
|
215
|
+
return null
|
|
216
|
+
}
|
|
217
|
+
// A constant pill (`text`): "Inwoner", "Klant" (screens-relation-pages).
|
|
218
|
+
if ((typeof config.field !== 'string' || config.field === '') && typeof config.text === 'string' && config.text !== '') {
|
|
219
|
+
return {
|
|
220
|
+
label: config.text,
|
|
221
|
+
colorKey: config.text,
|
|
222
|
+
colorMap: config.colorMap && typeof config.colorMap === 'object' ? config.colorMap : null,
|
|
223
|
+
variant: typeof config.variant === 'string' && config.variant !== '' ? config.variant : 'default',
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (typeof config.field !== 'string' || config.field === '') {
|
|
211
227
|
return null
|
|
212
228
|
}
|
|
213
229
|
const raw = stageOf(object, config.field)
|
|
@@ -260,3 +276,44 @@ export function resolveTabCount(tab, object) {
|
|
|
260
276
|
const number = Number(value)
|
|
261
277
|
return Number.isFinite(number) ? number : null
|
|
262
278
|
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* The list a count pill counts (`countFrom`), or null for any other pill.
|
|
282
|
+
*
|
|
283
|
+
* @param {object|null} config The pill config.
|
|
284
|
+
* @return {{register: string, schema: string, filter: object}|null} The list.
|
|
285
|
+
* @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-header-pill-can-be-a-constant-or-a-count
|
|
286
|
+
*/
|
|
287
|
+
export function pillCountSource(config) {
|
|
288
|
+
const from = config && typeof config === 'object' && !config.field ? config.countFrom : null
|
|
289
|
+
if (!from || typeof from !== 'object' || typeof from.register !== 'string' || from.register === '' || typeof from.schema !== 'string' || from.schema === '') {
|
|
290
|
+
return null
|
|
291
|
+
}
|
|
292
|
+
const filter = from.filter && typeof from.filter === 'object' && !Array.isArray(from.filter) ? from.filter : {}
|
|
293
|
+
return { register: from.register, schema: from.schema, filter }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* A count pill once its count is known: "1 lopende zaak", "2 lopende zaken".
|
|
298
|
+
* Nothing for a count of 0, an unknown count or a failed one.
|
|
299
|
+
*
|
|
300
|
+
* @param {{countLabel?: {one?: string, other?: string}, colorMap?: object, variant?: string}|null} config The pill config.
|
|
301
|
+
* @param {number|null|undefined} count The count.
|
|
302
|
+
* @param {(text: string) => string} [translate] Applied to the label before `{count}` is filled.
|
|
303
|
+
* @return {{label: string, colorKey: string, colorMap: object|null, variant: string}|null} What CnStatusBadge needs, or null.
|
|
304
|
+
* @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-header-pill-can-be-a-constant-or-a-count
|
|
305
|
+
*/
|
|
306
|
+
export function resolveCountPill(config, count, translate = (text) => text) {
|
|
307
|
+
if (!pillCountSource(config) || typeof count !== 'number' || !Number.isFinite(count) || count <= 0) {
|
|
308
|
+
return null
|
|
309
|
+
}
|
|
310
|
+
const labels = config.countLabel && typeof config.countLabel === 'object' ? config.countLabel : {}
|
|
311
|
+
const template = (count === 1 ? labels.one : labels.other) || labels.other || labels.one || '{count}'
|
|
312
|
+
const label = translate(template).replace(/\{count\}/g, String(count))
|
|
313
|
+
return {
|
|
314
|
+
label,
|
|
315
|
+
colorKey: '',
|
|
316
|
+
colorMap: config.colorMap && typeof config.colorMap === 'object' ? config.colorMap : null,
|
|
317
|
+
variant: typeof config.variant === 'string' && config.variant !== '' ? config.variant : 'default',
|
|
318
|
+
}
|
|
319
|
+
}
|