@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,159 @@
|
|
|
1
|
+
import { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue';
|
|
2
|
+
import { objectUrlOf, patchObject } from '../../utils/objectWrite.js';
|
|
3
|
+
import { readPath } from '../../utils/readPath.js';
|
|
4
|
+
import { serverErrorMessage } from '../../utils/serverErrorMessage.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* CnSwitchRowsWidget — the `switch-rows` widget: a card of switches, each with
|
|
8
|
+
* a label and a hint, bound to boolean fields of the CURRENT object. A toggle
|
|
9
|
+
* saves at once with ONE PATCH of that field; a refused PATCH puts the switch
|
|
10
|
+
* back and shows the server's words.
|
|
11
|
+
*
|
|
12
|
+
* @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md
|
|
13
|
+
*/
|
|
14
|
+
var script = {
|
|
15
|
+
name: 'CnSwitchRowsWidget',
|
|
16
|
+
|
|
17
|
+
components: { NcCheckboxRadioSwitch, NcNoteCard },
|
|
18
|
+
|
|
19
|
+
inject: {
|
|
20
|
+
cnTranslate: { default: () => (key) => key },
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
props: {
|
|
24
|
+
/**
|
|
25
|
+
* The widget configuration.
|
|
26
|
+
*
|
|
27
|
+
* - `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").
|
|
28
|
+
* - `readOnly`.
|
|
29
|
+
*
|
|
30
|
+
* @type {object}
|
|
31
|
+
*/
|
|
32
|
+
content: {
|
|
33
|
+
type: Object,
|
|
34
|
+
default: () => ({}),
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
/** The current detail-page object. */
|
|
38
|
+
objectData: {
|
|
39
|
+
type: Object,
|
|
40
|
+
default: null,
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
/** The current object id. */
|
|
44
|
+
objectId: {
|
|
45
|
+
type: [String, Number],
|
|
46
|
+
default: '',
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/** OpenRegister register slug of the surface. */
|
|
50
|
+
register: {
|
|
51
|
+
type: [String, Object],
|
|
52
|
+
default: '',
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
/** OpenRegister schema slug of the surface. */
|
|
56
|
+
schema: {
|
|
57
|
+
type: [String, Object],
|
|
58
|
+
default: '',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
emits: ['saved'],
|
|
63
|
+
|
|
64
|
+
data() {
|
|
65
|
+
return {
|
|
66
|
+
/** The switch states as last saved (by key, as the switch shows them). */
|
|
67
|
+
saved: {},
|
|
68
|
+
values: {},
|
|
69
|
+
busy: '',
|
|
70
|
+
notice: '',
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
computed: {
|
|
75
|
+
rows() {
|
|
76
|
+
const list = Array.isArray(this.content.rows) ? this.content.rows : [];
|
|
77
|
+
return list
|
|
78
|
+
.filter((row) => row && row.key)
|
|
79
|
+
.map((row) => ({ ...row, label: this.tr(row.label || row.key), hint: this.tr(row.hint || '') }))
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
readOnly() {
|
|
83
|
+
return this.content.readOnly === true
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
objectUrl() {
|
|
87
|
+
return objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
watch: {
|
|
92
|
+
objectData() {
|
|
93
|
+
this.adopt();
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
created() {
|
|
98
|
+
this.adopt();
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
methods: {
|
|
102
|
+
tr(text) {
|
|
103
|
+
if (typeof text !== 'string' || text === '') {
|
|
104
|
+
return ''
|
|
105
|
+
}
|
|
106
|
+
return typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/** Read every switch off the object. */
|
|
110
|
+
adopt() {
|
|
111
|
+
const values = {};
|
|
112
|
+
for (const row of this.rows) {
|
|
113
|
+
const stored = readPath(this.objectData || {}, row.key) === true;
|
|
114
|
+
values[row.key] = row.invert ? !stored : stored;
|
|
115
|
+
}
|
|
116
|
+
this.saved = values;
|
|
117
|
+
this.values = { ...values };
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Flip one switch and save that one field.
|
|
122
|
+
*
|
|
123
|
+
* @param {object} row The row.
|
|
124
|
+
* @param {boolean} on The new switch state.
|
|
125
|
+
* @return {Promise<void>}
|
|
126
|
+
* @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md#requirement-a-toggle-saves-that-one-field
|
|
127
|
+
*/
|
|
128
|
+
async toggle(row, on) {
|
|
129
|
+
if (!this.objectUrl) {
|
|
130
|
+
this.notice = this.tr('This switch cannot be saved here.');
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
this.notice = '';
|
|
134
|
+
this.busy = row.key;
|
|
135
|
+
this.values = { ...this.values, [row.key]: on };
|
|
136
|
+
const stored = row.invert ? !on : on;
|
|
137
|
+
try {
|
|
138
|
+
const data = await patchObject(this.objectUrl, { [row.key]: stored });
|
|
139
|
+
const written = data[row.key] !== undefined ? data[row.key] === true : stored;
|
|
140
|
+
const shown = row.invert ? !written : written;
|
|
141
|
+
this.saved = { ...this.saved, [row.key]: shown };
|
|
142
|
+
this.values = { ...this.values, [row.key]: shown };
|
|
143
|
+
/**
|
|
144
|
+
* @event saved A switch was written.
|
|
145
|
+
* @type {{field: string, value: boolean}}
|
|
146
|
+
*/
|
|
147
|
+
this.$emit('saved', { field: row.key, value: written });
|
|
148
|
+
} catch (e) {
|
|
149
|
+
this.values = { ...this.values, [row.key]: this.saved[row.key] };
|
|
150
|
+
this.notice = serverErrorMessage(e);
|
|
151
|
+
} finally {
|
|
152
|
+
this.busy = '';
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export { script as default };
|
|
159
|
+
//# sourceMappingURL=CnSwitchRowsWidget.vue2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnSwitchRowsWidget.vue2.js","sources":["../../../../src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-switch-rows\" data-testid=\"cn-switch-rows\">\n\t\t<ul class=\"cn-switch-rows__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-switch-rows__row\"\n\t\t\t\t:data-testid=\"`cn-switch-rows-row-${row.key}`\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t:modelValue=\"values[row.key] === true\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t:disabled=\"readOnly || busy === row.key\"\n\t\t\t\t\t@update:modelValue=\"toggle(row, $event)\">\n\t\t\t\t\t<span class=\"cn-switch-rows__label\">{{ row.label }}</span>\n\t\t\t\t\t<span v-if=\"row.hint\" class=\"cn-switch-rows__hint\">{{ row.hint }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</li>\n\t\t</ul>\n\t\t<NcNoteCard v-if=\"notice\" type=\"error\" data-testid=\"cn-switch-rows-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport { objectUrlOf, patchObject } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnSwitchRowsWidget — the `switch-rows` widget: a card of switches, each with\n * a label and a hint, bound to boolean fields of the CURRENT object. A toggle\n * saves at once with ONE PATCH of that field; a refused PATCH puts the switch\n * back and shows the server's words.\n *\n * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md\n */\nexport default {\n\tname: 'CnSwitchRowsWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `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\").\n\t\t * - `readOnly`.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The switch states as last saved (by key, as the switch shows them). */\n\t\t\tsaved: {},\n\t\t\tvalues: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\trows() {\n\t\t\tconst list = Array.isArray(this.content.rows) ? this.content.rows : []\n\t\t\treturn list\n\t\t\t\t.filter((row) => row && row.key)\n\t\t\t\t.map((row) => ({ ...row, label: this.tr(row.label || row.key), hint: this.tr(row.hint || '') }))\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.adopt()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.adopt()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/** Read every switch off the object. */\n\t\tadopt() {\n\t\t\tconst values = {}\n\t\t\tfor (const row of this.rows) {\n\t\t\t\tconst stored = readPath(this.objectData || {}, row.key) === true\n\t\t\t\tvalues[row.key] = row.invert ? !stored : stored\n\t\t\t}\n\t\t\tthis.saved = values\n\t\t\tthis.values = { ...values }\n\t\t},\n\n\t\t/**\n\t\t * Flip one switch and save that one field.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} on The new switch state.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md#requirement-a-toggle-saves-that-one-field\n\t\t */\n\t\tasync toggle(row, on) {\n\t\t\tif (!this.objectUrl) {\n\t\t\t\tthis.notice = this.tr('This switch cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.notice = ''\n\t\t\tthis.busy = row.key\n\t\t\tthis.values = { ...this.values, [row.key]: on }\n\t\t\tconst stored = row.invert ? !on : on\n\t\t\ttry {\n\t\t\t\tconst data = await patchObject(this.objectUrl, { [row.key]: stored })\n\t\t\t\tconst written = data[row.key] !== undefined ? data[row.key] === true : stored\n\t\t\t\tconst shown = row.invert ? !written : written\n\t\t\t\tthis.saved = { ...this.saved, [row.key]: shown }\n\t\t\t\tthis.values = { ...this.values, [row.key]: shown }\n\t\t\t\t/**\n\t\t\t\t * @event saved A switch was written.\n\t\t\t\t * @type {{field: string, value: boolean}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field: row.key, value: written })\n\t\t\t} catch (e) {\n\t\t\t\tthis.values = { ...this.values, [row.key]: this.saved[row.key] }\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-switch-rows {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-switch-rows__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-switch-rows__row {\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-switch-rows__row:first-child {\n\tborder-top: none;\n\tpadding-top: 0;\n}\n\n.cn-switch-rows__label {\n\tdisplay: block;\n\tfont-weight: 600;\n}\n\n.cn-switch-rows__hint {\n\tdisplay: block;\n\tfont-size: 12px;\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { resolveComponent, openBlock, createElementBlock, createElementVNode, Fragment, renderList, createVNode, withCtx, toDisplayString, createCommentVNode, createBlock, createTextVNode } from 'vue';
|
|
2
|
+
|
|
3
|
+
const _hoisted_1 = {
|
|
4
|
+
class: "cn-switch-rows",
|
|
5
|
+
"data-testid": "cn-switch-rows"
|
|
6
|
+
};
|
|
7
|
+
const _hoisted_2 = { class: "cn-switch-rows__list" };
|
|
8
|
+
const _hoisted_3 = ["data-testid"];
|
|
9
|
+
const _hoisted_4 = { class: "cn-switch-rows__label" };
|
|
10
|
+
const _hoisted_5 = {
|
|
11
|
+
key: 0,
|
|
12
|
+
class: "cn-switch-rows__hint"
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
16
|
+
const _component_NcCheckboxRadioSwitch = resolveComponent("NcCheckboxRadioSwitch");
|
|
17
|
+
const _component_NcNoteCard = resolveComponent("NcNoteCard");
|
|
18
|
+
|
|
19
|
+
return (openBlock(), createElementBlock("div", _hoisted_1, [
|
|
20
|
+
createElementVNode("ul", _hoisted_2, [
|
|
21
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($options.rows, (row) => {
|
|
22
|
+
return (openBlock(), createElementBlock("li", {
|
|
23
|
+
key: row.key,
|
|
24
|
+
class: "cn-switch-rows__row",
|
|
25
|
+
"data-testid": `cn-switch-rows-row-${row.key}`
|
|
26
|
+
}, [
|
|
27
|
+
createVNode(_component_NcCheckboxRadioSwitch, {
|
|
28
|
+
modelValue: $data.values[row.key] === true,
|
|
29
|
+
type: "switch",
|
|
30
|
+
disabled: $options.readOnly || $data.busy === row.key,
|
|
31
|
+
"onUpdate:modelValue": $event => ($options.toggle(row, $event))
|
|
32
|
+
}, {
|
|
33
|
+
default: withCtx(() => [
|
|
34
|
+
createElementVNode("span", _hoisted_4, toDisplayString(row.label), 1 /* TEXT */),
|
|
35
|
+
(row.hint)
|
|
36
|
+
? (openBlock(), createElementBlock("span", _hoisted_5, toDisplayString(row.hint), 1 /* TEXT */))
|
|
37
|
+
: createCommentVNode("v-if", true)
|
|
38
|
+
]),
|
|
39
|
+
_: 2 /* DYNAMIC */
|
|
40
|
+
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["modelValue", "disabled", "onUpdate:modelValue"])
|
|
41
|
+
], 8 /* PROPS */, _hoisted_3))
|
|
42
|
+
}), 128 /* KEYED_FRAGMENT */))
|
|
43
|
+
]),
|
|
44
|
+
($data.notice)
|
|
45
|
+
? (openBlock(), createBlock(_component_NcNoteCard, {
|
|
46
|
+
key: 0,
|
|
47
|
+
type: "error",
|
|
48
|
+
"data-testid": "cn-switch-rows-notice"
|
|
49
|
+
}, {
|
|
50
|
+
default: withCtx(() => [
|
|
51
|
+
createTextVNode(toDisplayString($data.notice), 1 /* TEXT */)
|
|
52
|
+
]),
|
|
53
|
+
_: 1 /* STABLE */
|
|
54
|
+
}))
|
|
55
|
+
: createCommentVNode("v-if", true)
|
|
56
|
+
]))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { render };
|
|
60
|
+
//# sourceMappingURL=CnSwitchRowsWidget.vue3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CnSwitchRowsWidget.vue3.js","sources":["../../../../src/components/CnSwitchRowsWidget/CnSwitchRowsWidget.vue?vue&type=template&id=9dd5b4e2&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-switch-rows\" data-testid=\"cn-switch-rows\">\n\t\t<ul class=\"cn-switch-rows__list\">\n\t\t\t<li\n\t\t\t\tv-for=\"row in rows\"\n\t\t\t\t:key=\"row.key\"\n\t\t\t\tclass=\"cn-switch-rows__row\"\n\t\t\t\t:data-testid=\"`cn-switch-rows-row-${row.key}`\">\n\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t:modelValue=\"values[row.key] === true\"\n\t\t\t\t\ttype=\"switch\"\n\t\t\t\t\t:disabled=\"readOnly || busy === row.key\"\n\t\t\t\t\t@update:modelValue=\"toggle(row, $event)\">\n\t\t\t\t\t<span class=\"cn-switch-rows__label\">{{ row.label }}</span>\n\t\t\t\t\t<span v-if=\"row.hint\" class=\"cn-switch-rows__hint\">{{ row.hint }}</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</li>\n\t\t</ul>\n\t\t<NcNoteCard v-if=\"notice\" type=\"error\" data-testid=\"cn-switch-rows-notice\">\n\t\t\t{{ notice }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n\n<script>\nimport { NcCheckboxRadioSwitch, NcNoteCard } from '@nextcloud/vue'\nimport { objectUrlOf, patchObject } from '../../utils/objectWrite.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\n/**\n * CnSwitchRowsWidget — the `switch-rows` widget: a card of switches, each with\n * a label and a hint, bound to boolean fields of the CURRENT object. A toggle\n * saves at once with ONE PATCH of that field; a refused PATCH puts the switch\n * back and shows the server's words.\n *\n * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md\n */\nexport default {\n\tname: 'CnSwitchRowsWidget',\n\n\tcomponents: { NcCheckboxRadioSwitch, NcNoteCard },\n\n\tinject: {\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget configuration.\n\t\t *\n\t\t * - `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\").\n\t\t * - `readOnly`.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The current detail-page object. */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** The current object id. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister register slug of the surface. */\n\t\tregister: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** OpenRegister schema slug of the surface. */\n\t\tschema: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['saved'],\n\n\tdata() {\n\t\treturn {\n\t\t\t/** The switch states as last saved (by key, as the switch shows them). */\n\t\t\tsaved: {},\n\t\t\tvalues: {},\n\t\t\tbusy: '',\n\t\t\tnotice: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\trows() {\n\t\t\tconst list = Array.isArray(this.content.rows) ? this.content.rows : []\n\t\t\treturn list\n\t\t\t\t.filter((row) => row && row.key)\n\t\t\t\t.map((row) => ({ ...row, label: this.tr(row.label || row.key), hint: this.tr(row.hint || '') }))\n\t\t},\n\n\t\treadOnly() {\n\t\t\treturn this.content.readOnly === true\n\t\t},\n\n\t\tobjectUrl() {\n\t\t\treturn objectUrlOf(this.register, this.schema, this.objectId || (this.objectData && this.objectData.id))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectData() {\n\t\t\tthis.adopt()\n\t\t},\n\t},\n\n\tcreated() {\n\t\tthis.adopt()\n\t},\n\n\tmethods: {\n\t\ttr(text) {\n\t\t\tif (typeof text !== 'string' || text === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn typeof this.cnTranslate === 'function' ? this.cnTranslate(text) : text\n\t\t},\n\n\t\t/** Read every switch off the object. */\n\t\tadopt() {\n\t\t\tconst values = {}\n\t\t\tfor (const row of this.rows) {\n\t\t\t\tconst stored = readPath(this.objectData || {}, row.key) === true\n\t\t\t\tvalues[row.key] = row.invert ? !stored : stored\n\t\t\t}\n\t\t\tthis.saved = values\n\t\t\tthis.values = { ...values }\n\t\t},\n\n\t\t/**\n\t\t * Flip one switch and save that one field.\n\t\t *\n\t\t * @param {object} row The row.\n\t\t * @param {boolean} on The new switch state.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/abstract-switch-rows/specs/switch-rows/spec.md#requirement-a-toggle-saves-that-one-field\n\t\t */\n\t\tasync toggle(row, on) {\n\t\t\tif (!this.objectUrl) {\n\t\t\t\tthis.notice = this.tr('This switch cannot be saved here.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.notice = ''\n\t\t\tthis.busy = row.key\n\t\t\tthis.values = { ...this.values, [row.key]: on }\n\t\t\tconst stored = row.invert ? !on : on\n\t\t\ttry {\n\t\t\t\tconst data = await patchObject(this.objectUrl, { [row.key]: stored })\n\t\t\t\tconst written = data[row.key] !== undefined ? data[row.key] === true : stored\n\t\t\t\tconst shown = row.invert ? !written : written\n\t\t\t\tthis.saved = { ...this.saved, [row.key]: shown }\n\t\t\t\tthis.values = { ...this.values, [row.key]: shown }\n\t\t\t\t/**\n\t\t\t\t * @event saved A switch was written.\n\t\t\t\t * @type {{field: string, value: boolean}}\n\t\t\t\t */\n\t\t\t\tthis.$emit('saved', { field: row.key, value: written })\n\t\t\t} catch (e) {\n\t\t\t\tthis.values = { ...this.values, [row.key]: this.saved[row.key] }\n\t\t\t\tthis.notice = serverErrorMessage(e)\n\t\t\t} finally {\n\t\t\t\tthis.busy = ''\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-switch-rows {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tmin-width: 0;\n}\n\n.cn-switch-rows__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n}\n\n.cn-switch-rows__row {\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--cn-board-hairline, var(--color-border));\n}\n\n.cn-switch-rows__row:first-child {\n\tborder-top: none;\n\tpadding-top: 0;\n}\n\n.cn-switch-rows__label {\n\tdisplay: block;\n\tfont-weight: 600;\n}\n\n.cn-switch-rows__hint {\n\tdisplay: block;\n\tfont-size: 12px;\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n"],"names":["_createElementBlock","_Fragment","_renderList","_createElementVNode","_toDisplayString"],"mappings":";;;AAWM,EAAA,KAAK,EAAC,gBAAgB;AAAC,EAAA,aAAC,EAAA,gBAAA;;AACxB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,sBAAsB,GAAA;;AAWvB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,uBAAwB,GAAA;;;AAC3B,EAAA,KAAA,EAAA,sBAAA;;;;;;;;;wBAXVA,kBAaE,CAAAC,QAAA,EAAA,IAAA,EAAAC,UAAA,CAZY,QAAI,CAAA,IAAA,EAAA,CAAX,GAAG,KAAA;6BADVF,kBAaE,CAAA,IAAA,EAAA;UAXD,GAAG,EAAE,GAAG,CAAC,GAAG;AACZ,UAAA,KAAI,EAAC,qBAAqB;UAC1B,aAAW,EAAA,CAAA,mBAAA,EAAwB,GAAG,CAAC,GAAC,CAAA,CAAA;;qBAQ/B,CAAA,gCAAA,EAAA;AANR,YAAA,UAAU,EAAE,KAAA,CAAA,MAAM,CAAC,GAAG,CAAC,GAAG,CAAA,KAAA,IAAA;AAC3B,YAAA,IAAI,EAAC,QAAQ;AACZ,YAAA,QAAC,EAAA,QAAA,CAAA,QAAA,IAAA,UAAA,KAAA,GAAA,CAAA,GAAA;AACD,YAAA,qBAAA,EAAA,MAAA,KAAA,QAAA,CAAA,MAAA,CAAA,GAAA,EAAA,MAAA,CAAA,CAAA;;6BACD,MAA0D;AAA1D,cAAAG,kBAAA,CAA0D,MAA1D,EAAA,UAA0D,EAAnBC,eAAA,CAAA,GAAG,CAAC,KAAK,CAAA,EAAA,CAAA,YAAA;AACvC,cAAA,CAAA,GAAA,CAAA,IAAA;mDAAA,kBAAA,EAAAA,eAAA,CAAA,GAAA,CAAA,IAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import __sfc_main from './CnSwitchRowsWidget.vue.js';
|
|
2
|
+
import { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SPDX-FileCopyrightText: 2026 Conduction B.V.
|
|
6
|
+
* SPDX-License-Identifier: EUPL-1.2
|
|
7
|
+
*
|
|
8
|
+
* CnSwitchRowsWidget — self-registers the `switch-rows` widget type (a card of
|
|
9
|
+
* switches, each with a label and a hint, bound to boolean fields of the
|
|
10
|
+
* current object and saved on toggle) into the shared dashboardWidgetRegistry.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
registerDashboardWidget('switch-rows', {
|
|
15
|
+
renderer: __sfc_main,
|
|
16
|
+
form: null,
|
|
17
|
+
defaultContent: {
|
|
18
|
+
rows: [],
|
|
19
|
+
},
|
|
20
|
+
displayName: 'Switch rows',
|
|
21
|
+
icon: 'ToggleSwitch',
|
|
22
|
+
surfaces: ['detail-page'],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export { __sfc_main as CnSwitchRowsWidget, __sfc_main as default };
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/CnSwitchRowsWidget/index.js"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Conduction B.V.\n * SPDX-License-Identifier: EUPL-1.2\n *\n * CnSwitchRowsWidget — self-registers the `switch-rows` widget type (a card of\n * switches, each with a label and a hint, bound to boolean fields of the\n * current object and saved on toggle) into the shared dashboardWidgetRegistry.\n */\n\nimport CnSwitchRowsWidget from './CnSwitchRowsWidget.vue'\nimport { registerDashboardWidget } from '../CnWidgetGrid/dashboardWidgetRegistry.js'\n\nregisterDashboardWidget('switch-rows', {\n\trenderer: CnSwitchRowsWidget,\n\tform: null,\n\tdefaultContent: {\n\t\trows: [],\n\t},\n\tdisplayName: 'Switch rows',\n\ticon: 'ToggleSwitch',\n\tsurfaces: ['detail-page'],\n})\n\nexport { CnSwitchRowsWidget }\nexport default CnSwitchRowsWidget\n"],"names":["CnSwitchRowsWidget"],"mappings":";;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA,uBAAuB,CAAC,aAAa,EAAE;AACvC,CAAC,QAAQ,EAAEA,UAAkB;AAC7B,CAAC,IAAI,EAAE,IAAI;AACX,CAAC,cAAc,EAAE;AACjB,EAAE,IAAI,EAAE,EAAE;AACV,EAAE;AACF,CAAC,WAAW,EAAE,aAAa;AAC3B,CAAC,IAAI,EAAE,cAAc;AACrB,CAAC,QAAQ,EAAE,CAAC,aAAa,CAAC;AAC1B,CAAC;;;;"}
|
|
@@ -8,6 +8,7 @@ import __sfc_main$3 from '../CnTabs/CnTab.vue.js';
|
|
|
8
8
|
import __sfc_main$4 from '../CnTabs/CnTabs.vue.js';
|
|
9
9
|
import { normalizeLook } from '../../composables/useLook.js';
|
|
10
10
|
import { resolveTabCount } from '../../utils/detailActionModel.js';
|
|
11
|
+
import { fetchListTotal } from '../../utils/fetchFilterCounts.js';
|
|
11
12
|
import { isActivityWidget } from '../../utils/headerMeta.js';
|
|
12
13
|
import { PANEL_ACTION_SINK } from '../../utils/panelActions.js';
|
|
13
14
|
import { isLocallyDecidableVisibleWhen, evaluateVisibleWhenLocal, evaluateVisibleWhen } from '../../utils/visibleWhen.js';
|
|
@@ -162,15 +163,24 @@ var script = {
|
|
|
162
163
|
* `tabs[]` entries are `{ widgetId, label?, icon?, count?, countField?, overflow? }`.
|
|
163
164
|
* `label` and `icon` fall back to the referenced widget's own title and
|
|
164
165
|
* icon. `count` is a number shown after the label; `countField` reads
|
|
165
|
-
* it off the record instead (a list counts its items). `
|
|
166
|
+
* it off the record instead (a list counts its items). `countFrom`
|
|
167
|
+
* counts a list on the server: `"widget"` counts the child widget's
|
|
168
|
+
* own list (`content.register`, `schema`, `filter`, tokens such as
|
|
169
|
+
* `@objectId` resolved), an object `{ register, schema, filter? }`
|
|
170
|
+
* names the list; `count` and `countField` win over it. `overflow: true`
|
|
166
171
|
* lists the tab under "More".
|
|
167
172
|
*
|
|
173
|
+
* A tab with `widgetIds` can lay them out in a grid instead of one under
|
|
174
|
+
* the other: `columns: 4` gives each a quarter of the row, and
|
|
175
|
+
* `layout: [{ widgetId, gridWidth }]` sets a width (of 12) per widget, as
|
|
176
|
+
* the page grid does. Widgets wrap onto the next row.
|
|
177
|
+
*
|
|
168
178
|
* `maxVisibleTabs` caps the strip: later tabs go under "More".
|
|
169
179
|
* `hideEmpty: true` moves a tab whose count is 0 there too.
|
|
170
180
|
* `moreLabel` names that menu. `variant: "segmented"` draws the strip
|
|
171
181
|
* as a pill switch (CnTabs' segmented variant); `line` is the default.
|
|
172
182
|
*
|
|
173
|
-
* @type {{ tabs?: Array<{widgetId
|
|
183
|
+
* @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') }}
|
|
174
184
|
*/
|
|
175
185
|
content: {
|
|
176
186
|
type: Object,
|
|
@@ -290,6 +300,9 @@ var script = {
|
|
|
290
300
|
sourceVisibility: {},
|
|
291
301
|
// Bumped per evaluation round, so a slow answer from an earlier round is dropped.
|
|
292
302
|
visibilitySeq: 0,
|
|
303
|
+
// Totals counted for tabs with `countFrom`, by position in `content.tabs`.
|
|
304
|
+
widgetCounts: {},
|
|
305
|
+
countSeq: 0,
|
|
293
306
|
// Tab id named by the route hash that has not appeared yet (still pending).
|
|
294
307
|
hashTargetId: '',
|
|
295
308
|
// Items published by the panels, keyed by widget id. Keyed rather
|
|
@@ -332,7 +345,7 @@ var script = {
|
|
|
332
345
|
// whatever its place in the manifest. `index` stays the position in
|
|
333
346
|
// `content.tabs`, which the source-mode conditions are keyed on.
|
|
334
347
|
const isActivityTab = (tab) => {
|
|
335
|
-
const id =
|
|
348
|
+
const id = this.tabWidgetIds(tab)[0];
|
|
336
349
|
return isActivityWidget(this.availableWidgets.find((w) => w && w.id === id))
|
|
337
350
|
};
|
|
338
351
|
const ordered = authored.map((tab, index) => ({ tab, index }));
|
|
@@ -354,9 +367,19 @@ var script = {
|
|
|
354
367
|
if (visibility === 'hidden') {
|
|
355
368
|
return
|
|
356
369
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
370
|
+
// A stack (`widgetIds`) resolves every id; one that names no
|
|
371
|
+
// widget is skipped. The first that resolves is the panel's.
|
|
372
|
+
const ids = this.tabWidgetIds(tab);
|
|
373
|
+
const widgets = ids.length > 1
|
|
374
|
+
? ids.map((id) => this.availableWidgets.find((w) => w && w.id === id) || null).filter(Boolean)
|
|
375
|
+
: [];
|
|
376
|
+
const widget = ids.length > 1
|
|
377
|
+
? (widgets[0] || null)
|
|
378
|
+
: (this.availableWidgets.find((w) => w && w.id === ids[0]) || null);
|
|
379
|
+
const widgetId = widget ? widget.id : ids[0];
|
|
380
|
+
const declared = resolveTabCount(typeof tab === 'object' ? tab : null, this.objectData);
|
|
381
|
+
const counted = this.widgetCounts[index];
|
|
382
|
+
const count = declared === null && typeof counted === 'number' ? counted : declared;
|
|
360
383
|
// The board strip has no "More": every tab is in the strip.
|
|
361
384
|
let overflow = !this.isBoard && ((tab && tab.overflow === true) || (hideEmpty && count === 0));
|
|
362
385
|
if (!overflow && !this.isBoard) {
|
|
@@ -373,6 +396,8 @@ var script = {
|
|
|
373
396
|
label: this.tabLabel(tab, widget, widgetId),
|
|
374
397
|
icon: (tab && tab.icon) || widget?.icon || '',
|
|
375
398
|
widget,
|
|
399
|
+
stack: widgets.slice(1),
|
|
400
|
+
grid: this.stackGrid(tab, widgets),
|
|
376
401
|
count,
|
|
377
402
|
overflow,
|
|
378
403
|
pending: visibility === 'pending',
|
|
@@ -391,6 +416,17 @@ var script = {
|
|
|
391
416
|
return translate('nextcloud-vue', 'Loading …')
|
|
392
417
|
},
|
|
393
418
|
|
|
419
|
+
/**
|
|
420
|
+
* The lists the tabs count (`countFrom`), serialised, to count again
|
|
421
|
+
* when they change.
|
|
422
|
+
*
|
|
423
|
+
* @return {string} The key.
|
|
424
|
+
*/
|
|
425
|
+
countSourcesKey() {
|
|
426
|
+
const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : [];
|
|
427
|
+
return JSON.stringify(tabs.map((tab) => this.countSourceOf(tab)))
|
|
428
|
+
},
|
|
429
|
+
|
|
394
430
|
/** @return {string} The source-mode conditions, serialised, to re-evaluate when they change. */
|
|
395
431
|
sourceConditionsKey() {
|
|
396
432
|
const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : [];
|
|
@@ -503,6 +539,12 @@ var script = {
|
|
|
503
539
|
objectId() {
|
|
504
540
|
this.sourceVisibility = {};
|
|
505
541
|
this.refreshSourceVisibility();
|
|
542
|
+
this.widgetCounts = {};
|
|
543
|
+
this.refreshWidgetCounts();
|
|
544
|
+
},
|
|
545
|
+
|
|
546
|
+
countSourcesKey() {
|
|
547
|
+
this.refreshWidgetCounts();
|
|
506
548
|
},
|
|
507
549
|
|
|
508
550
|
sourceConditionsKey() {
|
|
@@ -537,10 +579,14 @@ var script = {
|
|
|
537
579
|
}
|
|
538
580
|
this.activeKey = this.resolvedTabs[this.activeIndex]?.key || '';
|
|
539
581
|
this.refreshSourceVisibility();
|
|
582
|
+
this.refreshWidgetCounts();
|
|
540
583
|
},
|
|
541
584
|
|
|
542
585
|
mounted() {
|
|
543
|
-
this._onRefresh = () =>
|
|
586
|
+
this._onRefresh = () => {
|
|
587
|
+
this.refreshSourceVisibility();
|
|
588
|
+
this.refreshWidgetCounts();
|
|
589
|
+
};
|
|
544
590
|
subscribe('cn:page:refresh', this._onRefresh);
|
|
545
591
|
subscribe('cn:widget:refresh', this._onRefresh);
|
|
546
592
|
},
|
|
@@ -551,6 +597,67 @@ var script = {
|
|
|
551
597
|
},
|
|
552
598
|
|
|
553
599
|
methods: {
|
|
600
|
+
/**
|
|
601
|
+
* The grid a stack lays its widgets out in, as one column span (of 12)
|
|
602
|
+
* per widget in order, or null for the plain vertical stack. A tab says
|
|
603
|
+
* `columns: 4` (every widget spans a quarter of the row) and/or
|
|
604
|
+
* `layout: [{ widgetId, gridWidth }]`, the page grid's width key per
|
|
605
|
+
* widget (of 12; a widget it does not name takes the `columns` share, or
|
|
606
|
+
* the whole row). Widgets wrap onto the next row. Heights follow the
|
|
607
|
+
* content.
|
|
608
|
+
*
|
|
609
|
+
* @param {object|string} tab The `content.tabs[]` entry.
|
|
610
|
+
* @param {Array<object>} widgets The widgets of the stack, in order.
|
|
611
|
+
* @return {number[]|null} The column span of each widget, or null.
|
|
612
|
+
*/
|
|
613
|
+
stackGrid(tab, widgets) {
|
|
614
|
+
if (!tab || typeof tab !== 'object' || widgets.length < 2) {
|
|
615
|
+
return null
|
|
616
|
+
}
|
|
617
|
+
const clamp = (value) => Math.min(12, Math.max(1, Math.floor(Number(value))));
|
|
618
|
+
const columns = Number(tab.columns);
|
|
619
|
+
const share = Number.isFinite(columns) && columns >= 1 ? clamp(12 / Math.min(12, Math.floor(columns))) : 12;
|
|
620
|
+
const placed = new Map((Array.isArray(tab.layout) ? tab.layout : [])
|
|
621
|
+
.filter((entry) => entry && typeof entry.widgetId === 'string' && Number.isFinite(Number(entry.gridWidth)))
|
|
622
|
+
.map((entry) => [entry.widgetId, clamp(entry.gridWidth)]));
|
|
623
|
+
if (placed.size === 0 && share === 12) {
|
|
624
|
+
return null
|
|
625
|
+
}
|
|
626
|
+
return widgets.map((widget) => placed.get(widget.id) ?? share)
|
|
627
|
+
},
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* The inline column span of one widget of a gridded stack.
|
|
631
|
+
*
|
|
632
|
+
* @param {number[]|null} grid The spans of the stack, or null.
|
|
633
|
+
* @param {number} index The widget's position in the stack.
|
|
634
|
+
* @return {object|undefined} The style, or undefined without a grid.
|
|
635
|
+
*/
|
|
636
|
+
spanStyle(grid, index) {
|
|
637
|
+
return grid ? { gridColumn: `span ${grid[index] || 12}` } : undefined
|
|
638
|
+
},
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* The widget ids a tab names: `widgetIds` (a stack) when it holds at
|
|
642
|
+
* least one id, else `widgetId`, or the bare string.
|
|
643
|
+
*
|
|
644
|
+
* @param {object|string} tab The `content.tabs[]` entry.
|
|
645
|
+
* @return {string[]} The ids, at least one entry (possibly undefined).
|
|
646
|
+
* @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-tab-can-hold-a-stack-of-widgets
|
|
647
|
+
*/
|
|
648
|
+
tabWidgetIds(tab) {
|
|
649
|
+
if (typeof tab === 'string') {
|
|
650
|
+
return [tab]
|
|
651
|
+
}
|
|
652
|
+
if (tab && Array.isArray(tab.widgetIds)) {
|
|
653
|
+
const ids = tab.widgetIds.filter((id) => typeof id === 'string' && id !== '');
|
|
654
|
+
if (ids.length) {
|
|
655
|
+
return ids
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return [tab?.widgetId]
|
|
659
|
+
},
|
|
660
|
+
|
|
554
661
|
/**
|
|
555
662
|
* The label a tab shows: the authored `label`, else (board look) History
|
|
556
663
|
* for the activity widget, else the child widget's title, else its id.
|
|
@@ -627,6 +734,60 @@ var script = {
|
|
|
627
734
|
}));
|
|
628
735
|
},
|
|
629
736
|
|
|
737
|
+
/**
|
|
738
|
+
* The list a tab counts (`countFrom`): `"widget"` counts the child
|
|
739
|
+
* widget's own list (its `content.register`, `content.schema` and
|
|
740
|
+
* `content.filter`); an object `{ register, schema, filter? }` names
|
|
741
|
+
* the list itself. Null for a tab that does not ask, or a child with
|
|
742
|
+
* no list.
|
|
743
|
+
*
|
|
744
|
+
* @param {object|string} tab The `content.tabs[]` entry.
|
|
745
|
+
* @return {{register: string, schema: string, filter: object}|null} The list.
|
|
746
|
+
* @spec openspec/changes/screens-tab-counts-parity/specs/tab-counts/spec.md#requirement-a-tab-can-count-its-list
|
|
747
|
+
*/
|
|
748
|
+
countSourceOf(tab) {
|
|
749
|
+
const from = tab && typeof tab === 'object' ? tab.countFrom : null;
|
|
750
|
+
let source = null;
|
|
751
|
+
if (from === 'widget') {
|
|
752
|
+
// A stack counts its first widget that has a list.
|
|
753
|
+
const lists = this.tabWidgetIds(tab)
|
|
754
|
+
.map((id) => this.availableWidgets.find((w) => w && w.id === id))
|
|
755
|
+
.filter((w) => w && w.content && typeof w.content === 'object' && w.content.register && w.content.schema);
|
|
756
|
+
source = lists.length ? lists[0].content : null;
|
|
757
|
+
} else if (from && typeof from === 'object') {
|
|
758
|
+
source = from;
|
|
759
|
+
}
|
|
760
|
+
if (!source || typeof source.register !== 'string' || source.register === '' || typeof source.schema !== 'string' || source.schema === '') {
|
|
761
|
+
return null
|
|
762
|
+
}
|
|
763
|
+
const filter = source.filter && typeof source.filter === 'object' && !Array.isArray(source.filter) ? source.filter : {};
|
|
764
|
+
return { register: source.register, schema: source.schema, filter }
|
|
765
|
+
},
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Count the list behind every tab with `countFrom`: once on mount,
|
|
769
|
+
* when the record changes and after a refresh. A tab keeps its last
|
|
770
|
+
* total while the new one is on its way; a failed count shows none.
|
|
771
|
+
*
|
|
772
|
+
* @return {Promise<void>}
|
|
773
|
+
* @spec openspec/changes/screens-tab-counts-parity/specs/tab-counts/spec.md#requirement-a-tab-can-count-its-list
|
|
774
|
+
*/
|
|
775
|
+
async refreshWidgetCounts() {
|
|
776
|
+
const tabs = Array.isArray(this.content?.tabs) ? this.content.tabs : [];
|
|
777
|
+
const seq = ++this.countSeq;
|
|
778
|
+
const ctx = { objectId: this.objectId, object: this.objectData || undefined };
|
|
779
|
+
await Promise.all(tabs.map(async (tab, index) => {
|
|
780
|
+
const source = this.countSourceOf(tab);
|
|
781
|
+
if (!source) {
|
|
782
|
+
return
|
|
783
|
+
}
|
|
784
|
+
const total = await fetchListTotal(source.register, source.schema, source.filter, ctx).catch(() => null);
|
|
785
|
+
if (seq === this.countSeq) {
|
|
786
|
+
this.widgetCounts = { ...this.widgetCounts, [index]: total };
|
|
787
|
+
}
|
|
788
|
+
}));
|
|
789
|
+
},
|
|
790
|
+
|
|
630
791
|
/** @return {string} The route hash without its `#`, or ''. */
|
|
631
792
|
currentHash() {
|
|
632
793
|
const fromRoute = this.$route && typeof this.$route.hash === 'string' ? this.$route.hash : '';
|