@conduction/nextcloud-vue 2.85.0 → 2.87.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/CnAdvancedFormDialog/CnMetadataTab.vue.js +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js +3 -2
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue3.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue.js +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js +5 -4
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue3.js.map +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue.js +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js +2 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +2 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +156 -14
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +105 -74
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue.js +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js +2 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue.js +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js +2 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +6 -5
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue.js +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js +2 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js.map +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +2 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +2 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +2 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue.js +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js +3 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js.map +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js +2 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue3.js.map +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue.js +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js +2 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue.js +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js +3 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js.map +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue3.js.map +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue.js +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue2.js +3 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue2.js.map +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue3.js.map +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue.js +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js +2 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js.map +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +49 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +3 -3
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue.js +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js +2 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js.map +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -5
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +2 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue.js +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js +3 -2
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +28 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +82 -75
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js +5 -4
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue3.js.map +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue.js +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js +2 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js.map +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue3.js.map +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue.js +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js +2 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js.map +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue3.js.map +1 -1
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js +2 -0
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js +2 -2
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue.js +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +2 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue.js +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js +2 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js.map +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +36 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +55 -40
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue.js +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js +2 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +2 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue.js +1 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js +2 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue.js +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js +2 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +3 -26
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue.js +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js +2 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js.map +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js +3 -2
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js +4 -3
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -2
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js +6 -5
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +35 -2
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +38 -2
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +1068 -962
- package/dist/esm/store/useObjectStore.js +7 -2
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/boardColumns.js +50 -1
- package/dist/esm/utils/boardColumns.js.map +1 -1
- package/dist/esm/utils/boardReferenceColumns.js +115 -4
- package/dist/esm/utils/boardReferenceColumns.js.map +1 -1
- package/dist/esm/utils/contentHeaderLink.js +48 -1
- package/dist/esm/utils/contentHeaderLink.js.map +1 -1
- package/dist/esm/utils/schema.js +5 -4
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/userLocale.js +30 -0
- package/dist/esm/utils/userLocale.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1088 -476
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1068 -962
- package/l10n/en.json +35 -2
- package/l10n/nl.json +38 -2
- package/package.json +1 -1
- package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +3 -2
- package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +5 -4
- package/src/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue +2 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +2 -1
- package/src/components/CnBoardView/CnBoardView.vue +189 -24
- package/src/components/CnCalendarEventPicker/CnCalendarEventPicker.vue +2 -1
- package/src/components/CnCalendarWidget/CnCalendarWidget.vue +2 -1
- package/src/components/CnChartWidget/CnChartWidget.vue +6 -5
- package/src/components/CnCollectivePagePicker/CnCollectivePagePicker.vue +2 -1
- package/src/components/CnConversationThread/CnConversationThread.vue +2 -1
- package/src/components/CnCountdownWidget/CnCountdownWidget.vue +2 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +2 -1
- package/src/components/CnDataMatrix/CnDataMatrix.vue +2 -1
- package/src/components/CnDetailPage/CnDetailHeaderChips.vue +2 -1
- package/src/components/CnEmailPicker/CnEmailPicker.vue +2 -1
- package/src/components/CnFederationStatus/CnFederationStatus.vue +3 -1
- package/src/components/CnFileManager/CnFileManager.vue +2 -1
- package/src/components/CnFilePreview/CnFilePreview.vue +2 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +54 -6
- package/src/components/CnFollowToggle/CnFollowToggle.vue +2 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +30 -4
- package/src/components/CnNotesCard/CnNotesCard.vue +2 -1
- package/src/components/CnObjectCalendar/CnObjectCalendar.vue +3 -2
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +36 -0
- package/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +5 -4
- package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +2 -1
- package/src/components/CnObjectSidebar/CnFlowTasksPanel.vue +2 -1
- package/src/components/CnObjectSidebar/CnNotesTab.vue +2 -1
- package/src/components/CnObjectSidebar/CnTasksTab.vue +2 -1
- package/src/components/CnPropertySourceField/CnPropertySourceField.vue +2 -1
- package/src/components/CnRoadmapItem/CnRoadmapItem.vue +2 -1
- package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +4 -2
- package/src/components/CnStatsBlock/CnStatsBlock.vue +2 -1
- package/src/components/CnSummaryAggregates/CnSummaryAggregates.vue +2 -1
- package/src/components/CnTabsWidget/CnTabsWidget.vue +71 -0
- package/src/components/CnTasksCard/CnTasksCard.vue +2 -1
- package/src/components/CnTimelineWidget/CnTimelineWidget.vue +2 -1
- package/src/components/CnTranslatedBadge/CnTranslatedBadge.vue +2 -1
- package/src/components/CnVersionHistory/CnVersionHistory.vue +2 -1
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +3 -26
- package/src/css/board.css +40 -0
- package/src/dialogs/CnNoteHistoryDialog.vue +2 -1
- package/src/integrations/builtin/activity/CnActivityCard.vue +3 -2
- package/src/integrations/builtin/activity/CnActivityTab.vue +4 -3
- package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +3 -2
- package/src/integrations/builtin/calendar/CnCalendarCard.vue +2 -1
- package/src/integrations/builtin/calendar/CnCalendarTab.vue +6 -5
- package/src/integrations/builtin/contactmoment/CnContactmomentCard.vue +2 -1
- package/src/integrations/builtin/cospend/CnCospendTab.vue +2 -1
- package/src/integrations/builtin/deck/CnDeckTab.vue +2 -1
- package/src/integrations/builtin/email/CnEmailCard.vue +2 -1
- package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +2 -1
- package/src/integrations/builtin/field-inspection/CnFieldInspectionTab.vue +2 -1
- package/src/integrations/builtin/photos/CnPhotosTab.vue +2 -1
- package/src/schemas/app-manifest-v2.schema.json +4 -1
- package/src/store/useObjectStore.js +7 -2
- package/src/utils/boardColumns.js +49 -0
- package/src/utils/boardReferenceColumns.js +114 -3
- package/src/utils/contentHeaderLink.js +47 -0
- package/src/utils/schema.js +5 -4
- package/src/utils/userLocale.js +26 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -2,7 +2,7 @@ import script from './CnFollowToggle.vue2.js';
|
|
|
2
2
|
import { render } from './CnFollowToggle.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-8bff02a6";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -8,6 +8,7 @@ import EyeOutline from 'vue-material-design-icons/EyeOutline.vue';
|
|
|
8
8
|
import { patchStoredSelf } from '../../utils/patchStoredSelf.js';
|
|
9
9
|
import { setWatching, listWatchers, setWatcher } from '../../utils/recordInteractions.js';
|
|
10
10
|
import { searchNextcloudUsers } from '../../utils/userAutocomplete.js';
|
|
11
|
+
import { userLocale } from '../../utils/userLocale.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* CnFollowToggle — the one Follow control of a record: a Follow toggle bound to
|
|
@@ -198,7 +199,7 @@ var script = {
|
|
|
198
199
|
const d = new Date(created);
|
|
199
200
|
return Number.isNaN(d.getTime())
|
|
200
201
|
? ''
|
|
201
|
-
: translate('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString() })
|
|
202
|
+
: translate('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString(userLocale()) })
|
|
202
203
|
},
|
|
203
204
|
|
|
204
205
|
removeFollowerLabel(watcher) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnFollowToggle.vue2.js","sources":["../../../../src/components/CnFollowToggle/CnFollowToggle.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<span class=\"cn-follow-toggle\"\n\t\t:class=\"{ 'cn-follow-toggle--compact': compact }\"\n\t\tdata-testid=\"cn-follow-toggle\">\n\t\t<NcButton\n\t\t\t:variant=\"state && !compact ? 'secondary' : 'tertiary'\"\n\t\t\t:aria-pressed=\"state ? 'true' : 'false'\"\n\t\t\t:aria-label=\"compact ? (state ? followingLabel : followLabel) : undefined\"\n\t\t\t:title=\"tooltip\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-button\"\n\t\t\t@click.stop=\"toggle\">\n\t\t\t<template #icon>\n\t\t\t\t<Eye v-if=\"state\" :size=\"20\" class=\"cn-follow-toggle__on\" />\n\t\t\t\t<EyeOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!compact\">\n\t\t\t\t{{ state ? followingLabel : followLabel }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tv-if=\"showNotifySwitch\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t:aria-pressed=\"notifyState ? 'true' : 'false'\"\n\t\t\t:aria-label=\"notifyLabel\"\n\t\t\t:title=\"notifyLabel\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-notify\"\n\t\t\t@click.stop=\"toggleNotify\">\n\t\t\t<template #icon>\n\t\t\t\t<Bell v-if=\"notifyState\" :size=\"20\" />\n\t\t\t\t<BellOffOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcPopover\n\t\t\tv-if=\"count !== null && !compact\"\n\t\t\tv-model:shown=\"open\"\n\t\t\tplacement=\"bottom-start\">\n\t\t\t<template #trigger>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tclass=\"cn-follow-toggle__count\"\n\t\t\t\t\t:aria-label=\"followersLabel\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-count\">\n\t\t\t\t\t{{ count }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<div class=\"cn-follow-toggle__popover\" data-testid=\"cn-follow-toggle-popover\">\n\t\t\t\t<NcLoadingIcon v-if=\"loadingWatchers\" :size=\"20\" :name=\"loadingLabel\" />\n\t\t\t\t<ul v-else class=\"cn-follow-toggle__list\">\n\t\t\t\t\t<li v-for=\"watcher in watchers\" :key=\"watcher.userId\" class=\"cn-follow-toggle__row\">\n\t\t\t\t\t\t<NcAvatar :user=\"watcher.userId\"\n\t\t\t\t\t\t\t:displayName=\"watcher.displayName || watcher.userId\"\n\t\t\t\t\t\t\t:size=\"28\"\n\t\t\t\t\t\t\thideStatus />\n\t\t\t\t\t\t<span class=\"cn-follow-toggle__who\">\n\t\t\t\t\t\t\t<span class=\"cn-follow-toggle__name\">{{ watcher.displayName || watcher.userId }}</span>\n\t\t\t\t\t\t\t<span v-if=\"watcher.created\" class=\"cn-follow-toggle__since\">{{ sinceText(watcher.created) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove(watcher)\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\t:title=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-remove\"\n\t\t\t\t\t\t\t@click=\"removeWatcher(watcher)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Close :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-follow-toggle__picker\">\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:inputLabel=\"addColleagueLabel\"\n\t\t\t\t\t\t:modelValue=\"null\"\n\t\t\t\t\t\t:options=\"pickerOptions\"\n\t\t\t\t\t\t:loading=\"pickerLoading\"\n\t\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-picker\"\n\t\t\t\t\t\t@search=\"onPickerSearch\"\n\t\t\t\t\t\t@update:modelValue=\"addWatcher\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"popoverError\"\n\t\t\t\t\tclass=\"cn-follow-toggle__error\"\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-error\">\n\t\t\t\t\t{{ popoverError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect } from '@nextcloud/vue'\nimport Bell from 'vue-material-design-icons/Bell.vue'\nimport BellOffOutline from 'vue-material-design-icons/BellOffOutline.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport Eye from 'vue-material-design-icons/Eye.vue'\nimport EyeOutline from 'vue-material-design-icons/EyeOutline.vue'\nimport { patchStoredSelf } from '../../utils/patchStoredSelf.js'\nimport { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\n\n/**\n * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to\n * `@self.watching`, a notifications switch bound to `@self.watchNotify`, the\n * follower count and a followers popover for users who may see them.\n *\n * Following and favourites are one feature (OpenRegister's\n * `merge-follow-and-favourites`): a favourite is a follow with notifications\n * off, so there is no separate star. While the user follows, a bell beside the\n * toggle turns the follow's notifications on or off (`PUT .../watch` with\n * `{\"notify\": bool}`). With `notifies` false (the register sends no change\n * notifications) the bell is not offered. `compact` renders the toggle as an\n * icon only, without the bell, count or popover, for a column in a list.\n *\n * A click flips the toggle at once and sends `PUT` or `DELETE .../watch`; on\n * failure it flips back and shows the server's message, and a 404 says the\n * user can no longer see the record and emits `not-found`. The count shows\n * only when `watcherCount` is given (OpenRegister sets `@self.watcherCount` for\n * a reader with `update` only); opening the popover then fetches\n * `GET .../watchers`, never before, and a 403 closes it quietly. With\n * `canManage` (`@self.can.manage`) the popover offers an \"Add a colleague\"\n * picker and a remove action on each follower; without it, only the user's own\n * row can be removed.\n *\n * Example:\n * ```vue\n * <CnFollowToggle register=\"pipelinq\" schema=\"ticket\" :object-id=\"id\"\n * :watching=\"self.watching\" :notify=\"self.watchNotify\"\n * :watcher-count=\"self.watcherCount\" :can-manage=\"self.can && self.can.manage\" />\n * ```\n */\nexport default {\n\tname: 'CnFollowToggle',\n\n\tcomponents: { Bell, BellOffOutline, Close, Eye, EyeOutline, NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect },\n\n\tprops: {\n\t\t/** Register slug of the record. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema slug of the record. */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Id of the record. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether the current user follows the record (`@self.watching`). */\n\t\twatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the user's follow notifies them (`@self.watchNotify`). Null\n\t\t * (an older server, or not following) reads as on.\n\t\t */\n\t\tnotify: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Icon only, without the bell, count or popover: for a column in a list. */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of followers (`@self.watcherCount`). Null hides the count and the popover. */\n\t\twatcherCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the user may add and remove other followers (`@self.can.manage`). */\n\t\tcanManage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether following sends change notifications. False changes the tooltip to say it does not. */\n\t\tnotifies: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** User id of the current user. Defaults to Nextcloud's `OC.currentUser`. */\n\t\tcurrentUser: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['change', 'error', 'not-found'],\n\n\tdata() {\n\t\treturn {\n\t\t\tstate: this.watching,\n\t\t\tnotifyState: this.notify !== false,\n\t\t\tcount: this.watcherCount,\n\t\t\tbusy: false,\n\t\t\topen: false,\n\t\t\twatchers: [],\n\t\t\tloadingWatchers: false,\n\t\t\tpopoverError: '',\n\t\t\tpickerOptions: [],\n\t\t\tpickerLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfollowLabel() {\n\t\t\treturn t('nextcloud-vue', 'Follow')\n\t\t},\n\n\t\tfollowingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Following')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\n\t\taddColleagueLabel() {\n\t\t\treturn t('nextcloud-vue', 'Add a colleague')\n\t\t},\n\n\t\tnotifyLabel() {\n\t\t\treturn this.notifyState\n\t\t\t\t? t('nextcloud-vue', 'Turn notifications off')\n\t\t\t\t: t('nextcloud-vue', 'Turn notifications on')\n\t\t},\n\n\t\t/**\n\t\t * Whether the bell renders: following, not compact, and the register notifies.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowNotifySwitch() {\n\t\t\treturn this.state && !this.compact && this.notifies\n\t\t},\n\n\t\tfollowersLabel() {\n\t\t\treturn t('nextcloud-vue', '{count} followers', { count: this.count })\n\t\t},\n\n\t\ttooltip() {\n\t\t\treturn this.notifies\n\t\t\t\t? t('nextcloud-vue', 'Follow this record to get its updates')\n\t\t\t\t: t('nextcloud-vue', 'You will see it under Following. This register sends no change notifications.')\n\t\t},\n\n\t\tme() {\n\t\t\treturn this.currentUser || (typeof OC !== 'undefined' && OC ? OC.currentUser : '') || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\twatching(value) {\n\t\t\tthis.state = value\n\t\t},\n\n\t\tnotify(value) {\n\t\t\tthis.notifyState = value !== false\n\t\t},\n\n\t\twatcherCount(value) {\n\t\t\tthis.count = value\n\t\t},\n\n\t\topen(value) {\n\t\t\tif (value) {\n\t\t\t\tthis.loadWatchers()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tsinceText(created) {\n\t\t\tconst d = new Date(created)\n\t\t\treturn Number.isNaN(d.getTime())\n\t\t\t\t? ''\n\t\t\t\t: t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString() })\n\t\t},\n\n\t\tremoveFollowerLabel(watcher) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as a follower', { name: watcher.displayName || watcher.userId })\n\t\t},\n\n\t\tcanRemove(watcher) {\n\t\t\treturn this.canManage || (this.me !== '' && watcher.userId === this.me)\n\t\t},\n\n\t\tasync toggle() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.state\n\t\t\tthis.state = !previous\n\t\t\tif (this.count !== null) {\n\t\t\t\tthis.count = Math.max(0, this.count + (this.state ? 1 : -1))\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, this.state)\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.state = previous\n\t\t\t\tif (this.count !== null) {\n\t\t\t\t\tthis.count = Math.max(0, this.count + (previous ? 1 : -1))\n\t\t\t\t}\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change following.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\t/** @event error Emitted when a call failed; payload is the message shown. */\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\t/** @event not-found Emitted on a 404: the record went away or access was withdrawn. */\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// A new follow notifies (the server's default); an unfollow has no switch.\n\t\t\tthis.notifyState = this.state\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, {\n\t\t\t\twatching: this.state,\n\t\t\t\tfavourite: this.state,\n\t\t\t\twatchNotify: this.state ? true : undefined,\n\t\t\t\t...(this.count !== null ? { watcherCount: this.count } : {}),\n\t\t\t})\n\t\t\t/** @event change Emitted after a successful call. Payload: `{ watching, notify, count }`. */\n\t\t\tthis.$emit('change', { watching: this.state, notify: this.state ? this.notifyState : null, count: this.count })\n\t\t},\n\n\t\t/**\n\t\t * Turn the follow's notifications on or off, optimistically.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch\n\t\t */\n\t\tasync toggleNotify() {\n\t\t\tif (this.busy || !this.state) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.notifyState\n\t\t\tthis.notifyState = !previous\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, true, { notify: this.notifyState })\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.notifyState = previous\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change notifications.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, { watchNotify: this.notifyState })\n\t\t\tthis.$emit('change', { watching: true, notify: this.notifyState, count: this.count })\n\t\t},\n\n\t\tasync loadWatchers() {\n\t\t\tthis.popoverError = ''\n\t\t\tthis.loadingWatchers = true\n\t\t\tconst result = await listWatchers(this.register, this.schema, this.objectId)\n\t\t\tthis.loadingWatchers = false\n\t\t\tif (!result.ok) {\n\t\t\t\t// No right to see the list (403) or a failure: close without a toast.\n\t\t\t\tthis.open = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = result.data || {}\n\t\t\tthis.watchers = Array.isArray(data.results) ? data.results : []\n\t\t\tthis.count = Number.isFinite(data.total) ? data.total : this.watchers.length\n\t\t},\n\n\t\tasync onPickerSearch(query) {\n\t\t\tthis.pickerLoading = true\n\t\t\tconst found = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tconst already = new Set(this.watchers.map((w) => w.userId))\n\t\t\tthis.pickerOptions = found.filter((u) => !already.has(u.id)).map((u) => ({ ...u, label: u.label || u.displayName || u.id }))\n\t\t\tthis.pickerLoading = false\n\t\t},\n\n\t\tasync addWatcher(option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, option.id, true)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not add this colleague.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\n\t\tasync removeWatcher(watcher) {\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, watcher.userId, false)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not remove this follower.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (watcher.userId === this.me) {\n\t\t\t\tthis.state = false\n\t\t\t\tthis.$emit('change', { watching: false, count: this.count })\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-follow-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-follow-toggle__on {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-follow-toggle__popover {\n\tmin-width: 260px;\n\tpadding: 12px;\n}\n\n.cn-follow-toggle__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-follow-toggle__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 4px 0;\n}\n\n.cn-follow-toggle__who {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-follow-toggle__since {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-follow-toggle__error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["Bell","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnFollowToggle.vue2.js","sources":["../../../../src/components/CnFollowToggle/CnFollowToggle.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<span class=\"cn-follow-toggle\"\n\t\t:class=\"{ 'cn-follow-toggle--compact': compact }\"\n\t\tdata-testid=\"cn-follow-toggle\">\n\t\t<NcButton\n\t\t\t:variant=\"state && !compact ? 'secondary' : 'tertiary'\"\n\t\t\t:aria-pressed=\"state ? 'true' : 'false'\"\n\t\t\t:aria-label=\"compact ? (state ? followingLabel : followLabel) : undefined\"\n\t\t\t:title=\"tooltip\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-button\"\n\t\t\t@click.stop=\"toggle\">\n\t\t\t<template #icon>\n\t\t\t\t<Eye v-if=\"state\" :size=\"20\" class=\"cn-follow-toggle__on\" />\n\t\t\t\t<EyeOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!compact\">\n\t\t\t\t{{ state ? followingLabel : followLabel }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tv-if=\"showNotifySwitch\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t:aria-pressed=\"notifyState ? 'true' : 'false'\"\n\t\t\t:aria-label=\"notifyLabel\"\n\t\t\t:title=\"notifyLabel\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-notify\"\n\t\t\t@click.stop=\"toggleNotify\">\n\t\t\t<template #icon>\n\t\t\t\t<Bell v-if=\"notifyState\" :size=\"20\" />\n\t\t\t\t<BellOffOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcPopover\n\t\t\tv-if=\"count !== null && !compact\"\n\t\t\tv-model:shown=\"open\"\n\t\t\tplacement=\"bottom-start\">\n\t\t\t<template #trigger>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tclass=\"cn-follow-toggle__count\"\n\t\t\t\t\t:aria-label=\"followersLabel\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-count\">\n\t\t\t\t\t{{ count }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<div class=\"cn-follow-toggle__popover\" data-testid=\"cn-follow-toggle-popover\">\n\t\t\t\t<NcLoadingIcon v-if=\"loadingWatchers\" :size=\"20\" :name=\"loadingLabel\" />\n\t\t\t\t<ul v-else class=\"cn-follow-toggle__list\">\n\t\t\t\t\t<li v-for=\"watcher in watchers\" :key=\"watcher.userId\" class=\"cn-follow-toggle__row\">\n\t\t\t\t\t\t<NcAvatar :user=\"watcher.userId\"\n\t\t\t\t\t\t\t:displayName=\"watcher.displayName || watcher.userId\"\n\t\t\t\t\t\t\t:size=\"28\"\n\t\t\t\t\t\t\thideStatus />\n\t\t\t\t\t\t<span class=\"cn-follow-toggle__who\">\n\t\t\t\t\t\t\t<span class=\"cn-follow-toggle__name\">{{ watcher.displayName || watcher.userId }}</span>\n\t\t\t\t\t\t\t<span v-if=\"watcher.created\" class=\"cn-follow-toggle__since\">{{ sinceText(watcher.created) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove(watcher)\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\t:title=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-remove\"\n\t\t\t\t\t\t\t@click=\"removeWatcher(watcher)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Close :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-follow-toggle__picker\">\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:inputLabel=\"addColleagueLabel\"\n\t\t\t\t\t\t:modelValue=\"null\"\n\t\t\t\t\t\t:options=\"pickerOptions\"\n\t\t\t\t\t\t:loading=\"pickerLoading\"\n\t\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-picker\"\n\t\t\t\t\t\t@search=\"onPickerSearch\"\n\t\t\t\t\t\t@update:modelValue=\"addWatcher\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"popoverError\"\n\t\t\t\t\tclass=\"cn-follow-toggle__error\"\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-error\">\n\t\t\t\t\t{{ popoverError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect } from '@nextcloud/vue'\nimport Bell from 'vue-material-design-icons/Bell.vue'\nimport BellOffOutline from 'vue-material-design-icons/BellOffOutline.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport Eye from 'vue-material-design-icons/Eye.vue'\nimport EyeOutline from 'vue-material-design-icons/EyeOutline.vue'\nimport { patchStoredSelf } from '../../utils/patchStoredSelf.js'\nimport { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to\n * `@self.watching`, a notifications switch bound to `@self.watchNotify`, the\n * follower count and a followers popover for users who may see them.\n *\n * Following and favourites are one feature (OpenRegister's\n * `merge-follow-and-favourites`): a favourite is a follow with notifications\n * off, so there is no separate star. While the user follows, a bell beside the\n * toggle turns the follow's notifications on or off (`PUT .../watch` with\n * `{\"notify\": bool}`). With `notifies` false (the register sends no change\n * notifications) the bell is not offered. `compact` renders the toggle as an\n * icon only, without the bell, count or popover, for a column in a list.\n *\n * A click flips the toggle at once and sends `PUT` or `DELETE .../watch`; on\n * failure it flips back and shows the server's message, and a 404 says the\n * user can no longer see the record and emits `not-found`. The count shows\n * only when `watcherCount` is given (OpenRegister sets `@self.watcherCount` for\n * a reader with `update` only); opening the popover then fetches\n * `GET .../watchers`, never before, and a 403 closes it quietly. With\n * `canManage` (`@self.can.manage`) the popover offers an \"Add a colleague\"\n * picker and a remove action on each follower; without it, only the user's own\n * row can be removed.\n *\n * Example:\n * ```vue\n * <CnFollowToggle register=\"pipelinq\" schema=\"ticket\" :object-id=\"id\"\n * :watching=\"self.watching\" :notify=\"self.watchNotify\"\n * :watcher-count=\"self.watcherCount\" :can-manage=\"self.can && self.can.manage\" />\n * ```\n */\nexport default {\n\tname: 'CnFollowToggle',\n\n\tcomponents: { Bell, BellOffOutline, Close, Eye, EyeOutline, NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect },\n\n\tprops: {\n\t\t/** Register slug of the record. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema slug of the record. */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Id of the record. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether the current user follows the record (`@self.watching`). */\n\t\twatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the user's follow notifies them (`@self.watchNotify`). Null\n\t\t * (an older server, or not following) reads as on.\n\t\t */\n\t\tnotify: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Icon only, without the bell, count or popover: for a column in a list. */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of followers (`@self.watcherCount`). Null hides the count and the popover. */\n\t\twatcherCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the user may add and remove other followers (`@self.can.manage`). */\n\t\tcanManage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether following sends change notifications. False changes the tooltip to say it does not. */\n\t\tnotifies: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** User id of the current user. Defaults to Nextcloud's `OC.currentUser`. */\n\t\tcurrentUser: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['change', 'error', 'not-found'],\n\n\tdata() {\n\t\treturn {\n\t\t\tstate: this.watching,\n\t\t\tnotifyState: this.notify !== false,\n\t\t\tcount: this.watcherCount,\n\t\t\tbusy: false,\n\t\t\topen: false,\n\t\t\twatchers: [],\n\t\t\tloadingWatchers: false,\n\t\t\tpopoverError: '',\n\t\t\tpickerOptions: [],\n\t\t\tpickerLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfollowLabel() {\n\t\t\treturn t('nextcloud-vue', 'Follow')\n\t\t},\n\n\t\tfollowingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Following')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\n\t\taddColleagueLabel() {\n\t\t\treturn t('nextcloud-vue', 'Add a colleague')\n\t\t},\n\n\t\tnotifyLabel() {\n\t\t\treturn this.notifyState\n\t\t\t\t? t('nextcloud-vue', 'Turn notifications off')\n\t\t\t\t: t('nextcloud-vue', 'Turn notifications on')\n\t\t},\n\n\t\t/**\n\t\t * Whether the bell renders: following, not compact, and the register notifies.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowNotifySwitch() {\n\t\t\treturn this.state && !this.compact && this.notifies\n\t\t},\n\n\t\tfollowersLabel() {\n\t\t\treturn t('nextcloud-vue', '{count} followers', { count: this.count })\n\t\t},\n\n\t\ttooltip() {\n\t\t\treturn this.notifies\n\t\t\t\t? t('nextcloud-vue', 'Follow this record to get its updates')\n\t\t\t\t: t('nextcloud-vue', 'You will see it under Following. This register sends no change notifications.')\n\t\t},\n\n\t\tme() {\n\t\t\treturn this.currentUser || (typeof OC !== 'undefined' && OC ? OC.currentUser : '') || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\twatching(value) {\n\t\t\tthis.state = value\n\t\t},\n\n\t\tnotify(value) {\n\t\t\tthis.notifyState = value !== false\n\t\t},\n\n\t\twatcherCount(value) {\n\t\t\tthis.count = value\n\t\t},\n\n\t\topen(value) {\n\t\t\tif (value) {\n\t\t\t\tthis.loadWatchers()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tsinceText(created) {\n\t\t\tconst d = new Date(created)\n\t\t\treturn Number.isNaN(d.getTime())\n\t\t\t\t? ''\n\t\t\t\t: t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString(userLocale()) })\n\t\t},\n\n\t\tremoveFollowerLabel(watcher) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as a follower', { name: watcher.displayName || watcher.userId })\n\t\t},\n\n\t\tcanRemove(watcher) {\n\t\t\treturn this.canManage || (this.me !== '' && watcher.userId === this.me)\n\t\t},\n\n\t\tasync toggle() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.state\n\t\t\tthis.state = !previous\n\t\t\tif (this.count !== null) {\n\t\t\t\tthis.count = Math.max(0, this.count + (this.state ? 1 : -1))\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, this.state)\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.state = previous\n\t\t\t\tif (this.count !== null) {\n\t\t\t\t\tthis.count = Math.max(0, this.count + (previous ? 1 : -1))\n\t\t\t\t}\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change following.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\t/** @event error Emitted when a call failed; payload is the message shown. */\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\t/** @event not-found Emitted on a 404: the record went away or access was withdrawn. */\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// A new follow notifies (the server's default); an unfollow has no switch.\n\t\t\tthis.notifyState = this.state\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, {\n\t\t\t\twatching: this.state,\n\t\t\t\tfavourite: this.state,\n\t\t\t\twatchNotify: this.state ? true : undefined,\n\t\t\t\t...(this.count !== null ? { watcherCount: this.count } : {}),\n\t\t\t})\n\t\t\t/** @event change Emitted after a successful call. Payload: `{ watching, notify, count }`. */\n\t\t\tthis.$emit('change', { watching: this.state, notify: this.state ? this.notifyState : null, count: this.count })\n\t\t},\n\n\t\t/**\n\t\t * Turn the follow's notifications on or off, optimistically.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch\n\t\t */\n\t\tasync toggleNotify() {\n\t\t\tif (this.busy || !this.state) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.notifyState\n\t\t\tthis.notifyState = !previous\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, true, { notify: this.notifyState })\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.notifyState = previous\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change notifications.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, { watchNotify: this.notifyState })\n\t\t\tthis.$emit('change', { watching: true, notify: this.notifyState, count: this.count })\n\t\t},\n\n\t\tasync loadWatchers() {\n\t\t\tthis.popoverError = ''\n\t\t\tthis.loadingWatchers = true\n\t\t\tconst result = await listWatchers(this.register, this.schema, this.objectId)\n\t\t\tthis.loadingWatchers = false\n\t\t\tif (!result.ok) {\n\t\t\t\t// No right to see the list (403) or a failure: close without a toast.\n\t\t\t\tthis.open = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = result.data || {}\n\t\t\tthis.watchers = Array.isArray(data.results) ? data.results : []\n\t\t\tthis.count = Number.isFinite(data.total) ? data.total : this.watchers.length\n\t\t},\n\n\t\tasync onPickerSearch(query) {\n\t\t\tthis.pickerLoading = true\n\t\t\tconst found = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tconst already = new Set(this.watchers.map((w) => w.userId))\n\t\t\tthis.pickerOptions = found.filter((u) => !already.has(u.id)).map((u) => ({ ...u, label: u.label || u.displayName || u.id }))\n\t\t\tthis.pickerLoading = false\n\t\t},\n\n\t\tasync addWatcher(option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, option.id, true)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not add this colleague.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\n\t\tasync removeWatcher(watcher) {\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, watcher.userId, false)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not remove this follower.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (watcher.userId === this.me) {\n\t\t\t\tthis.state = false\n\t\t\t\tthis.$emit('change', { watching: false, count: this.count })\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-follow-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-follow-toggle__on {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-follow-toggle__popover {\n\tmin-width: 260px;\n\tpadding: 12px;\n}\n\n.cn-follow-toggle__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-follow-toggle__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 4px 0;\n}\n\n.cn-follow-toggle__who {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-follow-toggle__since {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-follow-toggle__error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["Bell","t"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnFollowToggle.vue3.js","sources":["../../../../src/components/CnFollowToggle/CnFollowToggle.vue?vue&type=template&id=17752367&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<span class=\"cn-follow-toggle\"\n\t\t:class=\"{ 'cn-follow-toggle--compact': compact }\"\n\t\tdata-testid=\"cn-follow-toggle\">\n\t\t<NcButton\n\t\t\t:variant=\"state && !compact ? 'secondary' : 'tertiary'\"\n\t\t\t:aria-pressed=\"state ? 'true' : 'false'\"\n\t\t\t:aria-label=\"compact ? (state ? followingLabel : followLabel) : undefined\"\n\t\t\t:title=\"tooltip\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-button\"\n\t\t\t@click.stop=\"toggle\">\n\t\t\t<template #icon>\n\t\t\t\t<Eye v-if=\"state\" :size=\"20\" class=\"cn-follow-toggle__on\" />\n\t\t\t\t<EyeOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!compact\">\n\t\t\t\t{{ state ? followingLabel : followLabel }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tv-if=\"showNotifySwitch\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t:aria-pressed=\"notifyState ? 'true' : 'false'\"\n\t\t\t:aria-label=\"notifyLabel\"\n\t\t\t:title=\"notifyLabel\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-notify\"\n\t\t\t@click.stop=\"toggleNotify\">\n\t\t\t<template #icon>\n\t\t\t\t<Bell v-if=\"notifyState\" :size=\"20\" />\n\t\t\t\t<BellOffOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcPopover\n\t\t\tv-if=\"count !== null && !compact\"\n\t\t\tv-model:shown=\"open\"\n\t\t\tplacement=\"bottom-start\">\n\t\t\t<template #trigger>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tclass=\"cn-follow-toggle__count\"\n\t\t\t\t\t:aria-label=\"followersLabel\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-count\">\n\t\t\t\t\t{{ count }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<div class=\"cn-follow-toggle__popover\" data-testid=\"cn-follow-toggle-popover\">\n\t\t\t\t<NcLoadingIcon v-if=\"loadingWatchers\" :size=\"20\" :name=\"loadingLabel\" />\n\t\t\t\t<ul v-else class=\"cn-follow-toggle__list\">\n\t\t\t\t\t<li v-for=\"watcher in watchers\" :key=\"watcher.userId\" class=\"cn-follow-toggle__row\">\n\t\t\t\t\t\t<NcAvatar :user=\"watcher.userId\"\n\t\t\t\t\t\t\t:displayName=\"watcher.displayName || watcher.userId\"\n\t\t\t\t\t\t\t:size=\"28\"\n\t\t\t\t\t\t\thideStatus />\n\t\t\t\t\t\t<span class=\"cn-follow-toggle__who\">\n\t\t\t\t\t\t\t<span class=\"cn-follow-toggle__name\">{{ watcher.displayName || watcher.userId }}</span>\n\t\t\t\t\t\t\t<span v-if=\"watcher.created\" class=\"cn-follow-toggle__since\">{{ sinceText(watcher.created) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove(watcher)\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\t:title=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-remove\"\n\t\t\t\t\t\t\t@click=\"removeWatcher(watcher)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Close :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-follow-toggle__picker\">\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:inputLabel=\"addColleagueLabel\"\n\t\t\t\t\t\t:modelValue=\"null\"\n\t\t\t\t\t\t:options=\"pickerOptions\"\n\t\t\t\t\t\t:loading=\"pickerLoading\"\n\t\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-picker\"\n\t\t\t\t\t\t@search=\"onPickerSearch\"\n\t\t\t\t\t\t@update:modelValue=\"addWatcher\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"popoverError\"\n\t\t\t\t\tclass=\"cn-follow-toggle__error\"\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-error\">\n\t\t\t\t\t{{ popoverError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect } from '@nextcloud/vue'\nimport Bell from 'vue-material-design-icons/Bell.vue'\nimport BellOffOutline from 'vue-material-design-icons/BellOffOutline.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport Eye from 'vue-material-design-icons/Eye.vue'\nimport EyeOutline from 'vue-material-design-icons/EyeOutline.vue'\nimport { patchStoredSelf } from '../../utils/patchStoredSelf.js'\nimport { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\n\n/**\n * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to\n * `@self.watching`, a notifications switch bound to `@self.watchNotify`, the\n * follower count and a followers popover for users who may see them.\n *\n * Following and favourites are one feature (OpenRegister's\n * `merge-follow-and-favourites`): a favourite is a follow with notifications\n * off, so there is no separate star. While the user follows, a bell beside the\n * toggle turns the follow's notifications on or off (`PUT .../watch` with\n * `{\"notify\": bool}`). With `notifies` false (the register sends no change\n * notifications) the bell is not offered. `compact` renders the toggle as an\n * icon only, without the bell, count or popover, for a column in a list.\n *\n * A click flips the toggle at once and sends `PUT` or `DELETE .../watch`; on\n * failure it flips back and shows the server's message, and a 404 says the\n * user can no longer see the record and emits `not-found`. The count shows\n * only when `watcherCount` is given (OpenRegister sets `@self.watcherCount` for\n * a reader with `update` only); opening the popover then fetches\n * `GET .../watchers`, never before, and a 403 closes it quietly. With\n * `canManage` (`@self.can.manage`) the popover offers an \"Add a colleague\"\n * picker and a remove action on each follower; without it, only the user's own\n * row can be removed.\n *\n * Example:\n * ```vue\n * <CnFollowToggle register=\"pipelinq\" schema=\"ticket\" :object-id=\"id\"\n * :watching=\"self.watching\" :notify=\"self.watchNotify\"\n * :watcher-count=\"self.watcherCount\" :can-manage=\"self.can && self.can.manage\" />\n * ```\n */\nexport default {\n\tname: 'CnFollowToggle',\n\n\tcomponents: { Bell, BellOffOutline, Close, Eye, EyeOutline, NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect },\n\n\tprops: {\n\t\t/** Register slug of the record. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema slug of the record. */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Id of the record. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether the current user follows the record (`@self.watching`). */\n\t\twatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the user's follow notifies them (`@self.watchNotify`). Null\n\t\t * (an older server, or not following) reads as on.\n\t\t */\n\t\tnotify: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Icon only, without the bell, count or popover: for a column in a list. */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of followers (`@self.watcherCount`). Null hides the count and the popover. */\n\t\twatcherCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the user may add and remove other followers (`@self.can.manage`). */\n\t\tcanManage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether following sends change notifications. False changes the tooltip to say it does not. */\n\t\tnotifies: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** User id of the current user. Defaults to Nextcloud's `OC.currentUser`. */\n\t\tcurrentUser: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['change', 'error', 'not-found'],\n\n\tdata() {\n\t\treturn {\n\t\t\tstate: this.watching,\n\t\t\tnotifyState: this.notify !== false,\n\t\t\tcount: this.watcherCount,\n\t\t\tbusy: false,\n\t\t\topen: false,\n\t\t\twatchers: [],\n\t\t\tloadingWatchers: false,\n\t\t\tpopoverError: '',\n\t\t\tpickerOptions: [],\n\t\t\tpickerLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfollowLabel() {\n\t\t\treturn t('nextcloud-vue', 'Follow')\n\t\t},\n\n\t\tfollowingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Following')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\n\t\taddColleagueLabel() {\n\t\t\treturn t('nextcloud-vue', 'Add a colleague')\n\t\t},\n\n\t\tnotifyLabel() {\n\t\t\treturn this.notifyState\n\t\t\t\t? t('nextcloud-vue', 'Turn notifications off')\n\t\t\t\t: t('nextcloud-vue', 'Turn notifications on')\n\t\t},\n\n\t\t/**\n\t\t * Whether the bell renders: following, not compact, and the register notifies.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowNotifySwitch() {\n\t\t\treturn this.state && !this.compact && this.notifies\n\t\t},\n\n\t\tfollowersLabel() {\n\t\t\treturn t('nextcloud-vue', '{count} followers', { count: this.count })\n\t\t},\n\n\t\ttooltip() {\n\t\t\treturn this.notifies\n\t\t\t\t? t('nextcloud-vue', 'Follow this record to get its updates')\n\t\t\t\t: t('nextcloud-vue', 'You will see it under Following. This register sends no change notifications.')\n\t\t},\n\n\t\tme() {\n\t\t\treturn this.currentUser || (typeof OC !== 'undefined' && OC ? OC.currentUser : '') || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\twatching(value) {\n\t\t\tthis.state = value\n\t\t},\n\n\t\tnotify(value) {\n\t\t\tthis.notifyState = value !== false\n\t\t},\n\n\t\twatcherCount(value) {\n\t\t\tthis.count = value\n\t\t},\n\n\t\topen(value) {\n\t\t\tif (value) {\n\t\t\t\tthis.loadWatchers()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tsinceText(created) {\n\t\t\tconst d = new Date(created)\n\t\t\treturn Number.isNaN(d.getTime())\n\t\t\t\t? ''\n\t\t\t\t: t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString() })\n\t\t},\n\n\t\tremoveFollowerLabel(watcher) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as a follower', { name: watcher.displayName || watcher.userId })\n\t\t},\n\n\t\tcanRemove(watcher) {\n\t\t\treturn this.canManage || (this.me !== '' && watcher.userId === this.me)\n\t\t},\n\n\t\tasync toggle() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.state\n\t\t\tthis.state = !previous\n\t\t\tif (this.count !== null) {\n\t\t\t\tthis.count = Math.max(0, this.count + (this.state ? 1 : -1))\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, this.state)\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.state = previous\n\t\t\t\tif (this.count !== null) {\n\t\t\t\t\tthis.count = Math.max(0, this.count + (previous ? 1 : -1))\n\t\t\t\t}\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change following.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\t/** @event error Emitted when a call failed; payload is the message shown. */\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\t/** @event not-found Emitted on a 404: the record went away or access was withdrawn. */\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// A new follow notifies (the server's default); an unfollow has no switch.\n\t\t\tthis.notifyState = this.state\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, {\n\t\t\t\twatching: this.state,\n\t\t\t\tfavourite: this.state,\n\t\t\t\twatchNotify: this.state ? true : undefined,\n\t\t\t\t...(this.count !== null ? { watcherCount: this.count } : {}),\n\t\t\t})\n\t\t\t/** @event change Emitted after a successful call. Payload: `{ watching, notify, count }`. */\n\t\t\tthis.$emit('change', { watching: this.state, notify: this.state ? this.notifyState : null, count: this.count })\n\t\t},\n\n\t\t/**\n\t\t * Turn the follow's notifications on or off, optimistically.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch\n\t\t */\n\t\tasync toggleNotify() {\n\t\t\tif (this.busy || !this.state) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.notifyState\n\t\t\tthis.notifyState = !previous\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, true, { notify: this.notifyState })\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.notifyState = previous\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change notifications.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, { watchNotify: this.notifyState })\n\t\t\tthis.$emit('change', { watching: true, notify: this.notifyState, count: this.count })\n\t\t},\n\n\t\tasync loadWatchers() {\n\t\t\tthis.popoverError = ''\n\t\t\tthis.loadingWatchers = true\n\t\t\tconst result = await listWatchers(this.register, this.schema, this.objectId)\n\t\t\tthis.loadingWatchers = false\n\t\t\tif (!result.ok) {\n\t\t\t\t// No right to see the list (403) or a failure: close without a toast.\n\t\t\t\tthis.open = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = result.data || {}\n\t\t\tthis.watchers = Array.isArray(data.results) ? data.results : []\n\t\t\tthis.count = Number.isFinite(data.total) ? data.total : this.watchers.length\n\t\t},\n\n\t\tasync onPickerSearch(query) {\n\t\t\tthis.pickerLoading = true\n\t\t\tconst found = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tconst already = new Set(this.watchers.map((w) => w.userId))\n\t\t\tthis.pickerOptions = found.filter((u) => !already.has(u.id)).map((u) => ({ ...u, label: u.label || u.displayName || u.id }))\n\t\t\tthis.pickerLoading = false\n\t\t},\n\n\t\tasync addWatcher(option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, option.id, true)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not add this colleague.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\n\t\tasync removeWatcher(watcher) {\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, watcher.userId, false)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not remove this follower.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (watcher.userId === this.me) {\n\t\t\t\tthis.state = false\n\t\t\t\tthis.$emit('change', { watching: false, count: this.count })\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-follow-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-follow-toggle__on {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-follow-toggle__popover {\n\tmin-width: 260px;\n\tpadding: 12px;\n}\n\n.cn-follow-toggle__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-follow-toggle__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 4px 0;\n}\n\n.cn-follow-toggle__who {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-follow-toggle__since {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-follow-toggle__error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_createBlock","_createElementBlock","_Fragment","_createElementVNode","_openBlock","_renderList","_toDisplayString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnFollowToggle.vue3.js","sources":["../../../../src/components/CnFollowToggle/CnFollowToggle.vue?vue&type=template&id=8bff02a6&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<span class=\"cn-follow-toggle\"\n\t\t:class=\"{ 'cn-follow-toggle--compact': compact }\"\n\t\tdata-testid=\"cn-follow-toggle\">\n\t\t<NcButton\n\t\t\t:variant=\"state && !compact ? 'secondary' : 'tertiary'\"\n\t\t\t:aria-pressed=\"state ? 'true' : 'false'\"\n\t\t\t:aria-label=\"compact ? (state ? followingLabel : followLabel) : undefined\"\n\t\t\t:title=\"tooltip\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-button\"\n\t\t\t@click.stop=\"toggle\">\n\t\t\t<template #icon>\n\t\t\t\t<Eye v-if=\"state\" :size=\"20\" class=\"cn-follow-toggle__on\" />\n\t\t\t\t<EyeOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t\t<template v-if=\"!compact\">\n\t\t\t\t{{ state ? followingLabel : followLabel }}\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcButton\n\t\t\tv-if=\"showNotifySwitch\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t:aria-pressed=\"notifyState ? 'true' : 'false'\"\n\t\t\t:aria-label=\"notifyLabel\"\n\t\t\t:title=\"notifyLabel\"\n\t\t\t:disabled=\"busy\"\n\t\t\tdata-testid=\"cn-follow-toggle-notify\"\n\t\t\t@click.stop=\"toggleNotify\">\n\t\t\t<template #icon>\n\t\t\t\t<Bell v-if=\"notifyState\" :size=\"20\" />\n\t\t\t\t<BellOffOutline v-else :size=\"20\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t\t<NcPopover\n\t\t\tv-if=\"count !== null && !compact\"\n\t\t\tv-model:shown=\"open\"\n\t\t\tplacement=\"bottom-start\">\n\t\t\t<template #trigger>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\tclass=\"cn-follow-toggle__count\"\n\t\t\t\t\t:aria-label=\"followersLabel\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-count\">\n\t\t\t\t\t{{ count }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t\t<div class=\"cn-follow-toggle__popover\" data-testid=\"cn-follow-toggle-popover\">\n\t\t\t\t<NcLoadingIcon v-if=\"loadingWatchers\" :size=\"20\" :name=\"loadingLabel\" />\n\t\t\t\t<ul v-else class=\"cn-follow-toggle__list\">\n\t\t\t\t\t<li v-for=\"watcher in watchers\" :key=\"watcher.userId\" class=\"cn-follow-toggle__row\">\n\t\t\t\t\t\t<NcAvatar :user=\"watcher.userId\"\n\t\t\t\t\t\t\t:displayName=\"watcher.displayName || watcher.userId\"\n\t\t\t\t\t\t\t:size=\"28\"\n\t\t\t\t\t\t\thideStatus />\n\t\t\t\t\t\t<span class=\"cn-follow-toggle__who\">\n\t\t\t\t\t\t\t<span class=\"cn-follow-toggle__name\">{{ watcher.displayName || watcher.userId }}</span>\n\t\t\t\t\t\t\t<span v-if=\"watcher.created\" class=\"cn-follow-toggle__since\">{{ sinceText(watcher.created) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"canRemove(watcher)\"\n\t\t\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t\t\t:aria-label=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\t:title=\"removeFollowerLabel(watcher)\"\n\t\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-remove\"\n\t\t\t\t\t\t\t@click=\"removeWatcher(watcher)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Close :size=\"16\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<div v-if=\"canManage\" class=\"cn-follow-toggle__picker\">\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t:inputLabel=\"addColleagueLabel\"\n\t\t\t\t\t\t:modelValue=\"null\"\n\t\t\t\t\t\t:options=\"pickerOptions\"\n\t\t\t\t\t\t:loading=\"pickerLoading\"\n\t\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\t\tdata-testid=\"cn-follow-toggle-picker\"\n\t\t\t\t\t\t@search=\"onPickerSearch\"\n\t\t\t\t\t\t@update:modelValue=\"addWatcher\" />\n\t\t\t\t</div>\n\t\t\t\t<p v-if=\"popoverError\"\n\t\t\t\t\tclass=\"cn-follow-toggle__error\"\n\t\t\t\t\trole=\"alert\"\n\t\t\t\t\tdata-testid=\"cn-follow-toggle-error\">\n\t\t\t\t\t{{ popoverError }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</NcPopover>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect } from '@nextcloud/vue'\nimport Bell from 'vue-material-design-icons/Bell.vue'\nimport BellOffOutline from 'vue-material-design-icons/BellOffOutline.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport Eye from 'vue-material-design-icons/Eye.vue'\nimport EyeOutline from 'vue-material-design-icons/EyeOutline.vue'\nimport { patchStoredSelf } from '../../utils/patchStoredSelf.js'\nimport { listWatchers, setWatcher, setWatching } from '../../utils/recordInteractions.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnFollowToggle — the one Follow control of a record: a Follow toggle bound to\n * `@self.watching`, a notifications switch bound to `@self.watchNotify`, the\n * follower count and a followers popover for users who may see them.\n *\n * Following and favourites are one feature (OpenRegister's\n * `merge-follow-and-favourites`): a favourite is a follow with notifications\n * off, so there is no separate star. While the user follows, a bell beside the\n * toggle turns the follow's notifications on or off (`PUT .../watch` with\n * `{\"notify\": bool}`). With `notifies` false (the register sends no change\n * notifications) the bell is not offered. `compact` renders the toggle as an\n * icon only, without the bell, count or popover, for a column in a list.\n *\n * A click flips the toggle at once and sends `PUT` or `DELETE .../watch`; on\n * failure it flips back and shows the server's message, and a 404 says the\n * user can no longer see the record and emits `not-found`. The count shows\n * only when `watcherCount` is given (OpenRegister sets `@self.watcherCount` for\n * a reader with `update` only); opening the popover then fetches\n * `GET .../watchers`, never before, and a 403 closes it quietly. With\n * `canManage` (`@self.can.manage`) the popover offers an \"Add a colleague\"\n * picker and a remove action on each follower; without it, only the user's own\n * row can be removed.\n *\n * Example:\n * ```vue\n * <CnFollowToggle register=\"pipelinq\" schema=\"ticket\" :object-id=\"id\"\n * :watching=\"self.watching\" :notify=\"self.watchNotify\"\n * :watcher-count=\"self.watcherCount\" :can-manage=\"self.can && self.can.manage\" />\n * ```\n */\nexport default {\n\tname: 'CnFollowToggle',\n\n\tcomponents: { Bell, BellOffOutline, Close, Eye, EyeOutline, NcAvatar, NcButton, NcLoadingIcon, NcPopover, NcSelect },\n\n\tprops: {\n\t\t/** Register slug of the record. */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Schema slug of the record. */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Id of the record. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Whether the current user follows the record (`@self.watching`). */\n\t\twatching: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Whether the user's follow notifies them (`@self.watchNotify`). Null\n\t\t * (an older server, or not following) reads as on.\n\t\t */\n\t\tnotify: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Icon only, without the bell, count or popover: for a column in a list. */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Number of followers (`@self.watcherCount`). Null hides the count and the popover. */\n\t\twatcherCount: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether the user may add and remove other followers (`@self.can.manage`). */\n\t\tcanManage: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether following sends change notifications. False changes the tooltip to say it does not. */\n\t\tnotifies: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** User id of the current user. Defaults to Nextcloud's `OC.currentUser`. */\n\t\tcurrentUser: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['change', 'error', 'not-found'],\n\n\tdata() {\n\t\treturn {\n\t\t\tstate: this.watching,\n\t\t\tnotifyState: this.notify !== false,\n\t\t\tcount: this.watcherCount,\n\t\t\tbusy: false,\n\t\t\topen: false,\n\t\t\twatchers: [],\n\t\t\tloadingWatchers: false,\n\t\t\tpopoverError: '',\n\t\t\tpickerOptions: [],\n\t\t\tpickerLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tfollowLabel() {\n\t\t\treturn t('nextcloud-vue', 'Follow')\n\t\t},\n\n\t\tfollowingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Following')\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading …')\n\t\t},\n\n\t\taddColleagueLabel() {\n\t\t\treturn t('nextcloud-vue', 'Add a colleague')\n\t\t},\n\n\t\tnotifyLabel() {\n\t\t\treturn this.notifyState\n\t\t\t\t? t('nextcloud-vue', 'Turn notifications off')\n\t\t\t\t: t('nextcloud-vue', 'Turn notifications on')\n\t\t},\n\n\t\t/**\n\t\t * Whether the bell renders: following, not compact, and the register notifies.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tshowNotifySwitch() {\n\t\t\treturn this.state && !this.compact && this.notifies\n\t\t},\n\n\t\tfollowersLabel() {\n\t\t\treturn t('nextcloud-vue', '{count} followers', { count: this.count })\n\t\t},\n\n\t\ttooltip() {\n\t\t\treturn this.notifies\n\t\t\t\t? t('nextcloud-vue', 'Follow this record to get its updates')\n\t\t\t\t: t('nextcloud-vue', 'You will see it under Following. This register sends no change notifications.')\n\t\t},\n\n\t\tme() {\n\t\t\treturn this.currentUser || (typeof OC !== 'undefined' && OC ? OC.currentUser : '') || ''\n\t\t},\n\t},\n\n\twatch: {\n\t\twatching(value) {\n\t\t\tthis.state = value\n\t\t},\n\n\t\tnotify(value) {\n\t\t\tthis.notifyState = value !== false\n\t\t},\n\n\t\twatcherCount(value) {\n\t\t\tthis.count = value\n\t\t},\n\n\t\topen(value) {\n\t\t\tif (value) {\n\t\t\t\tthis.loadWatchers()\n\t\t\t}\n\t\t},\n\t},\n\n\tmethods: {\n\t\tsinceText(created) {\n\t\t\tconst d = new Date(created)\n\t\t\treturn Number.isNaN(d.getTime())\n\t\t\t\t? ''\n\t\t\t\t: t('nextcloud-vue', 'Since {date}', { date: d.toLocaleDateString(userLocale()) })\n\t\t},\n\n\t\tremoveFollowerLabel(watcher) {\n\t\t\treturn t('nextcloud-vue', 'Remove {name} as a follower', { name: watcher.displayName || watcher.userId })\n\t\t},\n\n\t\tcanRemove(watcher) {\n\t\t\treturn this.canManage || (this.me !== '' && watcher.userId === this.me)\n\t\t},\n\n\t\tasync toggle() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.state\n\t\t\tthis.state = !previous\n\t\t\tif (this.count !== null) {\n\t\t\t\tthis.count = Math.max(0, this.count + (this.state ? 1 : -1))\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, this.state)\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.state = previous\n\t\t\t\tif (this.count !== null) {\n\t\t\t\t\tthis.count = Math.max(0, this.count + (previous ? 1 : -1))\n\t\t\t\t}\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change following.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\t/** @event error Emitted when a call failed; payload is the message shown. */\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\t/** @event not-found Emitted on a 404: the record went away or access was withdrawn. */\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// A new follow notifies (the server's default); an unfollow has no switch.\n\t\t\tthis.notifyState = this.state\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, {\n\t\t\t\twatching: this.state,\n\t\t\t\tfavourite: this.state,\n\t\t\t\twatchNotify: this.state ? true : undefined,\n\t\t\t\t...(this.count !== null ? { watcherCount: this.count } : {}),\n\t\t\t})\n\t\t\t/** @event change Emitted after a successful call. Payload: `{ watching, notify, count }`. */\n\t\t\tthis.$emit('change', { watching: this.state, notify: this.state ? this.notifyState : null, count: this.count })\n\t\t},\n\n\t\t/**\n\t\t * Turn the follow's notifications on or off, optimistically.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/one-follow-control/specs/record-follow/spec.md#requirement-one-follow-control-with-a-notifications-switch\n\t\t */\n\t\tasync toggleNotify() {\n\t\t\tif (this.busy || !this.state) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst previous = this.notifyState\n\t\t\tthis.notifyState = !previous\n\t\t\tthis.busy = true\n\t\t\tconst result = await setWatching(this.register, this.schema, this.objectId, true, { notify: this.notifyState })\n\t\t\tthis.busy = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.notifyState = previous\n\t\t\t\tconst message = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer see this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'Could not change notifications.'))\n\t\t\t\timport('@nextcloud/dialogs').then(({ showError }) => showError(message)).catch(() => {})\n\t\t\t\tthis.$emit('error', message)\n\t\t\t\tif (result.status === 404) {\n\t\t\t\t\tthis.$emit('not-found')\n\t\t\t\t}\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpatchStoredSelf(this.register, this.schema, this.objectId, { watchNotify: this.notifyState })\n\t\t\tthis.$emit('change', { watching: true, notify: this.notifyState, count: this.count })\n\t\t},\n\n\t\tasync loadWatchers() {\n\t\t\tthis.popoverError = ''\n\t\t\tthis.loadingWatchers = true\n\t\t\tconst result = await listWatchers(this.register, this.schema, this.objectId)\n\t\t\tthis.loadingWatchers = false\n\t\t\tif (!result.ok) {\n\t\t\t\t// No right to see the list (403) or a failure: close without a toast.\n\t\t\t\tthis.open = false\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst data = result.data || {}\n\t\t\tthis.watchers = Array.isArray(data.results) ? data.results : []\n\t\t\tthis.count = Number.isFinite(data.total) ? data.total : this.watchers.length\n\t\t},\n\n\t\tasync onPickerSearch(query) {\n\t\t\tthis.pickerLoading = true\n\t\t\tconst found = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tconst already = new Set(this.watchers.map((w) => w.userId))\n\t\t\tthis.pickerOptions = found.filter((u) => !already.has(u.id)).map((u) => ({ ...u, label: u.label || u.displayName || u.id }))\n\t\t\tthis.pickerLoading = false\n\t\t},\n\n\t\tasync addWatcher(option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, option.id, true)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not add this colleague.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\n\t\tasync removeWatcher(watcher) {\n\t\t\tthis.popoverError = ''\n\t\t\tconst result = await setWatcher(this.register, this.schema, this.objectId, watcher.userId, false)\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.popoverError = result.message || t('nextcloud-vue', 'Could not remove this follower.')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (watcher.userId === this.me) {\n\t\t\t\tthis.state = false\n\t\t\t\tthis.$emit('change', { watching: false, count: this.count })\n\t\t\t}\n\t\t\tawait this.loadWatchers()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-follow-toggle {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-follow-toggle__on {\n\tcolor: var(--color-primary-element);\n}\n\n.cn-follow-toggle__popover {\n\tmin-width: 260px;\n\tpadding: 12px;\n}\n\n.cn-follow-toggle__list {\n\tlist-style: none;\n\tmargin: 0 0 8px;\n\tpadding: 0;\n}\n\n.cn-follow-toggle__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 4px 0;\n}\n\n.cn-follow-toggle__who {\n\tdisplay: flex;\n\tflex-direction: column;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-follow-toggle__since {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--font-size-small, 13px);\n}\n\n.cn-follow-toggle__error {\n\tmargin: 8px 0 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["_normalizeClass","_createVNode","_createBlock","_createElementBlock","_Fragment","_createElementVNode","_openBlock","_renderList","_toDisplayString"],"mappings":"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"}
|
|
@@ -28,7 +28,7 @@ import { METADATA_COLUMNS } from '../../constants/metadata.js';
|
|
|
28
28
|
import { useObjectStore } from '../../store/useObjectStore.js';
|
|
29
29
|
import { routeHref, followItemActionLink, resolveItemActionLink } from '../../utils/actionLink.js';
|
|
30
30
|
import { resolveRegisteredHandler, buildOnSuccessRoute } from '../../utils/actionsDispatcher.js';
|
|
31
|
-
import { columnFieldsOf, refIdOf, buildValueStages, buildReferenceStages, columnKeyOfRow, resolveDropValue, referenceTargetOf, fetchReferenceObjects } from '../../utils/boardReferenceColumns.js';
|
|
31
|
+
import { columnFieldsOf, refIdOf, buildValueStages, buildReferenceStages, columnKeyOfRow, resolveDropValue, fullTargetOf, referenceTargetOf, fetchReferenceObjects } from '../../utils/boardReferenceColumns.js';
|
|
32
32
|
import { reportBindingProblems } from '../../utils/diagnostics.js';
|
|
33
33
|
import { fetchFilterCounts } from '../../utils/fetchFilterCounts.js';
|
|
34
34
|
import { buildExportUrl } from '../../utils/indexExportHelpers.js';
|
|
@@ -3099,6 +3099,9 @@ var script = {
|
|
|
3099
3099
|
mergeBy: source.mergeBy || '',
|
|
3100
3100
|
narrowBy,
|
|
3101
3101
|
narrowValue: narrowBy ? this.boardNarrowValue : '',
|
|
3102
|
+
capacityField: source.capacityField || '',
|
|
3103
|
+
neutralColor: typeof source.neutralColor === 'string' ? source.neutralColor : '',
|
|
3104
|
+
colorMap: source.colorMap && typeof source.colorMap === 'object' ? source.colorMap : null,
|
|
3102
3105
|
})
|
|
3103
3106
|
},
|
|
3104
3107
|
|
|
@@ -3141,6 +3144,10 @@ var script = {
|
|
|
3141
3144
|
* row (PATCH). `readOnly` gives no move. A board on `statusField` with
|
|
3142
3145
|
* neither keeps the `runTransition` prop.
|
|
3143
3146
|
*
|
|
3147
|
+
* With `source.capacityField`, a drop that would fill the referenced
|
|
3148
|
+
* row past its limit is refused before the handler or the PATCH runs.
|
|
3149
|
+
* The server still guards; this only spares the round trip.
|
|
3150
|
+
*
|
|
3144
3151
|
* @return {((move: {card: object, toKey: string}) => Promise<object>)|null} The move, or null for a read-only board.
|
|
3145
3152
|
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-a-drop-writes-the-reference
|
|
3146
3153
|
*/
|
|
@@ -3162,6 +3169,7 @@ var script = {
|
|
|
3162
3169
|
const field = this.boardColumnField;
|
|
3163
3170
|
const kind = active?.kind || 'schema';
|
|
3164
3171
|
const narrowBy = active?.source?.narrowBy || null;
|
|
3172
|
+
const capacityField = active?.source?.capacityField || '';
|
|
3165
3173
|
return async ({ card, toKey }) => {
|
|
3166
3174
|
const drop = stages
|
|
3167
3175
|
? resolveDropValue({ card, toKey, kind, refsByKey: stages.refsByKey, narrowBy })
|
|
@@ -3169,6 +3177,13 @@ var script = {
|
|
|
3169
3177
|
if (drop === null) {
|
|
3170
3178
|
throw new Error(translate('nextcloud-vue', 'This card cannot move to that column.'))
|
|
3171
3179
|
}
|
|
3180
|
+
const full = capacityField && drop.target
|
|
3181
|
+
? fullTargetOf({ target: drop.target, card, rows: this.displayObjects, field, capacityField, rowKey: this.rowKey })
|
|
3182
|
+
: null;
|
|
3183
|
+
if (full) {
|
|
3184
|
+
const column = stages.states.find((state) => state.key === String(toKey))?.label || String(toKey);
|
|
3185
|
+
throw new Error(translate('nextcloud-vue', '{column} is full: {count} of {capacity}.', { column, count: full.count, capacity: full.capacity }))
|
|
3186
|
+
}
|
|
3172
3187
|
if (handler) {
|
|
3173
3188
|
return handler({ card, toKey, field, value: drop.value, target: drop.target })
|
|
3174
3189
|
}
|
|
@@ -3184,9 +3199,12 @@ var script = {
|
|
|
3184
3199
|
/**
|
|
3185
3200
|
* Where a card may go, from the app's `moveTargetsHandler`: it gets
|
|
3186
3201
|
* `{ card, field }` and answers the values (referenced ids) the card
|
|
3187
|
-
* can reach; the board maps them to its columns.
|
|
3202
|
+
* can reach; the board maps them to its columns. An entry may also be
|
|
3203
|
+
* `{ key, allowed, reason }`: a target that is offered but blocked,
|
|
3204
|
+
* with the sentence that says why.
|
|
3188
3205
|
*
|
|
3189
|
-
* @return {((card: object) => Promise<Array<string>|null>)|null} The question, or null.
|
|
3206
|
+
* @return {((card: object) => Promise<Array<string|{key: string, allowed: boolean, reason: string}>|null>)|null} The question, or null.
|
|
3207
|
+
* @spec openspec/changes/board-move-block-reasons/specs/board-view/spec.md#requirement-a-move-target-can-be-blocked-with-a-reason
|
|
3190
3208
|
* @spec openspec/changes/screens-board-reference-columns/specs/board-view/spec.md#requirement-the-board-shows-where-a-card-can-go
|
|
3191
3209
|
*/
|
|
3192
3210
|
boardAllowedMoves() {
|
|
@@ -3204,9 +3222,16 @@ var script = {
|
|
|
3204
3222
|
if (!Array.isArray(values)) {
|
|
3205
3223
|
return null
|
|
3206
3224
|
}
|
|
3225
|
+
const columnOf = (id) => (stages && stages.keyByValue.has(id) ? stages.keyByValue.get(id) : id);
|
|
3207
3226
|
return values.map((value) => {
|
|
3208
|
-
|
|
3209
|
-
|
|
3227
|
+
if (value && typeof value === 'object' && Object.hasOwn(value, 'key')) {
|
|
3228
|
+
return {
|
|
3229
|
+
key: columnOf(refIdOf(value.key)),
|
|
3230
|
+
allowed: value.allowed !== false,
|
|
3231
|
+
reason: typeof value.reason === 'string' ? value.reason : '',
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
return columnOf(refIdOf(value))
|
|
3210
3235
|
})
|
|
3211
3236
|
}
|
|
3212
3237
|
},
|