@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
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
- SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
- SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<div class="cn-switch-rows" data-testid="cn-switch-rows">
|
|
8
|
+
<ul class="cn-switch-rows__list">
|
|
9
|
+
<li
|
|
10
|
+
v-for="row in rows"
|
|
11
|
+
:key="row.key"
|
|
12
|
+
class="cn-switch-rows__row"
|
|
13
|
+
:data-testid="`cn-switch-rows-row-${row.key}`">
|
|
14
|
+
<NcCheckboxRadioSwitch
|
|
15
|
+
:modelValue="values[row.key] === true"
|
|
16
|
+
type="switch"
|
|
17
|
+
:disabled="readOnly || busy === row.key"
|
|
18
|
+
@update:modelValue="toggle(row, $event)">
|
|
19
|
+
<span class="cn-switch-rows__label">{{ row.label }}</span>
|
|
20
|
+
<span v-if="row.hint" class="cn-switch-rows__hint">{{ row.hint }}</span>
|
|
21
|
+
</NcCheckboxRadioSwitch>
|
|
22
|
+
</li>
|
|
23
|
+
</ul>
|
|
24
|
+
<NcNoteCard v-if="notice" type="error" data-testid="cn-switch-rows-notice">
|
|
25
|
+
{{ notice }}
|
|
26
|
+
</NcNoteCard>
|
|
27
|
+
</div>
|
|
28
|
+
</template>
|
|
29
|
+
|
|
30
|
+
<script>
|
|
31
|
+
import { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'
|
|
32
|
+
import { objectUrlOf, patchObject } from '../../utils/objectWrite.js'
|
|
33
|
+
import { readPath } from '../../utils/readPath.js'
|
|
34
|
+
import { serverErrorMessage } from '../../utils/serverErrorMessage.js'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* CnSwitchRowsWidget — the `switch-rows` widget: a card of switches, each with
|
|
38
|
+
* a label and a hint, bound to boolean fields of the CURRENT object. A toggle
|
|
39
|
+
* saves at once with ONE PATCH of that field; a refused PATCH puts the switch
|
|
40
|
+
* back and shows the server's words.
|
|
41
|
+
*
|
|
42
|
+
* @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md
|
|
43
|
+
*/
|
|
44
|
+
export default {
|
|
45
|
+
name: 'CnSwitchRowsWidget',
|
|
46
|
+
|
|
47
|
+
components: { NcCheckboxRadioSwitch, NcNoteCard },
|
|
48
|
+
|
|
49
|
+
inject: {
|
|
50
|
+
cnTranslate: { default: () => (key) => key },
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
props: {
|
|
54
|
+
/**
|
|
55
|
+
* The widget configuration.
|
|
56
|
+
*
|
|
57
|
+
* - `rows` (required) — `[{ key, label, hint?, invert? }]`; `key` is a top-level boolean field. `invert` shows the switch on when the field is false (a stored `disabled` read as "enabled").
|
|
58
|
+
* - `readOnly`.
|
|
59
|
+
*
|
|
60
|
+
* @type {object}
|
|
61
|
+
*/
|
|
62
|
+
content: {
|
|
63
|
+
type: Object,
|
|
64
|
+
default: () => ({}),
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
/** The current detail-page object. */
|
|
68
|
+
objectData: {
|
|
69
|
+
type: Object,
|
|
70
|
+
default: null,
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
/** The current object id. */
|
|
74
|
+
objectId: {
|
|
75
|
+
type: [String, Number],
|
|
76
|
+
default: '',
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/** OpenRegister register slug of the surface. */
|
|
80
|
+
register: {
|
|
81
|
+
type: [String, Object],
|
|
82
|
+
default: '',
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/** OpenRegister schema slug of the surface. */
|
|
86
|
+
schema: {
|
|
87
|
+
type: [String, Object],
|
|
88
|
+
default: '',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
emits: ['saved'],
|
|
93
|
+
|
|
94
|
+
data() {
|
|
95
|
+
return {
|
|
96
|
+
/** The switch states as last saved (by key, as the switch shows them). */
|
|
97
|
+
saved: {},
|
|
98
|
+
values: {},
|
|
99
|
+
busy: '',
|
|
100
|
+
notice: '',
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
computed: {
|
|
105
|
+
rows() {
|
|
106
|
+
const list = Array.isArray(this.content.rows) ? this.content.rows : []
|
|
107
|
+
return list
|
|
108
|
+
.filter((row) => row && row.key)
|
|
109
|
+
.map((row) => ({ ...row, label: this.tr(row.label || row.key), hint: this.tr(row.hint || '') }))
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
readOnly() {
|
|
113
|
+
return this.content.readOnly === true
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
objectUrl() {
|
|
117
|
+
return objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
watch: {
|
|
122
|
+
objectData() {
|
|
123
|
+
this.adopt()
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
created() {
|
|
128
|
+
this.adopt()
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
methods: {
|
|
132
|
+
tr(text) {
|
|
133
|
+
if (typeof text !== 'string' || text === '') {
|
|
134
|
+
return ''
|
|
135
|
+
}
|
|
136
|
+
return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
/** Read every switch off the object. */
|
|
140
|
+
adopt() {
|
|
141
|
+
const values = {}
|
|
142
|
+
for (const row of this.rows) {
|
|
143
|
+
const stored = readPath(this.objectData || {}, row.key) === true
|
|
144
|
+
values[row.key] = row.invert ? !stored : stored
|
|
145
|
+
}
|
|
146
|
+
this.saved = values
|
|
147
|
+
this.values = { ...values }
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Flip one switch and save that one field.
|
|
152
|
+
*
|
|
153
|
+
* @param {object} row The row.
|
|
154
|
+
* @param {boolean} on The new switch state.
|
|
155
|
+
* @return {Promise<void>}
|
|
156
|
+
* @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md#requirement-a-toggle-saves-that-one-field
|
|
157
|
+
*/
|
|
158
|
+
async toggle(row, on) {
|
|
159
|
+
if (!this.objectUrl) {
|
|
160
|
+
this.notice = this.tr('This switch cannot be saved here.')
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
this.notice = ''
|
|
164
|
+
this.busy = row.key
|
|
165
|
+
this.values = { ...this.values, [row.key]: on }
|
|
166
|
+
const stored = row.invert ? !on : on
|
|
167
|
+
try {
|
|
168
|
+
const data = await patchObject(this.objectUrl, { [row.key]: stored })
|
|
169
|
+
const written = data[row.key] !== undefined ? data[row.key] === true : stored
|
|
170
|
+
const shown = row.invert ? !written : written
|
|
171
|
+
this.saved = { ...this.saved, [row.key]: shown }
|
|
172
|
+
this.values = { ...this.values, [row.key]: shown }
|
|
173
|
+
/**
|
|
174
|
+
* @event saved A switch was written.
|
|
175
|
+
* @type {{field: string, value: boolean}}
|
|
176
|
+
*/
|
|
177
|
+
this.$emit('saved', { field: row.key, value: written })
|
|
178
|
+
} catch (e) {
|
|
179
|
+
this.values = { ...this.values, [row.key]: this.saved[row.key] }
|
|
180
|
+
this.notice = serverErrorMessage(e)
|
|
181
|
+
} finally {
|
|
182
|
+
this.busy = ''
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
}
|
|
187
|
+
</script>
|
|
188
|
+
|
|
189
|
+
<style scoped>
|
|
190
|
+
.cn-switch-rows {
|
|
191
|
+
display: flex;
|
|
192
|
+
flex-direction: column;
|
|
193
|
+
gap: 8px;
|
|
194
|
+
min-width: 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.cn-switch-rows__list {
|
|
198
|
+
list-style: none;
|
|
199
|
+
margin: 0;
|
|
200
|
+
padding: 0;
|
|
201
|
+
display: flex;
|
|
202
|
+
flex-direction: column;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.cn-switch-rows__row {
|
|
206
|
+
padding: 10px 0;
|
|
207
|
+
border-top: 1px solid var(--cn-board-hairline, var(--color-border));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.cn-switch-rows__row:first-child {
|
|
211
|
+
border-top: none;
|
|
212
|
+
padding-top: 0;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.cn-switch-rows__label {
|
|
216
|
+
display: block;
|
|
217
|
+
font-weight: 600;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.cn-switch-rows__hint {
|
|
221
|
+
display: block;
|
|
222
|
+
font-size: 12px;
|
|
223
|
+
font-weight: 400;
|
|
224
|
+
color: var(--color-text-maxcontrast);
|
|
225
|
+
}
|
|
226
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
3
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
4
|
+
*
|
|
5
|
+
* CnSwitchRowsWidget — self-registers the `switch-rows` widget type (a card of
|
|
6
|
+
* switches, each with a label and a hint, bound to boolean fields of the
|
|
7
|
+
* current object and saved on toggle) into the shared dashboardWidgetRegistry.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import CnSwitchRowsWidget from './CnSwitchRowsWidget.vue'
|
|
11
|
+
import { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js'
|
|
12
|
+
|
|
13
|
+
registerDashboardWidget('switch-rows', {
|
|
14
|
+
renderer: CnSwitchRowsWidget,
|
|
15
|
+
form: null,
|
|
16
|
+
defaultContent: {
|
|
17
|
+
rows: [],
|
|
18
|
+
},
|
|
19
|
+
displayName: 'Switch rows',
|
|
20
|
+
icon: 'ToggleSwitch',
|
|
21
|
+
surfaces: ['detail-page'],
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
export { CnSwitchRowsWidget }
|
|
25
|
+
export default CnSwitchRowsWidget
|
|
@@ -80,10 +80,66 @@
|
|
|
80
80
|
</span>
|
|
81
81
|
</template>
|
|
82
82
|
|
|
83
|
+
<!-- A stack (`widgetIds`): every widget is a titled card; the
|
|
84
|
+
first joins the open tab, the next ones stand below it. -->
|
|
85
|
+
<div
|
|
86
|
+
v-if="entry.widget && entry.stack.length"
|
|
87
|
+
class="cn-tabs-widget__stack"
|
|
88
|
+
:class="{ 'cn-tabs-widget__stack--grid': !!entry.grid }"
|
|
89
|
+
data-testid="cn-tabs-widget-stack">
|
|
90
|
+
<div class="cn-tabs-widget__stack-first" :style="spanStyle(entry.grid, 0)">
|
|
91
|
+
<CnDetailWidgetHost
|
|
92
|
+
:widget="entry.widget"
|
|
93
|
+
chrome="card"
|
|
94
|
+
:showCardTitle="true"
|
|
95
|
+
:showActions="false"
|
|
96
|
+
:availableWidgets="availableWidgets"
|
|
97
|
+
:objectId="objectId"
|
|
98
|
+
:object="objectData"
|
|
99
|
+
:objectType="objectType"
|
|
100
|
+
:schemaObject="schemaObject"
|
|
101
|
+
:register="register"
|
|
102
|
+
:schema="schema"
|
|
103
|
+
:store="store"
|
|
104
|
+
:surface="surface"
|
|
105
|
+
:integrationContext="integrationContext"
|
|
106
|
+
:cnRegistry="cnRegistry"
|
|
107
|
+
@geoSaved="onGeoSaved"
|
|
108
|
+
@openIntegration="onOpenIntegration"
|
|
109
|
+
@selectObject="onSelectObject" />
|
|
110
|
+
</div>
|
|
111
|
+
<div
|
|
112
|
+
v-for="(child, childIndex) in entry.stack"
|
|
113
|
+
:key="`${entry.key}-${child.id}`"
|
|
114
|
+
class="cn-tabs-widget__stack-item"
|
|
115
|
+
:style="spanStyle(entry.grid, childIndex + 1)"
|
|
116
|
+
:data-testid="`cn-tabs-widget-stack-${child.id}`">
|
|
117
|
+
<CnDetailWidgetHost
|
|
118
|
+
:widget="child"
|
|
119
|
+
chrome="card"
|
|
120
|
+
:showCardTitle="true"
|
|
121
|
+
:showActions="false"
|
|
122
|
+
:availableWidgets="availableWidgets"
|
|
123
|
+
:objectId="objectId"
|
|
124
|
+
:object="objectData"
|
|
125
|
+
:objectType="objectType"
|
|
126
|
+
:schemaObject="schemaObject"
|
|
127
|
+
:register="register"
|
|
128
|
+
:schema="schema"
|
|
129
|
+
:store="store"
|
|
130
|
+
:surface="surface"
|
|
131
|
+
:integrationContext="integrationContext"
|
|
132
|
+
:cnRegistry="cnRegistry"
|
|
133
|
+
@geoSaved="onGeoSaved"
|
|
134
|
+
@openIntegration="onOpenIntegration"
|
|
135
|
+
@selectObject="onSelectObject" />
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
83
138
|
<CnDetailWidgetHost
|
|
84
|
-
v-if="entry.widget"
|
|
139
|
+
v-else-if="entry.widget"
|
|
85
140
|
:widget="entry.widget"
|
|
86
141
|
chrome="bare"
|
|
142
|
+
:availableWidgets="availableWidgets"
|
|
87
143
|
:objectId="objectId"
|
|
88
144
|
:object="objectData"
|
|
89
145
|
:objectType="objectType"
|
|
@@ -114,6 +170,7 @@ import CnTab from '../CnTabs/CnTab.vue'
|
|
|
114
170
|
import CnTabs from '../CnTabs/CnTabs.vue'
|
|
115
171
|
import { normalizeLook } from '../../composables/useLook.js'
|
|
116
172
|
import { resolveTabCount } from '../../utils/detailActionModel.js'
|
|
173
|
+
import { fetchListTotal } from '../../utils/fetchFilterCounts.js'
|
|
117
174
|
import { isActivityWidget } from '../../utils/headerMeta.js'
|
|
118
175
|
import { PANEL_ACTION_SINK } from '../../utils/panelActions.js'
|
|
119
176
|
import { evaluateVisibleWhen, evaluateVisibleWhenLocal, isLocallyDecidableVisibleWhen } from '../../utils/visibleWhen.js'
|
|
@@ -268,15 +325,24 @@ export default {
|
|
|
268
325
|
* `tabs[]` entries are `{ widgetId, label?, icon?, count?, countField?, overflow? }`.
|
|
269
326
|
* `label` and `icon` fall back to the referenced widget's own title and
|
|
270
327
|
* icon. `count` is a number shown after the label; `countField` reads
|
|
271
|
-
* it off the record instead (a list counts its items). `
|
|
328
|
+
* it off the record instead (a list counts its items). `countFrom`
|
|
329
|
+
* counts a list on the server: `"widget"` counts the child widget's
|
|
330
|
+
* own list (`content.register`, `schema`, `filter`, tokens such as
|
|
331
|
+
* `@objectId` resolved), an object `{ register, schema, filter? }`
|
|
332
|
+
* names the list; `count` and `countField` win over it. `overflow: true`
|
|
272
333
|
* lists the tab under "More".
|
|
273
334
|
*
|
|
335
|
+
* A tab with `widgetIds` can lay them out in a grid instead of one under
|
|
336
|
+
* the other: `columns: 4` gives each a quarter of the row, and
|
|
337
|
+
* `layout: [{ widgetId, gridWidth }]` sets a width (of 12) per widget, as
|
|
338
|
+
* the page grid does. Widgets wrap onto the next row.
|
|
339
|
+
*
|
|
274
340
|
* `maxVisibleTabs` caps the strip: later tabs go under "More".
|
|
275
341
|
* `hideEmpty: true` moves a tab whose count is 0 there too.
|
|
276
342
|
* `moreLabel` names that menu. `variant: "segmented"` draws the strip
|
|
277
343
|
* as a pill switch (CnTabs' segmented variant); `line` is the default.
|
|
278
344
|
*
|
|
279
|
-
* @type {{ tabs?: Array<{widgetId
|
|
345
|
+
* @type {{ tabs?: Array<{widgetId?: string, widgetIds?: string[], label?: string, icon?: string, count?: number, countField?: string, countFrom?: ('widget'|{register: string, schema: string, filter?: object}), overflow?: boolean, columns?: number, layout?: Array<{widgetId: string, gridWidth: number}>}>, ariaLabel?: string, maxVisibleTabs?: number, hideEmpty?: boolean, moreLabel?: string, variant?: ('line'|'segmented') }}
|
|
280
346
|
*/
|
|
281
347
|
content: {
|
|
282
348
|
type: Object,
|
|
@@ -396,6 +462,9 @@ export default {
|
|
|
396
462
|
sourceVisibility: {},
|
|
397
463
|
// Bumped per evaluation round, so a slow answer from an earlier round is dropped.
|
|
398
464
|
visibilitySeq: 0,
|
|
465
|
+
// Totals counted for tabs with `countFrom`, by position in `content.tabs`.
|
|
466
|
+
widgetCounts: {},
|
|
467
|
+
countSeq: 0,
|
|
399
468
|
// Tab id named by the route hash that has not appeared yet (still pending).
|
|
400
469
|
hashTargetId: '',
|
|
401
470
|
// Items published by the panels, keyed by widget id. Keyed rather
|
|
@@ -438,7 +507,7 @@ export default {
|
|
|
438
507
|
// whatever its place in the manifest. `index` stays the position in
|
|
439
508
|
// `content.tabs`, which the source-mode conditions are keyed on.
|
|
440
509
|
const isActivityTab = (tab) => {
|
|
441
|
-
const id =
|
|
510
|
+
const id = this.tabWidgetIds(tab)[0]
|
|
442
511
|
return isActivityWidget(this.availableWidgets.find((w) => w && w.id === id))
|
|
443
512
|
}
|
|
444
513
|
const ordered = authored.map((tab, index) => ({ tab, index }))
|
|
@@ -460,9 +529,19 @@ export default {
|
|
|
460
529
|
if (visibility === 'hidden') {
|
|
461
530
|
return
|
|
462
531
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
const
|
|
532
|
+
// A stack (`widgetIds`) resolves every id; one that names no
|
|
533
|
+
// widget is skipped. The first that resolves is the panel's.
|
|
534
|
+
const ids = this.tabWidgetIds(tab)
|
|
535
|
+
const widgets = ids.length > 1
|
|
536
|
+
? ids.map((id) => this.availableWidgets.find((w) => w && w.id === id) || null).filter(Boolean)
|
|
537
|
+
: []
|
|
538
|
+
const widget = ids.length > 1
|
|
539
|
+
? (widgets[0] || null)
|
|
540
|
+
: (this.availableWidgets.find((w) => w && w.id === ids[0]) || null)
|
|
541
|
+
const widgetId = widget ? widget.id : ids[0]
|
|
542
|
+
const declared = resolveTabCount(typeof tab === 'object' ? tab : null, this.objectData)
|
|
543
|
+
const counted = this.widgetCounts[index]
|
|
544
|
+
const count = declared === null && typeof counted === 'number' ? counted : declared
|
|
466
545
|
// The board strip has no "More": every tab is in the strip.
|
|
467
546
|
let overflow = !this.isBoard && ((tab && tab.overflow === true) || (hideEmpty && count === 0))
|
|
468
547
|
if (!overflow && !this.isBoard) {
|
|
@@ -479,6 +558,8 @@ export default {
|
|
|
479
558
|
label: this.tabLabel(tab, widget, widgetId),
|
|
480
559
|
icon: (tab && tab.icon) || widget?.icon || '',
|
|
481
560
|
widget,
|
|
561
|
+
stack: widgets.slice(1),
|
|
562
|
+
grid: this.stackGrid(tab, widgets),
|
|
482
563
|
count,
|
|
483
564
|
overflow,
|
|
484
565
|
pending: visibility === 'pending',
|
|
@@ -497,6 +578,17 @@ export default {
|
|
|
497
578
|
return t('nextcloud-vue', 'Loading …')
|
|
498
579
|
},
|
|
499
580
|
|
|
581
|
+
/**
|
|
582
|
+
* The lists the tabs count (`countFrom`), serialised, to count again
|
|
583
|
+
* when they change.
|
|
584
|
+
*
|
|
585
|
+
* @return {string} The key.
|
|
586
|
+
*/
|
|
587
|
+
countSourcesKey() {
|
|
588
|
+
const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : []
|
|
589
|
+
return JSON.stringify(tabs.map((tab) => this.countSourceOf(tab)))
|
|
590
|
+
},
|
|
591
|
+
|
|
500
592
|
/** @return {string} The source-mode conditions, serialised, to re-evaluate when they change. */
|
|
501
593
|
sourceConditionsKey() {
|
|
502
594
|
const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : []
|
|
@@ -609,6 +701,12 @@ export default {
|
|
|
609
701
|
objectId() {
|
|
610
702
|
this.sourceVisibility = {}
|
|
611
703
|
this.refreshSourceVisibility()
|
|
704
|
+
this.widgetCounts = {}
|
|
705
|
+
this.refreshWidgetCounts()
|
|
706
|
+
},
|
|
707
|
+
|
|
708
|
+
countSourcesKey() {
|
|
709
|
+
this.refreshWidgetCounts()
|
|
612
710
|
},
|
|
613
711
|
|
|
614
712
|
sourceConditionsKey() {
|
|
@@ -643,10 +741,14 @@ export default {
|
|
|
643
741
|
}
|
|
644
742
|
this.activeKey = this.resolvedTabs[this.activeIndex]?.key || ''
|
|
645
743
|
this.refreshSourceVisibility()
|
|
744
|
+
this.refreshWidgetCounts()
|
|
646
745
|
},
|
|
647
746
|
|
|
648
747
|
mounted() {
|
|
649
|
-
this._onRefresh = () =>
|
|
748
|
+
this._onRefresh = () => {
|
|
749
|
+
this.refreshSourceVisibility()
|
|
750
|
+
this.refreshWidgetCounts()
|
|
751
|
+
}
|
|
650
752
|
subscribe('cn:page:refresh', this._onRefresh)
|
|
651
753
|
subscribe('cn:widget:refresh', this._onRefresh)
|
|
652
754
|
},
|
|
@@ -657,6 +759,67 @@ export default {
|
|
|
657
759
|
},
|
|
658
760
|
|
|
659
761
|
methods: {
|
|
762
|
+
/**
|
|
763
|
+
* The grid a stack lays its widgets out in, as one column span (of 12)
|
|
764
|
+
* per widget in order, or null for the plain vertical stack. A tab says
|
|
765
|
+
* `columns: 4` (every widget spans a quarter of the row) and/or
|
|
766
|
+
* `layout: [{ widgetId, gridWidth }]`, the page grid's width key per
|
|
767
|
+
* widget (of 12; a widget it does not name takes the `columns` share, or
|
|
768
|
+
* the whole row). Widgets wrap onto the next row. Heights follow the
|
|
769
|
+
* content.
|
|
770
|
+
*
|
|
771
|
+
* @param {object|string} tab The `content.tabs[]` entry.
|
|
772
|
+
* @param {Array<object>} widgets The widgets of the stack, in order.
|
|
773
|
+
* @return {number[]|null} The column span of each widget, or null.
|
|
774
|
+
*/
|
|
775
|
+
stackGrid(tab, widgets) {
|
|
776
|
+
if (!tab || typeof tab !== 'object' || widgets.length < 2) {
|
|
777
|
+
return null
|
|
778
|
+
}
|
|
779
|
+
const clamp = (value) => Math.min(12, Math.max(1, Math.floor(Number(value))))
|
|
780
|
+
const columns = Number(tab.columns)
|
|
781
|
+
const share = Number.isFinite(columns) && columns >= 1 ? clamp(12 / Math.min(12, Math.floor(columns))) : 12
|
|
782
|
+
const placed = new Map((Array.isArray(tab.layout) ? tab.layout : [])
|
|
783
|
+
.filter((entry) => entry && typeof entry.widgetId === 'string' && Number.isFinite(Number(entry.gridWidth)))
|
|
784
|
+
.map((entry) => [entry.widgetId, clamp(entry.gridWidth)]))
|
|
785
|
+
if (placed.size === 0 && share === 12) {
|
|
786
|
+
return null
|
|
787
|
+
}
|
|
788
|
+
return widgets.map((widget) => placed.get(widget.id) ?? share)
|
|
789
|
+
},
|
|
790
|
+
|
|
791
|
+
/**
|
|
792
|
+
* The inline column span of one widget of a gridded stack.
|
|
793
|
+
*
|
|
794
|
+
* @param {number[]|null} grid The spans of the stack, or null.
|
|
795
|
+
* @param {number} index The widget's position in the stack.
|
|
796
|
+
* @return {object|undefined} The style, or undefined without a grid.
|
|
797
|
+
*/
|
|
798
|
+
spanStyle(grid, index) {
|
|
799
|
+
return grid ? { gridColumn: `span ${grid[index] || 12}` } : undefined
|
|
800
|
+
},
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* The widget ids a tab names: `widgetIds` (a stack) when it holds at
|
|
804
|
+
* least one id, else `widgetId`, or the bare string.
|
|
805
|
+
*
|
|
806
|
+
* @param {object|string} tab The `content.tabs[]` entry.
|
|
807
|
+
* @return {string[]} The ids, at least one entry (possibly undefined).
|
|
808
|
+
* @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-tab-can-hold-a-stack-of-widgets
|
|
809
|
+
*/
|
|
810
|
+
tabWidgetIds(tab) {
|
|
811
|
+
if (typeof tab === 'string') {
|
|
812
|
+
return [tab]
|
|
813
|
+
}
|
|
814
|
+
if (tab && Array.isArray(tab.widgetIds)) {
|
|
815
|
+
const ids = tab.widgetIds.filter((id) => typeof id === 'string' && id !== '')
|
|
816
|
+
if (ids.length) {
|
|
817
|
+
return ids
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return [tab?.widgetId]
|
|
821
|
+
},
|
|
822
|
+
|
|
660
823
|
/**
|
|
661
824
|
* The label a tab shows: the authored `label`, else (board look) History
|
|
662
825
|
* for the activity widget, else the child widget's title, else its id.
|
|
@@ -733,6 +896,60 @@ export default {
|
|
|
733
896
|
}))
|
|
734
897
|
},
|
|
735
898
|
|
|
899
|
+
/**
|
|
900
|
+
* The list a tab counts (`countFrom`): `"widget"` counts the child
|
|
901
|
+
* widget's own list (its `content.register`, `content.schema` and
|
|
902
|
+
* `content.filter`); an object `{ register, schema, filter? }` names
|
|
903
|
+
* the list itself. Null for a tab that does not ask, or a child with
|
|
904
|
+
* no list.
|
|
905
|
+
*
|
|
906
|
+
* @param {object|string} tab The `content.tabs[]` entry.
|
|
907
|
+
* @return {{register: string, schema: string, filter: object}|null} The list.
|
|
908
|
+
* @spec openspec/changes/screens-tab-counts-parity/specs/tab-counts/spec.md#requirement-a-tab-can-count-its-list
|
|
909
|
+
*/
|
|
910
|
+
countSourceOf(tab) {
|
|
911
|
+
const from = tab && typeof tab === 'object' ? tab.countFrom : null
|
|
912
|
+
let source = null
|
|
913
|
+
if (from === 'widget') {
|
|
914
|
+
// A stack counts its first widget that has a list.
|
|
915
|
+
const lists = this.tabWidgetIds(tab)
|
|
916
|
+
.map((id) => this.availableWidgets.find((w) => w && w.id === id))
|
|
917
|
+
.filter((w) => w && w.content && typeof w.content === 'object' && w.content.register && w.content.schema)
|
|
918
|
+
source = lists.length ? lists[0].content : null
|
|
919
|
+
} else if (from && typeof from === 'object') {
|
|
920
|
+
source = from
|
|
921
|
+
}
|
|
922
|
+
if (!source || typeof source.register !== 'string' || source.register === '' || typeof source.schema !== 'string' || source.schema === '') {
|
|
923
|
+
return null
|
|
924
|
+
}
|
|
925
|
+
const filter = source.filter && typeof source.filter === 'object' && !Array.isArray(source.filter) ? source.filter : {}
|
|
926
|
+
return { register: source.register, schema: source.schema, filter }
|
|
927
|
+
},
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* Count the list behind every tab with `countFrom`: once on mount,
|
|
931
|
+
* when the record changes and after a refresh. A tab keeps its last
|
|
932
|
+
* total while the new one is on its way; a failed count shows none.
|
|
933
|
+
*
|
|
934
|
+
* @return {Promise<void>}
|
|
935
|
+
* @spec openspec/changes/screens-tab-counts-parity/specs/tab-counts/spec.md#requirement-a-tab-can-count-its-list
|
|
936
|
+
*/
|
|
937
|
+
async refreshWidgetCounts() {
|
|
938
|
+
const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : []
|
|
939
|
+
const seq = ++this.countSeq
|
|
940
|
+
const ctx = { objectId: this.objectId, object: this.objectData || undefined }
|
|
941
|
+
await Promise.all(tabs.map(async (tab, index) => {
|
|
942
|
+
const source = this.countSourceOf(tab)
|
|
943
|
+
if (!source) {
|
|
944
|
+
return
|
|
945
|
+
}
|
|
946
|
+
const total = await fetchListTotal(source.register, source.schema, source.filter, ctx).catch(() => null)
|
|
947
|
+
if (seq === this.countSeq) {
|
|
948
|
+
this.widgetCounts = { ...this.widgetCounts, [index]: total }
|
|
949
|
+
}
|
|
950
|
+
}))
|
|
951
|
+
},
|
|
952
|
+
|
|
736
953
|
/** @return {string} The route hash without its `#`, or ''. */
|
|
737
954
|
currentHash() {
|
|
738
955
|
const fromRoute = this.$route && typeof this.$route.hash === 'string' ? this.$route.hash : ''
|
|
@@ -823,6 +1040,36 @@ export default {
|
|
|
823
1040
|
</script>
|
|
824
1041
|
|
|
825
1042
|
<style scoped>
|
|
1043
|
+
/* A stack (`widgetIds`): the panel's widget, then cards 20px apart. */
|
|
1044
|
+
.cn-tabs-widget__stack {
|
|
1045
|
+
display: flex;
|
|
1046
|
+
flex-direction: column;
|
|
1047
|
+
gap: 20px;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/* A gridded stack (`columns` / `layout` on the tab): 12 columns, widgets wrap
|
|
1051
|
+
onto the next row, a row's cards as tall as the tallest. Narrow, it is the
|
|
1052
|
+
plain stack again. */
|
|
1053
|
+
.cn-tabs-widget__stack--grid {
|
|
1054
|
+
display: grid;
|
|
1055
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
1056
|
+
align-items: stretch;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.cn-tabs-widget__stack--grid > * {
|
|
1060
|
+
min-width: 0;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
@media (max-width: 700px) {
|
|
1064
|
+
.cn-tabs-widget__stack--grid {
|
|
1065
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
.cn-tabs-widget__stack--grid > * {
|
|
1069
|
+
grid-column: auto !important;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
826
1073
|
/* The panel is the card; the strip is not inside it. There is no title bar
|
|
827
1074
|
above the tabs either: the open tab names the panel, so a title row would
|
|
828
1075
|
say the same thing twice and cost a row of height on a card that is mostly
|
|
@@ -943,6 +1190,14 @@ export default {
|
|
|
943
1190
|
height: 100%;
|
|
944
1191
|
}
|
|
945
1192
|
|
|
1193
|
+
/* A list widget's footer Add bleeds through its card's 16px content padding
|
|
1194
|
+
(margin 0 -16px -16px). The panel of a tab pads 12px, so on a tab that
|
|
1195
|
+
holds the list directly the footer stuck out 4px on the right and at the
|
|
1196
|
+
bottom and made the panel scroll. It bleeds exactly the panel's padding. */
|
|
1197
|
+
.cn-tabs-widget__tabs :deep(.cn-tabs__content > .cn-tab > .cn-detail-widget-host--bare .cn-object-list-widget__add) {
|
|
1198
|
+
margin: auto -12px -12px;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
946
1201
|
.cn-tabs-widget__title {
|
|
947
1202
|
align-items: center;
|
|
948
1203
|
display: inline-flex;
|