@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAuditTrailTab.vue3.js","sources":["../../../../src/components/CnObjectSidebar/CnAuditTrailTab.vue?vue&type=template&id=6f5592a5&lang.js"],"sourcesContent":["<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<template v-else-if=\"entries.length > 0\">\n\t\t\t<!-- Filters -->\n\t\t\t<div class=\"cn-audit-filters\">\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"filterAction\"\n\t\t\t\t\t:options=\"actionOptions\"\n\t\t\t\t\t:placeholder=\"actionFilterLabel\"\n\t\t\t\t\t:inputLabel=\"actionFilterLabel\"\n\t\t\t\t\t:multiple=\"true\"\n\t\t\t\t\t:keepOpen=\"true\"\n\t\t\t\t\tclass=\"cn-audit-filters__select\" />\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"filterUser\"\n\t\t\t\t\t:options=\"userOptions\"\n\t\t\t\t\t:placeholder=\"userFilterLabel\"\n\t\t\t\t\t:inputLabel=\"userFilterLabel\"\n\t\t\t\t\t:multiple=\"true\"\n\t\t\t\t\t:keepOpen=\"true\"\n\t\t\t\t\tclass=\"cn-audit-filters__select\" />\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tid=\"audit-date-from\"\n\t\t\t\t\tv-model=\"filterDateFrom\"\n\t\t\t\t\t:label=\"fromLabel\"\n\t\t\t\t\ttype=\"date\"\n\t\t\t\t\tclass=\"cn-audit-filters__date\" />\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tid=\"audit-date-to\"\n\t\t\t\t\tv-model=\"filterDateTo\"\n\t\t\t\t\t:label=\"toLabel\"\n\t\t\t\t\ttype=\"date\"\n\t\t\t\t\tclass=\"cn-audit-filters__date\" />\n\t\t\t</div>\n\n\t\t\t<div v-if=\"entries.length === 0 && !loading\" class=\"cn-sidebar-tab__empty\">\n\t\t\t\t{{ noMatchLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-sidebar-tab__list\">\n\t\t\t\t<div v-for=\"entry in entries\" :key=\"entry.id\" class=\"cn-audit-entry\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\t:name=\"formatDate(entry.created)\"\n\t\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t\t:details=\"entry.action\"\n\t\t\t\t\t\t:counterNumber=\"changedCount(entry)\"\n\t\t\t\t\t\t@click=\"toggleExpand(entry.id)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<History :size=\"32\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t{{ entry.userName || entry.user || 'System' }}\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t\t<!-- Expandable details -->\n\t\t\t\t\t<div v-if=\"expandedId === entry.id\" class=\"cn-audit-details\">\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Action</span>\n\t\t\t\t\t\t\t<span>{{ entry.action }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">User</span>\n\t\t\t\t\t\t\t<span>{{ entry.userName || entry.user || 'System' }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Date</span>\n\t\t\t\t\t\t\t<span>{{ formatDate(entry.created) }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"entry.ipAddress\" class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">IP</span>\n\t\t\t\t\t\t\t<span>{{ entry.ipAddress }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"entry.session\" class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Session</span>\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__mono\">{{ entry.session }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- Restore (allowRestore only; create and update entries) -->\n\t\t\t\t\t\t<div v-if=\"canRestore(entry)\" class=\"cn-audit-details__restore\">\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t\t:disabled=\"restoreBlocked\"\n\t\t\t\t\t\t\t\t:title=\"restoreBlocked ? restoreLockedLabel : undefined\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-audit-restore\"\n\t\t\t\t\t\t\t\t@click.stop=\"askRestore(entry)\">\n\t\t\t\t\t\t\t\t{{ restoreLabel }}\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- Changed fields -->\n\t\t\t\t\t\t<div v-if=\"entry.changed && Object.keys(entry.changed).length > 0\" class=\"cn-audit-details__changes\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Changes</span>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tv-for=\"(change, field) in entry.changed\"\n\t\t\t\t\t\t\t\t:key=\"field\"\n\t\t\t\t\t\t\t\tclass=\"cn-audit-details__change\">\n\t\t\t\t\t\t\t\t<span class=\"cn-audit-details__field\">{{ field }}</span>\n\t\t\t\t\t\t\t\t<div v-if=\"isSimpleValue(change)\" class=\"cn-audit-details__values\">\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old !== null && change.old !== undefined\" class=\"cn-audit-details__old\">{{ formatValue(change.old) }}</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old !== null && change.new !== null\" class=\"cn-audit-details__arrow\">→</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.new !== null && change.new !== undefined\" class=\"cn-audit-details__new\">{{ formatValue(change.new) }}</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old === null && change.new === null\" class=\"cn-audit-details__null\">null</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div v-else class=\"cn-audit-details__values\">\n\t\t\t\t\t\t\t\t\t<span class=\"cn-audit-details__mono\">{{ formatValue(change) }}</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<!-- Load more -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"hasMore\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:wide=\"true\"\n\t\t\t\t\t:disabled=\"loadingMore\"\n\t\t\t\t\tclass=\"cn-sidebar-tab__load-more\"\n\t\t\t\t\t@click=\"loadMore\">\n\t\t\t\t\t<template v-if=\"loadingMore\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ loadMoreLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</template>\n\t\t<div v-else class=\"cn-sidebar-tab__empty\">\n\t\t\t{{ noAuditTrailLabel }}\n\t\t</div>\n\t\t<CnConfirmDialog\n\t\t\tv-if=\"restoreEntry\"\n\t\t\tref=\"restoreDialog\"\n\t\t\t:dialogTitle=\"restoreLabel + '?'\"\n\t\t\t:message=\"restoreMessage\"\n\t\t\t:confirmLabel=\"restoreLabel\"\n\t\t\t:successText=\"restoredLabel\"\n\t\t\t@confirm=\"confirmRestore\"\n\t\t\t@close=\"restoreEntry = null\" />\n\t</div>\n</template>\n\n<script>\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcDateTimePickerNative, NcListItem, NcLoadingIcon, NcSelect } from '@nextcloud/vue'\nimport History from 'vue-material-design-icons/History.vue'\nimport CnConfirmDialog from '../../dialogs/CnConfirmDialog.vue'\nimport { useRestoreVersion } from '../../composables/useRestoreVersion.js'\nimport { buildHeaders } from '../../utils/index.js'\nimport { isLockedByCurrentUser, isObjectLocked, lockHolder } from '../../utils/objectLock.js'\n\nexport default {\n\tname: 'CnAuditTrailTab',\n\n\tcomponents: { CnConfirmDialog, NcButton, NcListItem, NcLoadingIcon, NcSelect, NcDateTimePickerNative, History },\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Text shown when there are no audit trail entries */\n\t\tnoAuditTrailLabel: { type: String, default: () => t('nextcloud-vue', 'No audit trail entries') },\n\t\t/** Text shown when no entries match the current filter */\n\t\tnoMatchLabel: { type: String, default: () => t('nextcloud-vue', 'No matching entries') },\n\t\t/** Label for the action filter control */\n\t\tactionFilterLabel: { type: String, default: () => t('nextcloud-vue', 'Action') },\n\t\t/** Label for the user filter control */\n\t\tuserFilterLabel: { type: String, default: () => t('nextcloud-vue', 'User') },\n\t\t/** Label for the date-from filter */\n\t\tfromLabel: { type: String, default: () => t('nextcloud-vue', 'From') },\n\t\t/** Label for the date-to filter */\n\t\ttoLabel: { type: String, default: () => t('nextcloud-vue', 'To') },\n\t\t/** Label for the load-more button */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/**\n\t\t * Offer \"Restore this version\" on an expanded create or update entry.\n\t\t * Off by default: a tab rendered without it shows no button.\n\t\t */\n\t\tallowRestore: { type: Boolean, default: false },\n\t\t/**\n\t\t * The record as the page holds it. Read for `@self.actions` (the button\n\t\t * is hidden when the reader may not update) and for the lock.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: { type: Object, default: null },\n\t},\n\n\temits: ['restored'],\n\n\tdata() {\n\t\treturn {\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\texpandedId: null,\n\t\t\tfilterAction: [],\n\t\t\tfilterUser: [],\n\t\t\tfilterDateFrom: null,\n\t\t\tfilterDateTo: null,\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tlimit: 20,\n\t\t\tactionOptions: ['create', 'read', 'update', 'delete'],\n\t\t\tuserOptions: [],\n\t\t\trestoreEntry: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\thasMore() {\n\t\t\treturn this.entries.length < this.total\n\t\t},\n\n\t\t/** Whether the record's lock belongs to somebody else. */\n\t\trestoreBlocked() {\n\t\t\treturn isObjectLocked(this.objectData) && !isLockedByCurrentUser(this.objectData)\n\t\t},\n\n\t\trestoreLabel() {\n\t\t\treturn t('nextcloud-vue', 'Restore this version')\n\t\t},\n\n\t\trestoredLabel() {\n\t\t\treturn t('nextcloud-vue', 'The record was restored.')\n\t\t},\n\n\t\trestoreLockedLabel() {\n\t\t\tconst holder = lockHolder(this.objectData)\n\t\t\treturn holder\n\t\t\t\t? t('nextcloud-vue', 'This record is locked by {name}.', { name: holder })\n\t\t\t\t: t('nextcloud-vue', 'This record is locked by someone else.')\n\t\t},\n\n\t\t/** The confirm text: which entry, and that nothing is removed. */\n\t\trestoreMessage() {\n\t\t\tif (!this.restoreEntry) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Restore the record to how it was after the change by {user} on {date}? This is saved as a new version and nothing is removed.', {\n\t\t\t\tuser: this.restoreEntry.userName || this.restoreEntry.user || 'System',\n\t\t\t\tdate: this.formatDate(this.restoreEntry.created),\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchAuditTrails()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tfilterAction() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterUser() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterDateFrom() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterDateTo() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tresetAndFetch() {\n\t\t\tthis.page = 1\n\t\t\tthis.entries = []\n\t\t\tthis.fetchAuditTrails()\n\t\t},\n\n\t\tbuildQueryParams() {\n\t\t\tconst params = new URLSearchParams()\n\t\t\tparams.set('limit', this.limit)\n\t\t\tparams.set('_page', this.page)\n\t\t\tparams.set('_sort[created]', 'DESC')\n\t\t\tif (this.filterAction?.length) {\n\t\t\t\tparams.set('action', this.filterAction.join(','))\n\t\t\t}\n\t\t\tif (this.filterUser?.length) {\n\t\t\t\tparams.set('user_name', this.filterUser.join(','))\n\t\t\t}\n\t\t\tif (this.filterDateFrom) {\n\t\t\t\tparams.set('_dateFrom', new Date(this.filterDateFrom).toISOString().split('T')[0])\n\t\t\t}\n\t\t\tif (this.filterDateTo) {\n\t\t\t\tparams.set('_dateTo', new Date(this.filterDateTo).toISOString().split('T')[0])\n\t\t\t}\n\t\t\treturn params.toString()\n\t\t},\n\n\t\tasync fetchAuditTrails() {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = this.page === 1\n\t\t\tthis.loadingMore = this.page > 1\n\t\t\ttry {\n\t\t\t\tconst query = this.buildQueryParams()\n\t\t\t\t// generateUrl prepends the Nextcloud webroot + `/index.php` so the\n\t\t\t\t// request resolves on instances without URL rewriting.\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails`)\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\t`${url}?${query}`,\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst results = data.results || data || []\n\t\t\t\t\tif (this.page === 1) {\n\t\t\t\t\t\tthis.entries = results\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.entries = [...this.entries, ...results]\n\t\t\t\t\t}\n\t\t\t\t\tthis.total = data.total || this.entries.length\n\t\t\t\t\t// Build user options from all seen entries\n\t\t\t\t\tconst users = new Set(this.entries.map((e) => e.userName || e.user).filter(Boolean))\n\t\t\t\t\tthis.userOptions = [...users].sort()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnAuditTrailTab: Failed to fetch audit trails', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.loadingMore = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an entry shows the restore button.\n\t\t *\n\t\t * @param {object} entry The audit-trail entry.\n\t\t * @return {boolean} True for a create or update entry when restore is allowed and the reader may update.\n\t\t */\n\t\tcanRestore(entry) {\n\t\t\tif (!this.allowRestore || !['create', 'update'].includes(entry.action)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst actions = this.objectData?.['@self']?.actions\n\t\t\treturn !Array.isArray(actions) || actions.includes('update')\n\t\t},\n\n\t\t/**\n\t\t * Open the confirm dialog for an entry.\n\t\t *\n\t\t * @param {object} entry The audit-trail entry to restore to.\n\t\t */\n\t\taskRestore(entry) {\n\t\t\tif (!this.restoreBlocked) {\n\t\t\t\tthis.restoreEntry = entry\n\t\t\t}\n\t\t},\n\n\t\t/** Call the revert route for the chosen entry and report back to the dialog. */\n\t\tasync confirmRestore() {\n\t\t\tconst entry = this.restoreEntry\n\t\t\tconst { restore } = useRestoreVersion({ apiBase: this.apiBase })\n\t\t\tconst result = await restore({\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tauditTrailId: entry.id,\n\t\t\t\tobject: this.objectData,\n\t\t\t})\n\t\t\tif (result.ok) {\n\t\t\t\tthis.page = 1\n\t\t\t\tthis.entries = []\n\t\t\t\tawait this.fetchAuditTrails()\n\t\t\t\t/**\n\t\t\t\t * @event restored Emitted with the restored record after a successful restore.\n\t\t\t\t * @type {object|null}\n\t\t\t\t */\n\t\t\t\tthis.$emit('restored', result.record)\n\t\t\t\temit('cn:page:refresh')\n\t\t\t} else if (result.status === 423) {\n\t\t\t\t// Re-read the record so the page shows the lock.\n\t\t\t\temit('cn:page:refresh')\n\t\t\t}\n\t\t\tthis.$refs.restoreDialog?.setResult(result.ok ? { success: true } : { error: result.message })\n\t\t},\n\n\t\tloadMore() {\n\t\t\tthis.page++\n\t\t\tthis.fetchAuditTrails()\n\t\t},\n\n\t\ttoggleExpand(id) {\n\t\t\tthis.expandedId = this.expandedId === id ? null : id\n\t\t},\n\n\t\tchangedCount(entry) {\n\t\t\tif (!entry.changed || typeof entry.changed !== 'object') {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Object.keys(entry.changed).length\n\t\t},\n\n\t\tisSimpleValue(change) {\n\t\t\treturn change && typeof change === 'object' && ('old' in change || 'new' in change)\n\t\t},\n\n\t\tformatValue(val) {\n\t\t\tif (val === null || val === undefined) {\n\t\t\t\treturn 'null'\n\t\t\t}\n\t\t\tif (typeof val === 'object') {\n\t\t\t\treturn JSON.stringify(val)\n\t\t\t}\n\t\t\treturn String(val)\n\t\t},\n\n\t\tformatDate(dateStr) {\n\t\t\tif (!dateStr) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(dateStr).toLocaleString(undefined, {\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\thour: '2-digit',\n\t\t\t\t\tminute: '2-digit',\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn dateStr\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; }\n\n.cn-audit-filters {\n\tdisplay: grid;\n\tgrid-template-columns: 1fr 1fr;\n\tgap: 8px;\n\tmargin-bottom: 12px;\n}\n\n.cn-audit-filters__select { min-width: 0; }\n\n.cn-audit-filters__date { min-width: 0; }\n\n.cn-sidebar-tab__load-more { margin-top: 8px; }\n\n.cn-audit-entry { cursor: pointer; }\n\n.cn-audit-details {\n\tpadding: 8px 12px 12px 52px;\n\tfont-size: 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tanimation: cn-slide-down 0.15s ease;\n}\n\n@keyframes cn-slide-down {\n\tfrom { opacity: 0; max-height: 0; }\n\tto { opacity: 1; max-height: 600px; }\n}\n\n.cn-audit-details__restore { margin: 8px 0; }\n\n.cn-audit-details__row {\n\tdisplay: flex;\n\tgap: 8px;\n\tpadding: 2px 0;\n}\n\n.cn-audit-details__label {\n\tcolor: var(--color-text-maxcontrast);\n\tmin-width: 56px;\n\tfont-weight: 500;\n}\n\n.cn-audit-details__mono {\n\tfont-family: monospace;\n\tfont-size: 11px;\n\tword-break: break-all;\n}\n\n.cn-audit-details__changes {\n\tmargin-top: 8px;\n\tpadding-top: 8px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-audit-details__change {\n\tpadding: 4px 0 4px 8px;\n\tborder-left: 2px solid var(--color-border);\n\tmargin: 4px 0;\n}\n\n.cn-audit-details__field {\n\tfont-weight: 500;\n\tdisplay: block;\n\tmargin-bottom: 2px;\n}\n\n.cn-audit-details__values {\n\tdisplay: flex;\n\tgap: 6px;\n\talign-items: baseline;\n\tflex-wrap: wrap;\n}\n\n.cn-audit-details__old {\n\tcolor: var(--color-error, #e53935);\n\ttext-decoration: line-through;\n}\n\n.cn-audit-details__arrow {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-audit-details__new {\n\tcolor: var(--color-success, #43a047);\n}\n\n.cn-audit-details__null {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-style: italic;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createBlock","_Fragment","_createElementVNode","_createVNode","_toDisplayString","_renderList","_createTextVNode","_withModifiers"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnAuditTrailTab.vue3.js","sources":["../../../../src/components/CnObjectSidebar/CnAuditTrailTab.vue?vue&type=template&id=1f3f9f5d&lang.js"],"sourcesContent":["<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<template v-else-if=\"entries.length > 0\">\n\t\t\t<!-- Filters -->\n\t\t\t<div class=\"cn-audit-filters\">\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"filterAction\"\n\t\t\t\t\t:options=\"actionOptions\"\n\t\t\t\t\t:placeholder=\"actionFilterLabel\"\n\t\t\t\t\t:inputLabel=\"actionFilterLabel\"\n\t\t\t\t\t:multiple=\"true\"\n\t\t\t\t\t:keepOpen=\"true\"\n\t\t\t\t\tclass=\"cn-audit-filters__select\" />\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"filterUser\"\n\t\t\t\t\t:options=\"userOptions\"\n\t\t\t\t\t:placeholder=\"userFilterLabel\"\n\t\t\t\t\t:inputLabel=\"userFilterLabel\"\n\t\t\t\t\t:multiple=\"true\"\n\t\t\t\t\t:keepOpen=\"true\"\n\t\t\t\t\tclass=\"cn-audit-filters__select\" />\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tid=\"audit-date-from\"\n\t\t\t\t\tv-model=\"filterDateFrom\"\n\t\t\t\t\t:label=\"fromLabel\"\n\t\t\t\t\ttype=\"date\"\n\t\t\t\t\tclass=\"cn-audit-filters__date\" />\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tid=\"audit-date-to\"\n\t\t\t\t\tv-model=\"filterDateTo\"\n\t\t\t\t\t:label=\"toLabel\"\n\t\t\t\t\ttype=\"date\"\n\t\t\t\t\tclass=\"cn-audit-filters__date\" />\n\t\t\t</div>\n\n\t\t\t<div v-if=\"entries.length === 0 && !loading\" class=\"cn-sidebar-tab__empty\">\n\t\t\t\t{{ noMatchLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-sidebar-tab__list\">\n\t\t\t\t<div v-for=\"entry in entries\" :key=\"entry.id\" class=\"cn-audit-entry\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\t:name=\"formatDate(entry.created)\"\n\t\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t\t:details=\"entry.action\"\n\t\t\t\t\t\t:counterNumber=\"changedCount(entry)\"\n\t\t\t\t\t\t@click=\"toggleExpand(entry.id)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<History :size=\"32\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t{{ entry.userName || entry.user || 'System' }}\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t\t<!-- Expandable details -->\n\t\t\t\t\t<div v-if=\"expandedId === entry.id\" class=\"cn-audit-details\">\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Action</span>\n\t\t\t\t\t\t\t<span>{{ entry.action }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">User</span>\n\t\t\t\t\t\t\t<span>{{ entry.userName || entry.user || 'System' }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Date</span>\n\t\t\t\t\t\t\t<span>{{ formatDate(entry.created) }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"entry.ipAddress\" class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">IP</span>\n\t\t\t\t\t\t\t<span>{{ entry.ipAddress }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"entry.session\" class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Session</span>\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__mono\">{{ entry.session }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- Restore (allowRestore only; create and update entries) -->\n\t\t\t\t\t\t<div v-if=\"canRestore(entry)\" class=\"cn-audit-details__restore\">\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t\t:disabled=\"restoreBlocked\"\n\t\t\t\t\t\t\t\t:title=\"restoreBlocked ? restoreLockedLabel : undefined\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-audit-restore\"\n\t\t\t\t\t\t\t\t@click.stop=\"askRestore(entry)\">\n\t\t\t\t\t\t\t\t{{ restoreLabel }}\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- Changed fields -->\n\t\t\t\t\t\t<div v-if=\"entry.changed && Object.keys(entry.changed).length > 0\" class=\"cn-audit-details__changes\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Changes</span>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tv-for=\"(change, field) in entry.changed\"\n\t\t\t\t\t\t\t\t:key=\"field\"\n\t\t\t\t\t\t\t\tclass=\"cn-audit-details__change\">\n\t\t\t\t\t\t\t\t<span class=\"cn-audit-details__field\">{{ field }}</span>\n\t\t\t\t\t\t\t\t<div v-if=\"isSimpleValue(change)\" class=\"cn-audit-details__values\">\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old !== null && change.old !== undefined\" class=\"cn-audit-details__old\">{{ formatValue(change.old) }}</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old !== null && change.new !== null\" class=\"cn-audit-details__arrow\">→</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.new !== null && change.new !== undefined\" class=\"cn-audit-details__new\">{{ formatValue(change.new) }}</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old === null && change.new === null\" class=\"cn-audit-details__null\">null</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div v-else class=\"cn-audit-details__values\">\n\t\t\t\t\t\t\t\t\t<span class=\"cn-audit-details__mono\">{{ formatValue(change) }}</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<!-- Load more -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"hasMore\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:wide=\"true\"\n\t\t\t\t\t:disabled=\"loadingMore\"\n\t\t\t\t\tclass=\"cn-sidebar-tab__load-more\"\n\t\t\t\t\t@click=\"loadMore\">\n\t\t\t\t\t<template v-if=\"loadingMore\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ loadMoreLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</template>\n\t\t<div v-else class=\"cn-sidebar-tab__empty\">\n\t\t\t{{ noAuditTrailLabel }}\n\t\t</div>\n\t\t<CnConfirmDialog\n\t\t\tv-if=\"restoreEntry\"\n\t\t\tref=\"restoreDialog\"\n\t\t\t:dialogTitle=\"restoreLabel + '?'\"\n\t\t\t:message=\"restoreMessage\"\n\t\t\t:confirmLabel=\"restoreLabel\"\n\t\t\t:successText=\"restoredLabel\"\n\t\t\t@confirm=\"confirmRestore\"\n\t\t\t@close=\"restoreEntry = null\" />\n\t</div>\n</template>\n\n<script>\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcDateTimePickerNative, NcListItem, NcLoadingIcon, NcSelect } from '@nextcloud/vue'\nimport History from 'vue-material-design-icons/History.vue'\nimport CnConfirmDialog from '../../dialogs/CnConfirmDialog.vue'\nimport { useRestoreVersion } from '../../composables/useRestoreVersion.js'\nimport { buildHeaders } from '../../utils/index.js'\nimport { isLockedByCurrentUser, isObjectLocked, lockHolder } from '../../utils/objectLock.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\nexport default {\n\tname: 'CnAuditTrailTab',\n\n\tcomponents: { CnConfirmDialog, NcButton, NcListItem, NcLoadingIcon, NcSelect, NcDateTimePickerNative, History },\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Text shown when there are no audit trail entries */\n\t\tnoAuditTrailLabel: { type: String, default: () => t('nextcloud-vue', 'No audit trail entries') },\n\t\t/** Text shown when no entries match the current filter */\n\t\tnoMatchLabel: { type: String, default: () => t('nextcloud-vue', 'No matching entries') },\n\t\t/** Label for the action filter control */\n\t\tactionFilterLabel: { type: String, default: () => t('nextcloud-vue', 'Action') },\n\t\t/** Label for the user filter control */\n\t\tuserFilterLabel: { type: String, default: () => t('nextcloud-vue', 'User') },\n\t\t/** Label for the date-from filter */\n\t\tfromLabel: { type: String, default: () => t('nextcloud-vue', 'From') },\n\t\t/** Label for the date-to filter */\n\t\ttoLabel: { type: String, default: () => t('nextcloud-vue', 'To') },\n\t\t/** Label for the load-more button */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/**\n\t\t * Offer \"Restore this version\" on an expanded create or update entry.\n\t\t * Off by default: a tab rendered without it shows no button.\n\t\t */\n\t\tallowRestore: { type: Boolean, default: false },\n\t\t/**\n\t\t * The record as the page holds it. Read for `@self.actions` (the button\n\t\t * is hidden when the reader may not update) and for the lock.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: { type: Object, default: null },\n\t},\n\n\temits: ['restored'],\n\n\tdata() {\n\t\treturn {\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\texpandedId: null,\n\t\t\tfilterAction: [],\n\t\t\tfilterUser: [],\n\t\t\tfilterDateFrom: null,\n\t\t\tfilterDateTo: null,\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tlimit: 20,\n\t\t\tactionOptions: ['create', 'read', 'update', 'delete'],\n\t\t\tuserOptions: [],\n\t\t\trestoreEntry: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\thasMore() {\n\t\t\treturn this.entries.length < this.total\n\t\t},\n\n\t\t/** Whether the record's lock belongs to somebody else. */\n\t\trestoreBlocked() {\n\t\t\treturn isObjectLocked(this.objectData) && !isLockedByCurrentUser(this.objectData)\n\t\t},\n\n\t\trestoreLabel() {\n\t\t\treturn t('nextcloud-vue', 'Restore this version')\n\t\t},\n\n\t\trestoredLabel() {\n\t\t\treturn t('nextcloud-vue', 'The record was restored.')\n\t\t},\n\n\t\trestoreLockedLabel() {\n\t\t\tconst holder = lockHolder(this.objectData)\n\t\t\treturn holder\n\t\t\t\t? t('nextcloud-vue', 'This record is locked by {name}.', { name: holder })\n\t\t\t\t: t('nextcloud-vue', 'This record is locked by someone else.')\n\t\t},\n\n\t\t/** The confirm text: which entry, and that nothing is removed. */\n\t\trestoreMessage() {\n\t\t\tif (!this.restoreEntry) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Restore the record to how it was after the change by {user} on {date}? This is saved as a new version and nothing is removed.', {\n\t\t\t\tuser: this.restoreEntry.userName || this.restoreEntry.user || 'System',\n\t\t\t\tdate: this.formatDate(this.restoreEntry.created),\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchAuditTrails()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tfilterAction() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterUser() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterDateFrom() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterDateTo() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tresetAndFetch() {\n\t\t\tthis.page = 1\n\t\t\tthis.entries = []\n\t\t\tthis.fetchAuditTrails()\n\t\t},\n\n\t\tbuildQueryParams() {\n\t\t\tconst params = new URLSearchParams()\n\t\t\tparams.set('limit', this.limit)\n\t\t\tparams.set('_page', this.page)\n\t\t\tparams.set('_sort[created]', 'DESC')\n\t\t\tif (this.filterAction?.length) {\n\t\t\t\tparams.set('action', this.filterAction.join(','))\n\t\t\t}\n\t\t\tif (this.filterUser?.length) {\n\t\t\t\tparams.set('user_name', this.filterUser.join(','))\n\t\t\t}\n\t\t\tif (this.filterDateFrom) {\n\t\t\t\tparams.set('_dateFrom', new Date(this.filterDateFrom).toISOString().split('T')[0])\n\t\t\t}\n\t\t\tif (this.filterDateTo) {\n\t\t\t\tparams.set('_dateTo', new Date(this.filterDateTo).toISOString().split('T')[0])\n\t\t\t}\n\t\t\treturn params.toString()\n\t\t},\n\n\t\tasync fetchAuditTrails() {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = this.page === 1\n\t\t\tthis.loadingMore = this.page > 1\n\t\t\ttry {\n\t\t\t\tconst query = this.buildQueryParams()\n\t\t\t\t// generateUrl prepends the Nextcloud webroot + `/index.php` so the\n\t\t\t\t// request resolves on instances without URL rewriting.\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails`)\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\t`${url}?${query}`,\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst results = data.results || data || []\n\t\t\t\t\tif (this.page === 1) {\n\t\t\t\t\t\tthis.entries = results\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.entries = [...this.entries, ...results]\n\t\t\t\t\t}\n\t\t\t\t\tthis.total = data.total || this.entries.length\n\t\t\t\t\t// Build user options from all seen entries\n\t\t\t\t\tconst users = new Set(this.entries.map((e) => e.userName || e.user).filter(Boolean))\n\t\t\t\t\tthis.userOptions = [...users].sort()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnAuditTrailTab: Failed to fetch audit trails', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.loadingMore = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an entry shows the restore button.\n\t\t *\n\t\t * @param {object} entry The audit-trail entry.\n\t\t * @return {boolean} True for a create or update entry when restore is allowed and the reader may update.\n\t\t */\n\t\tcanRestore(entry) {\n\t\t\tif (!this.allowRestore || !['create', 'update'].includes(entry.action)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst actions = this.objectData?.['@self']?.actions\n\t\t\treturn !Array.isArray(actions) || actions.includes('update')\n\t\t},\n\n\t\t/**\n\t\t * Open the confirm dialog for an entry.\n\t\t *\n\t\t * @param {object} entry The audit-trail entry to restore to.\n\t\t */\n\t\taskRestore(entry) {\n\t\t\tif (!this.restoreBlocked) {\n\t\t\t\tthis.restoreEntry = entry\n\t\t\t}\n\t\t},\n\n\t\t/** Call the revert route for the chosen entry and report back to the dialog. */\n\t\tasync confirmRestore() {\n\t\t\tconst entry = this.restoreEntry\n\t\t\tconst { restore } = useRestoreVersion({ apiBase: this.apiBase })\n\t\t\tconst result = await restore({\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tauditTrailId: entry.id,\n\t\t\t\tobject: this.objectData,\n\t\t\t})\n\t\t\tif (result.ok) {\n\t\t\t\tthis.page = 1\n\t\t\t\tthis.entries = []\n\t\t\t\tawait this.fetchAuditTrails()\n\t\t\t\t/**\n\t\t\t\t * @event restored Emitted with the restored record after a successful restore.\n\t\t\t\t * @type {object|null}\n\t\t\t\t */\n\t\t\t\tthis.$emit('restored', result.record)\n\t\t\t\temit('cn:page:refresh')\n\t\t\t} else if (result.status === 423) {\n\t\t\t\t// Re-read the record so the page shows the lock.\n\t\t\t\temit('cn:page:refresh')\n\t\t\t}\n\t\t\tthis.$refs.restoreDialog?.setResult(result.ok ? { success: true } : { error: result.message })\n\t\t},\n\n\t\tloadMore() {\n\t\t\tthis.page++\n\t\t\tthis.fetchAuditTrails()\n\t\t},\n\n\t\ttoggleExpand(id) {\n\t\t\tthis.expandedId = this.expandedId === id ? null : id\n\t\t},\n\n\t\tchangedCount(entry) {\n\t\t\tif (!entry.changed || typeof entry.changed !== 'object') {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Object.keys(entry.changed).length\n\t\t},\n\n\t\tisSimpleValue(change) {\n\t\t\treturn change && typeof change === 'object' && ('old' in change || 'new' in change)\n\t\t},\n\n\t\tformatValue(val) {\n\t\t\tif (val === null || val === undefined) {\n\t\t\t\treturn 'null'\n\t\t\t}\n\t\t\tif (typeof val === 'object') {\n\t\t\t\treturn JSON.stringify(val)\n\t\t\t}\n\t\t\treturn String(val)\n\t\t},\n\n\t\tformatDate(dateStr) {\n\t\t\tif (!dateStr) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(dateStr).toLocaleString(userLocale(), {\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\thour: '2-digit',\n\t\t\t\t\tminute: '2-digit',\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn dateStr\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; }\n\n.cn-audit-filters {\n\tdisplay: grid;\n\tgrid-template-columns: 1fr 1fr;\n\tgap: 8px;\n\tmargin-bottom: 12px;\n}\n\n.cn-audit-filters__select { min-width: 0; }\n\n.cn-audit-filters__date { min-width: 0; }\n\n.cn-sidebar-tab__load-more { margin-top: 8px; }\n\n.cn-audit-entry { cursor: pointer; }\n\n.cn-audit-details {\n\tpadding: 8px 12px 12px 52px;\n\tfont-size: 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tanimation: cn-slide-down 0.15s ease;\n}\n\n@keyframes cn-slide-down {\n\tfrom { opacity: 0; max-height: 0; }\n\tto { opacity: 1; max-height: 600px; }\n}\n\n.cn-audit-details__restore { margin: 8px 0; }\n\n.cn-audit-details__row {\n\tdisplay: flex;\n\tgap: 8px;\n\tpadding: 2px 0;\n}\n\n.cn-audit-details__label {\n\tcolor: var(--color-text-maxcontrast);\n\tmin-width: 56px;\n\tfont-weight: 500;\n}\n\n.cn-audit-details__mono {\n\tfont-family: monospace;\n\tfont-size: 11px;\n\tword-break: break-all;\n}\n\n.cn-audit-details__changes {\n\tmargin-top: 8px;\n\tpadding-top: 8px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-audit-details__change {\n\tpadding: 4px 0 4px 8px;\n\tborder-left: 2px solid var(--color-border);\n\tmargin: 4px 0;\n}\n\n.cn-audit-details__field {\n\tfont-weight: 500;\n\tdisplay: block;\n\tmargin-bottom: 2px;\n}\n\n.cn-audit-details__values {\n\tdisplay: flex;\n\tgap: 6px;\n\talign-items: baseline;\n\tflex-wrap: wrap;\n}\n\n.cn-audit-details__old {\n\tcolor: var(--color-error, #e53935);\n\ttext-decoration: line-through;\n}\n\n.cn-audit-details__arrow {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-audit-details__new {\n\tcolor: var(--color-success, #43a047);\n}\n\n.cn-audit-details__null {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-style: italic;\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createBlock","_Fragment","_createElementVNode","_createVNode","_toDisplayString","_renderList","_createTextVNode","_withModifiers"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnFlowTasksPanel.vue2.js';
|
|
|
2
2
|
import { render } from './CnFlowTasksPanel.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-06a42055";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -4,6 +4,7 @@ import { taskDeepLink, taskDueLabel } from '../../composables/indexSources.js';
|
|
|
4
4
|
import { useTaskInboxStore } from '../../composables/useTaskInboxStore.js';
|
|
5
5
|
import { searchGroupSharees } from '../../utils/searchGroupSharees.js';
|
|
6
6
|
import { searchNextcloudUsers } from '../../utils/userAutocomplete.js';
|
|
7
|
+
import { userLocale } from '../../utils/userLocale.js';
|
|
7
8
|
|
|
8
9
|
/** The verbs this panel has a control for, in the order a row shows them. */
|
|
9
10
|
const VERBS = ['claim', 'unclaim', 'reassign', 'complete', 'cancel'];
|
|
@@ -125,7 +126,7 @@ var script = {
|
|
|
125
126
|
return label
|
|
126
127
|
}
|
|
127
128
|
const d = new Date(task.dueAt);
|
|
128
|
-
const date = Number.isNaN(d.getTime()) ? String(task.dueAt) : d.toLocaleDateString();
|
|
129
|
+
const date = Number.isNaN(d.getTime()) ? String(task.dueAt) : d.toLocaleDateString(userLocale());
|
|
129
130
|
return this.isOverdue(task) ? translate('nextcloud-vue', 'Overdue: {date}', { date }) : date
|
|
130
131
|
},
|
|
131
132
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnFlowTasksPanel.vue2.js","sources":["../../../../src/components/CnObjectSidebar/CnFlowTasksPanel.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-flow-tasks\" data-testid=\"cn-flow-tasks-panel\">\n\t\t<!-- Create a task on the record -->\n\t\t<form class=\"cn-sidebar-tab__section\" data-testid=\"cn-flow-tasks-form\" @submit.prevent=\"addTask\">\n\t\t\t<NcTextField\n\t\t\t\tv-model=\"title\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Add task…')\"\n\t\t\t\tdata-testid=\"cn-flow-tasks-title\" />\n\t\t\t<div class=\"cn-sidebar-tab__grid\">\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tv-model=\"due\"\n\t\t\t\t\t:label=\"t('nextcloud-vue', 'Deadline')\"\n\t\t\t\t\ttype=\"date\" />\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"assignee\"\n\t\t\t\t\t:options=\"assigneeOptions\"\n\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Assignee')\"\n\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Assignee')\"\n\t\t\t\t\t:loading=\"searching\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\tdata-testid=\"cn-flow-tasks-assignee\"\n\t\t\t\t\t@search=\"searchAssignees\" />\n\t\t\t</div>\n\t\t\t<NcTextField\n\t\t\t\tv-model=\"description\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Description')\" />\n\t\t\t<NcNoteCard v-if=\"formError\" type=\"error\" data-testid=\"cn-flow-tasks-form-error\">\n\t\t\t\t{{ formError }}\n\t\t\t</NcNoteCard>\n\t\t\t<NcButton\n\t\t\t\ttype=\"submit\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!title.trim() || saving\"\n\t\t\t\tdata-testid=\"cn-flow-tasks-add\">\n\t\t\t\t{{ t('nextcloud-vue', 'Add task') }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t<template v-else>\n\t\t\t<p v-if=\"openTasks.length === 0 && doneTasks.length === 0\" class=\"cn-sidebar-tab__empty\" data-testid=\"cn-flow-tasks-empty\">\n\t\t\t\t{{ t('nextcloud-vue', 'No tasks on this record yet. Personal reminders live in the Integrations tab.') }}\n\t\t\t</p>\n\n\t\t\t<ul v-if=\"openTasks.length > 0\" class=\"cn-flow-tasks__list\" data-testid=\"cn-flow-tasks-open\">\n\t\t\t\t<li v-for=\"task in openTasks\"\n\t\t\t\t\t:key=\"uuidOf(task)\"\n\t\t\t\t\tclass=\"cn-flow-tasks__row\"\n\t\t\t\t\t:data-task=\"uuidOf(task)\">\n\t\t\t\t\t<a :href=\"deepLink(task)\" class=\"cn-flow-tasks__title\">{{ task.title }}</a>\n\t\t\t\t\t<span class=\"cn-flow-tasks__meta\">{{ whoOf(task) }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"task.dueAt\"\n\t\t\t\t\t\tclass=\"cn-flow-tasks__due\"\n\t\t\t\t\t\t:class=\"{ 'cn-flow-tasks__due--overdue': isOverdue(task) }\"\n\t\t\t\t\t\tdata-testid=\"cn-flow-tasks-due\">\n\t\t\t\t\t\t{{ dueText(task) }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-flow-tasks__state\">{{ stateText(task) }}</span>\n\t\t\t\t\t<span class=\"cn-flow-tasks__verbs\">\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-for=\"verb in verbsOf(task)\"\n\t\t\t\t\t\t\t:key=\"verb\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t:disabled=\"busy === uuidOf(task)\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-flow-tasks-verb-${verb}`\"\n\t\t\t\t\t\t\t@click=\"onVerb(task, verb)\">\n\t\t\t\t\t\t\t{{ verbLabel(verb) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</span>\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\tv-if=\"reassigning === uuidOf(task)\"\n\t\t\t\t\t\t:options=\"userOptions\"\n\t\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Reassign to')\"\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-flow-tasks-reassign-picker\"\n\t\t\t\t\t\t@search=\"searchUsers\"\n\t\t\t\t\t\t@update:modelValue=\"(option) => reassign(task, option)\" />\n\t\t\t\t\t<p v-if=\"rowErrors[uuidOf(task)]\"\n\t\t\t\t\t\tclass=\"cn-flow-tasks__error\"\n\t\t\t\t\t\trole=\"alert\"\n\t\t\t\t\t\tdata-testid=\"cn-flow-tasks-row-error\">\n\t\t\t\t\t\t{{ rowErrors[uuidOf(task)] }}\n\t\t\t\t\t</p>\n\t\t\t\t</li>\n\t\t\t</ul>\n\n\t\t\t<div v-if=\"doneTasks.length > 0\" class=\"cn-flow-tasks__done\">\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:aria-expanded=\"doneOpen ? 'true' : 'false'\"\n\t\t\t\t\tdata-testid=\"cn-flow-tasks-done-toggle\"\n\t\t\t\t\t@click=\"doneOpen = !doneOpen\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Done ({count})', { count: doneTasks.length }) }}\n\t\t\t\t</NcButton>\n\t\t\t\t<ul v-if=\"doneOpen\" class=\"cn-flow-tasks__list\" data-testid=\"cn-flow-tasks-done\">\n\t\t\t\t\t<li v-for=\"task in doneTasks\" :key=\"uuidOf(task)\" class=\"cn-flow-tasks__row\">\n\t\t\t\t\t\t<a :href=\"deepLink(task)\" class=\"cn-flow-tasks__title\">{{ task.title }}</a>\n\t\t\t\t\t\t<span class=\"cn-flow-tasks__state\">{{ stateText(task) }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcDateTimePickerNative, NcLoadingIcon, NcNoteCard, NcSelect, NcTextField } from '@nextcloud/vue'\nimport { taskDeepLink, taskDueLabel } from '../../composables/indexSources.js'\nimport { useTaskInboxStore } from '../../composables/useTaskInboxStore.js'\nimport { searchGroupSharees } from '../../utils/searchGroupSharees.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\n\n/** The verbs this panel has a control for, in the order a row shows them. */\nconst VERBS = ['claim', 'unclaim', 'reassign', 'complete', 'cancel']\n\n/** States after which a task is finished. */\nconst TERMINAL_STATES = ['completed', 'terminated', 'cancelled', 'canceled']\n\n/**\n * CnFlowTasksPanel — the `flow-tasks` source of `CnTasksTab`: the OpenRegister\n * flow tasks anchored on one record. Lists them (open ones first by due date,\n * finished ones folded under \"Done\", overdue marked), creates a task on the\n * record with an assignee (a user, or a group as a pool) and a due date, and\n * offers on each row exactly the verbs in the row's `can` list. A verb the\n * server refuses shows its message on the row and leaves the row unchanged.\n * Rendered by `CnTasksTab` when `source=\"flow-tasks\"`.\n */\nexport default {\n\tname: 'CnFlowTasksPanel',\n\n\tcomponents: { NcButton, NcDateTimePickerNative, NcLoadingIcon, NcNoteCard, NcSelect, NcTextField },\n\n\tprops: {\n\t\t/** Uuid of the record the tasks hang on. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Register of the record (sent as `registerId`). */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Schema of the record (sent as `schemaId`). */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['count'],\n\n\tdata() {\n\t\treturn {\n\t\t\ttasks: [],\n\t\t\tloading: false,\n\t\t\tsaving: false,\n\t\t\ttitle: '',\n\t\t\tdescription: '',\n\t\t\tdue: null,\n\t\t\tassignee: null,\n\t\t\tformError: '',\n\t\t\tassigneeOptions: [],\n\t\t\tuserOptions: [],\n\t\t\tsearching: false,\n\t\t\trowErrors: {},\n\t\t\tbusy: '',\n\t\t\treassigning: '',\n\t\t\tdoneOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\topenTasks() {\n\t\t\treturn this.tasks\n\t\t\t\t.filter((task) => !this.isFinished(task))\n\t\t\t\t.sort((a, b) => {\n\t\t\t\t\tconst left = a.dueAt ? new Date(a.dueAt).getTime() : Infinity\n\t\t\t\t\tconst right = b.dueAt ? new Date(b.dueAt).getTime() : Infinity\n\t\t\t\t\treturn left - right\n\t\t\t\t})\n\t\t},\n\n\t\tdoneTasks() {\n\t\t\treturn this.tasks.filter((task) => this.isFinished(task))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\n\t\topenTasks(list) {\n\t\t\t/** @event count Emitted with the number of open tasks, for the tab badge. */\n\t\t\tthis.$emit('count', list.length)\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tuuidOf(task) {\n\t\t\treturn String(task.uuid || task.id || '')\n\t\t},\n\n\t\tdeepLink(task) {\n\t\t\treturn taskDeepLink(this.uuidOf(task))\n\t\t},\n\n\t\tisFinished(task) {\n\t\t\treturn task.isTerminal === true || TERMINAL_STATES.includes(String(task.state || '').toLowerCase())\n\t\t},\n\n\t\tisOverdue(task) {\n\t\t\tif (task.overdue === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn !!task.dueAt && !this.isFinished(task) && new Date(task.dueAt).getTime() < Date.now()\n\t\t},\n\n\t\tdueText(task) {\n\t\t\tconst label = taskDueLabel(task)\n\t\t\tif (label !== '') {\n\t\t\t\treturn label\n\t\t\t}\n\t\t\tconst d = new Date(task.dueAt)\n\t\t\tconst date = Number.isNaN(d.getTime()) ? String(task.dueAt) : d.toLocaleDateString()\n\t\t\treturn this.isOverdue(task) ? t('nextcloud-vue', 'Overdue: {date}', { date }) : date\n\t\t},\n\n\t\tstateText(task) {\n\t\t\treturn String(task.state || '')\n\t\t},\n\n\t\twhoOf(task) {\n\t\t\tif (task.assignee) {\n\t\t\t\treturn task.assigneeName || task.assignee\n\t\t\t}\n\t\t\tconst groups = Array.isArray(task.candidateGroups) ? task.candidateGroups : []\n\t\t\treturn groups.length > 0 ? t('nextcloud-vue', 'Pool: {groups}', { groups: groups.join(', ') }) : t('nextcloud-vue', 'Unassigned')\n\t\t},\n\n\t\t/**\n\t\t * The verbs a row offers: exactly the ones in its `can` list that this\n\t\t * panel has a control for. Nothing is derived from state, assignee or\n\t\t * requester; a row without `can` offers none.\n\t\t *\n\t\t * @param {object} task The task row.\n\t\t * @return {string[]} The verbs, in display order.\n\t\t */\n\t\tverbsOf(task) {\n\t\t\tconst can = Array.isArray(task.can) ? task.can : []\n\t\t\treturn VERBS.filter((verb) => can.includes(verb))\n\t\t},\n\n\t\tverbLabel(verb) {\n\t\t\tconst labels = {\n\t\t\t\tclaim: t('nextcloud-vue', 'Claim'),\n\t\t\t\tunclaim: t('nextcloud-vue', 'Unclaim'),\n\t\t\t\treassign: t('nextcloud-vue', 'Reassign'),\n\t\t\t\tcomplete: t('nextcloud-vue', 'Complete'),\n\t\t\t\tcancel: t('nextcloud-vue', 'Cancel'),\n\t\t\t}\n\t\t\treturn labels[verb] || verb\n\t\t},\n\n\t\tasync load() {\n\t\t\tif (!this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst { results } = await useTaskInboxStore().fetchFor({ objectUuid: this.objectId, scope: 'all' })\n\t\t\t\tthis.tasks = results\n\t\t\t} catch (error) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnFlowTasksPanel] Loading the tasks failed', error)\n\t\t\t\tthis.tasks = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync searchAssignees(query) {\n\t\t\tthis.searching = true\n\t\t\tconst [users, groups] = await Promise.all([\n\t\t\t\tsearchNextcloudUsers(query || '', { limit: 10 }),\n\t\t\t\tsearchGroupSharees(query || '', { limit: 10 }),\n\t\t\t])\n\t\t\tthis.searching = false\n\t\t\tthis.assigneeOptions = [\n\t\t\t\t...users.map((u) => ({ kind: 'user', id: u.id, label: u.label || u.displayName || u.id })),\n\t\t\t\t...groups.map((g) => ({ kind: 'group', id: g.id, label: t('nextcloud-vue', '{name} (group)', { name: g.label }) })),\n\t\t\t]\n\t\t},\n\n\t\tasync searchUsers(query) {\n\t\t\tconst users = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tthis.userOptions = users.map((u) => ({ kind: 'user', id: u.id, label: u.label || u.displayName || u.id }))\n\t\t},\n\n\t\tasync addTask() {\n\t\t\tif (!this.title.trim() || this.saving) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.formError = ''\n\t\t\tconst result = await useTaskInboxStore().createTask({\n\t\t\t\ttitle: this.title,\n\t\t\t\tdescription: this.description,\n\t\t\t\tdueAt: this.due ? new Date(this.due).toISOString() : '',\n\t\t\t\tanchor: { objectUuid: this.objectId, registerId: this.register, schemaId: this.schema },\n\t\t\t\tassignee: this.assignee ? { kind: this.assignee.kind, id: this.assignee.id } : null,\n\t\t\t})\n\t\t\tthis.saving = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.formError = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer open this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'The task could not be created.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.title = ''\n\t\t\tthis.description = ''\n\t\t\tthis.due = null\n\t\t\tthis.assignee = null\n\t\t\tawait this.load()\n\t\t},\n\n\t\tasync onVerb(task, verb) {\n\t\t\tif (verb === 'reassign') {\n\t\t\t\tthis.reassigning = this.reassigning === this.uuidOf(task) ? '' : this.uuidOf(task)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.run(task, verb, {})\n\t\t},\n\n\t\tasync reassign(task, option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.reassigning = ''\n\t\t\tawait this.run(task, 'reassign', { assignee: option.id })\n\t\t},\n\n\t\tasync run(task, verb, body) {\n\t\t\tconst uuid = this.uuidOf(task)\n\t\t\tthis.busy = uuid\n\t\t\tthis.rowErrors = { ...this.rowErrors, [uuid]: '' }\n\t\t\tconst result = await useTaskInboxStore().runVerb(uuid, verb, body)\n\t\t\tthis.busy = ''\n\t\t\tif (!result.ok) {\n\t\t\t\t// The row stays exactly as it was, with the server's words on it.\n\t\t\t\tthis.rowErrors = { ...this.rowErrors, [uuid]: result.message || t('nextcloud-vue', 'The server refused this.') }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.load()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-flow-tasks__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-flow-tasks__row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 4px 8px;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-flow-tasks__title {\n\tflex: 1 1 100%;\n\tfont-weight: bold;\n}\n\n.cn-flow-tasks__meta,\n.cn-flow-tasks__state {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-flow-tasks__due--overdue {\n\tcolor: var(--color-error-text);\n\tfont-weight: bold;\n}\n\n.cn-flow-tasks__verbs {\n\tdisplay: inline-flex;\n\tgap: 4px;\n\tflex-wrap: wrap;\n}\n\n.cn-flow-tasks__error {\n\tflex: 1 1 100%;\n\tmargin: 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnFlowTasksPanel.vue2.js","sources":["../../../../src/components/CnObjectSidebar/CnFlowTasksPanel.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-flow-tasks\" data-testid=\"cn-flow-tasks-panel\">\n\t\t<!-- Create a task on the record -->\n\t\t<form class=\"cn-sidebar-tab__section\" data-testid=\"cn-flow-tasks-form\" @submit.prevent=\"addTask\">\n\t\t\t<NcTextField\n\t\t\t\tv-model=\"title\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Add task…')\"\n\t\t\t\tdata-testid=\"cn-flow-tasks-title\" />\n\t\t\t<div class=\"cn-sidebar-tab__grid\">\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tv-model=\"due\"\n\t\t\t\t\t:label=\"t('nextcloud-vue', 'Deadline')\"\n\t\t\t\t\ttype=\"date\" />\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"assignee\"\n\t\t\t\t\t:options=\"assigneeOptions\"\n\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Assignee')\"\n\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Assignee')\"\n\t\t\t\t\t:loading=\"searching\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\tdata-testid=\"cn-flow-tasks-assignee\"\n\t\t\t\t\t@search=\"searchAssignees\" />\n\t\t\t</div>\n\t\t\t<NcTextField\n\t\t\t\tv-model=\"description\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Description')\" />\n\t\t\t<NcNoteCard v-if=\"formError\" type=\"error\" data-testid=\"cn-flow-tasks-form-error\">\n\t\t\t\t{{ formError }}\n\t\t\t</NcNoteCard>\n\t\t\t<NcButton\n\t\t\t\ttype=\"submit\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!title.trim() || saving\"\n\t\t\t\tdata-testid=\"cn-flow-tasks-add\">\n\t\t\t\t{{ t('nextcloud-vue', 'Add task') }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t<template v-else>\n\t\t\t<p v-if=\"openTasks.length === 0 && doneTasks.length === 0\" class=\"cn-sidebar-tab__empty\" data-testid=\"cn-flow-tasks-empty\">\n\t\t\t\t{{ t('nextcloud-vue', 'No tasks on this record yet. Personal reminders live in the Integrations tab.') }}\n\t\t\t</p>\n\n\t\t\t<ul v-if=\"openTasks.length > 0\" class=\"cn-flow-tasks__list\" data-testid=\"cn-flow-tasks-open\">\n\t\t\t\t<li v-for=\"task in openTasks\"\n\t\t\t\t\t:key=\"uuidOf(task)\"\n\t\t\t\t\tclass=\"cn-flow-tasks__row\"\n\t\t\t\t\t:data-task=\"uuidOf(task)\">\n\t\t\t\t\t<a :href=\"deepLink(task)\" class=\"cn-flow-tasks__title\">{{ task.title }}</a>\n\t\t\t\t\t<span class=\"cn-flow-tasks__meta\">{{ whoOf(task) }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"task.dueAt\"\n\t\t\t\t\t\tclass=\"cn-flow-tasks__due\"\n\t\t\t\t\t\t:class=\"{ 'cn-flow-tasks__due--overdue': isOverdue(task) }\"\n\t\t\t\t\t\tdata-testid=\"cn-flow-tasks-due\">\n\t\t\t\t\t\t{{ dueText(task) }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-flow-tasks__state\">{{ stateText(task) }}</span>\n\t\t\t\t\t<span class=\"cn-flow-tasks__verbs\">\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-for=\"verb in verbsOf(task)\"\n\t\t\t\t\t\t\t:key=\"verb\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t:disabled=\"busy === uuidOf(task)\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-flow-tasks-verb-${verb}`\"\n\t\t\t\t\t\t\t@click=\"onVerb(task, verb)\">\n\t\t\t\t\t\t\t{{ verbLabel(verb) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</span>\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\tv-if=\"reassigning === uuidOf(task)\"\n\t\t\t\t\t\t:options=\"userOptions\"\n\t\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Reassign to')\"\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-flow-tasks-reassign-picker\"\n\t\t\t\t\t\t@search=\"searchUsers\"\n\t\t\t\t\t\t@update:modelValue=\"(option) => reassign(task, option)\" />\n\t\t\t\t\t<p v-if=\"rowErrors[uuidOf(task)]\"\n\t\t\t\t\t\tclass=\"cn-flow-tasks__error\"\n\t\t\t\t\t\trole=\"alert\"\n\t\t\t\t\t\tdata-testid=\"cn-flow-tasks-row-error\">\n\t\t\t\t\t\t{{ rowErrors[uuidOf(task)] }}\n\t\t\t\t\t</p>\n\t\t\t\t</li>\n\t\t\t</ul>\n\n\t\t\t<div v-if=\"doneTasks.length > 0\" class=\"cn-flow-tasks__done\">\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:aria-expanded=\"doneOpen ? 'true' : 'false'\"\n\t\t\t\t\tdata-testid=\"cn-flow-tasks-done-toggle\"\n\t\t\t\t\t@click=\"doneOpen = !doneOpen\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Done ({count})', { count: doneTasks.length }) }}\n\t\t\t\t</NcButton>\n\t\t\t\t<ul v-if=\"doneOpen\" class=\"cn-flow-tasks__list\" data-testid=\"cn-flow-tasks-done\">\n\t\t\t\t\t<li v-for=\"task in doneTasks\" :key=\"uuidOf(task)\" class=\"cn-flow-tasks__row\">\n\t\t\t\t\t\t<a :href=\"deepLink(task)\" class=\"cn-flow-tasks__title\">{{ task.title }}</a>\n\t\t\t\t\t\t<span class=\"cn-flow-tasks__state\">{{ stateText(task) }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcDateTimePickerNative, NcLoadingIcon, NcNoteCard, NcSelect, NcTextField } from '@nextcloud/vue'\nimport { taskDeepLink, taskDueLabel } from '../../composables/indexSources.js'\nimport { useTaskInboxStore } from '../../composables/useTaskInboxStore.js'\nimport { searchGroupSharees } from '../../utils/searchGroupSharees.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/** The verbs this panel has a control for, in the order a row shows them. */\nconst VERBS = ['claim', 'unclaim', 'reassign', 'complete', 'cancel']\n\n/** States after which a task is finished. */\nconst TERMINAL_STATES = ['completed', 'terminated', 'cancelled', 'canceled']\n\n/**\n * CnFlowTasksPanel — the `flow-tasks` source of `CnTasksTab`: the OpenRegister\n * flow tasks anchored on one record. Lists them (open ones first by due date,\n * finished ones folded under \"Done\", overdue marked), creates a task on the\n * record with an assignee (a user, or a group as a pool) and a due date, and\n * offers on each row exactly the verbs in the row's `can` list. A verb the\n * server refuses shows its message on the row and leaves the row unchanged.\n * Rendered by `CnTasksTab` when `source=\"flow-tasks\"`.\n */\nexport default {\n\tname: 'CnFlowTasksPanel',\n\n\tcomponents: { NcButton, NcDateTimePickerNative, NcLoadingIcon, NcNoteCard, NcSelect, NcTextField },\n\n\tprops: {\n\t\t/** Uuid of the record the tasks hang on. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Register of the record (sent as `registerId`). */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Schema of the record (sent as `schemaId`). */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['count'],\n\n\tdata() {\n\t\treturn {\n\t\t\ttasks: [],\n\t\t\tloading: false,\n\t\t\tsaving: false,\n\t\t\ttitle: '',\n\t\t\tdescription: '',\n\t\t\tdue: null,\n\t\t\tassignee: null,\n\t\t\tformError: '',\n\t\t\tassigneeOptions: [],\n\t\t\tuserOptions: [],\n\t\t\tsearching: false,\n\t\t\trowErrors: {},\n\t\t\tbusy: '',\n\t\t\treassigning: '',\n\t\t\tdoneOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\topenTasks() {\n\t\t\treturn this.tasks\n\t\t\t\t.filter((task) => !this.isFinished(task))\n\t\t\t\t.sort((a, b) => {\n\t\t\t\t\tconst left = a.dueAt ? new Date(a.dueAt).getTime() : Infinity\n\t\t\t\t\tconst right = b.dueAt ? new Date(b.dueAt).getTime() : Infinity\n\t\t\t\t\treturn left - right\n\t\t\t\t})\n\t\t},\n\n\t\tdoneTasks() {\n\t\t\treturn this.tasks.filter((task) => this.isFinished(task))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\n\t\topenTasks(list) {\n\t\t\t/** @event count Emitted with the number of open tasks, for the tab badge. */\n\t\t\tthis.$emit('count', list.length)\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tuuidOf(task) {\n\t\t\treturn String(task.uuid || task.id || '')\n\t\t},\n\n\t\tdeepLink(task) {\n\t\t\treturn taskDeepLink(this.uuidOf(task))\n\t\t},\n\n\t\tisFinished(task) {\n\t\t\treturn task.isTerminal === true || TERMINAL_STATES.includes(String(task.state || '').toLowerCase())\n\t\t},\n\n\t\tisOverdue(task) {\n\t\t\tif (task.overdue === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn !!task.dueAt && !this.isFinished(task) && new Date(task.dueAt).getTime() < Date.now()\n\t\t},\n\n\t\tdueText(task) {\n\t\t\tconst label = taskDueLabel(task)\n\t\t\tif (label !== '') {\n\t\t\t\treturn label\n\t\t\t}\n\t\t\tconst d = new Date(task.dueAt)\n\t\t\tconst date = Number.isNaN(d.getTime()) ? String(task.dueAt) : d.toLocaleDateString(userLocale())\n\t\t\treturn this.isOverdue(task) ? t('nextcloud-vue', 'Overdue: {date}', { date }) : date\n\t\t},\n\n\t\tstateText(task) {\n\t\t\treturn String(task.state || '')\n\t\t},\n\n\t\twhoOf(task) {\n\t\t\tif (task.assignee) {\n\t\t\t\treturn task.assigneeName || task.assignee\n\t\t\t}\n\t\t\tconst groups = Array.isArray(task.candidateGroups) ? task.candidateGroups : []\n\t\t\treturn groups.length > 0 ? t('nextcloud-vue', 'Pool: {groups}', { groups: groups.join(', ') }) : t('nextcloud-vue', 'Unassigned')\n\t\t},\n\n\t\t/**\n\t\t * The verbs a row offers: exactly the ones in its `can` list that this\n\t\t * panel has a control for. Nothing is derived from state, assignee or\n\t\t * requester; a row without `can` offers none.\n\t\t *\n\t\t * @param {object} task The task row.\n\t\t * @return {string[]} The verbs, in display order.\n\t\t */\n\t\tverbsOf(task) {\n\t\t\tconst can = Array.isArray(task.can) ? task.can : []\n\t\t\treturn VERBS.filter((verb) => can.includes(verb))\n\t\t},\n\n\t\tverbLabel(verb) {\n\t\t\tconst labels = {\n\t\t\t\tclaim: t('nextcloud-vue', 'Claim'),\n\t\t\t\tunclaim: t('nextcloud-vue', 'Unclaim'),\n\t\t\t\treassign: t('nextcloud-vue', 'Reassign'),\n\t\t\t\tcomplete: t('nextcloud-vue', 'Complete'),\n\t\t\t\tcancel: t('nextcloud-vue', 'Cancel'),\n\t\t\t}\n\t\t\treturn labels[verb] || verb\n\t\t},\n\n\t\tasync load() {\n\t\t\tif (!this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst { results } = await useTaskInboxStore().fetchFor({ objectUuid: this.objectId, scope: 'all' })\n\t\t\t\tthis.tasks = results\n\t\t\t} catch (error) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnFlowTasksPanel] Loading the tasks failed', error)\n\t\t\t\tthis.tasks = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync searchAssignees(query) {\n\t\t\tthis.searching = true\n\t\t\tconst [users, groups] = await Promise.all([\n\t\t\t\tsearchNextcloudUsers(query || '', { limit: 10 }),\n\t\t\t\tsearchGroupSharees(query || '', { limit: 10 }),\n\t\t\t])\n\t\t\tthis.searching = false\n\t\t\tthis.assigneeOptions = [\n\t\t\t\t...users.map((u) => ({ kind: 'user', id: u.id, label: u.label || u.displayName || u.id })),\n\t\t\t\t...groups.map((g) => ({ kind: 'group', id: g.id, label: t('nextcloud-vue', '{name} (group)', { name: g.label }) })),\n\t\t\t]\n\t\t},\n\n\t\tasync searchUsers(query) {\n\t\t\tconst users = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tthis.userOptions = users.map((u) => ({ kind: 'user', id: u.id, label: u.label || u.displayName || u.id }))\n\t\t},\n\n\t\tasync addTask() {\n\t\t\tif (!this.title.trim() || this.saving) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.formError = ''\n\t\t\tconst result = await useTaskInboxStore().createTask({\n\t\t\t\ttitle: this.title,\n\t\t\t\tdescription: this.description,\n\t\t\t\tdueAt: this.due ? new Date(this.due).toISOString() : '',\n\t\t\t\tanchor: { objectUuid: this.objectId, registerId: this.register, schemaId: this.schema },\n\t\t\t\tassignee: this.assignee ? { kind: this.assignee.kind, id: this.assignee.id } : null,\n\t\t\t})\n\t\t\tthis.saving = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.formError = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer open this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'The task could not be created.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.title = ''\n\t\t\tthis.description = ''\n\t\t\tthis.due = null\n\t\t\tthis.assignee = null\n\t\t\tawait this.load()\n\t\t},\n\n\t\tasync onVerb(task, verb) {\n\t\t\tif (verb === 'reassign') {\n\t\t\t\tthis.reassigning = this.reassigning === this.uuidOf(task) ? '' : this.uuidOf(task)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.run(task, verb, {})\n\t\t},\n\n\t\tasync reassign(task, option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.reassigning = ''\n\t\t\tawait this.run(task, 'reassign', { assignee: option.id })\n\t\t},\n\n\t\tasync run(task, verb, body) {\n\t\t\tconst uuid = this.uuidOf(task)\n\t\t\tthis.busy = uuid\n\t\t\tthis.rowErrors = { ...this.rowErrors, [uuid]: '' }\n\t\t\tconst result = await useTaskInboxStore().runVerb(uuid, verb, body)\n\t\t\tthis.busy = ''\n\t\t\tif (!result.ok) {\n\t\t\t\t// The row stays exactly as it was, with the server's words on it.\n\t\t\t\tthis.rowErrors = { ...this.rowErrors, [uuid]: result.message || t('nextcloud-vue', 'The server refused this.') }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.load()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-flow-tasks__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-flow-tasks__row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 4px 8px;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-flow-tasks__title {\n\tflex: 1 1 100%;\n\tfont-weight: bold;\n}\n\n.cn-flow-tasks__meta,\n.cn-flow-tasks__state {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-flow-tasks__due--overdue {\n\tcolor: var(--color-error-text);\n\tfont-weight: bold;\n}\n\n.cn-flow-tasks__verbs {\n\tdisplay: inline-flex;\n\tgap: 4px;\n\tflex-wrap: wrap;\n}\n\n.cn-flow-tasks__error {\n\tflex: 1 1 100%;\n\tmargin: 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["t"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnFlowTasksPanel.vue3.js","sources":["../../../../src/components/CnObjectSidebar/CnFlowTasksPanel.vue?vue&type=template&id=6aff1961&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-flow-tasks\" data-testid=\"cn-flow-tasks-panel\">\n\t\t<!-- Create a task on the record -->\n\t\t<form class=\"cn-sidebar-tab__section\" data-testid=\"cn-flow-tasks-form\" @submit.prevent=\"addTask\">\n\t\t\t<NcTextField\n\t\t\t\tv-model=\"title\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Add task…')\"\n\t\t\t\tdata-testid=\"cn-flow-tasks-title\" />\n\t\t\t<div class=\"cn-sidebar-tab__grid\">\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tv-model=\"due\"\n\t\t\t\t\t:label=\"t('nextcloud-vue', 'Deadline')\"\n\t\t\t\t\ttype=\"date\" />\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"assignee\"\n\t\t\t\t\t:options=\"assigneeOptions\"\n\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Assignee')\"\n\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Assignee')\"\n\t\t\t\t\t:loading=\"searching\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\tdata-testid=\"cn-flow-tasks-assignee\"\n\t\t\t\t\t@search=\"searchAssignees\" />\n\t\t\t</div>\n\t\t\t<NcTextField\n\t\t\t\tv-model=\"description\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Description')\" />\n\t\t\t<NcNoteCard v-if=\"formError\" type=\"error\" data-testid=\"cn-flow-tasks-form-error\">\n\t\t\t\t{{ formError }}\n\t\t\t</NcNoteCard>\n\t\t\t<NcButton\n\t\t\t\ttype=\"submit\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!title.trim() || saving\"\n\t\t\t\tdata-testid=\"cn-flow-tasks-add\">\n\t\t\t\t{{ t('nextcloud-vue', 'Add task') }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t<template v-else>\n\t\t\t<p v-if=\"openTasks.length === 0 && doneTasks.length === 0\" class=\"cn-sidebar-tab__empty\" data-testid=\"cn-flow-tasks-empty\">\n\t\t\t\t{{ t('nextcloud-vue', 'No tasks on this record yet. Personal reminders live in the Integrations tab.') }}\n\t\t\t</p>\n\n\t\t\t<ul v-if=\"openTasks.length > 0\" class=\"cn-flow-tasks__list\" data-testid=\"cn-flow-tasks-open\">\n\t\t\t\t<li v-for=\"task in openTasks\"\n\t\t\t\t\t:key=\"uuidOf(task)\"\n\t\t\t\t\tclass=\"cn-flow-tasks__row\"\n\t\t\t\t\t:data-task=\"uuidOf(task)\">\n\t\t\t\t\t<a :href=\"deepLink(task)\" class=\"cn-flow-tasks__title\">{{ task.title }}</a>\n\t\t\t\t\t<span class=\"cn-flow-tasks__meta\">{{ whoOf(task) }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"task.dueAt\"\n\t\t\t\t\t\tclass=\"cn-flow-tasks__due\"\n\t\t\t\t\t\t:class=\"{ 'cn-flow-tasks__due--overdue': isOverdue(task) }\"\n\t\t\t\t\t\tdata-testid=\"cn-flow-tasks-due\">\n\t\t\t\t\t\t{{ dueText(task) }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-flow-tasks__state\">{{ stateText(task) }}</span>\n\t\t\t\t\t<span class=\"cn-flow-tasks__verbs\">\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-for=\"verb in verbsOf(task)\"\n\t\t\t\t\t\t\t:key=\"verb\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t:disabled=\"busy === uuidOf(task)\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-flow-tasks-verb-${verb}`\"\n\t\t\t\t\t\t\t@click=\"onVerb(task, verb)\">\n\t\t\t\t\t\t\t{{ verbLabel(verb) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</span>\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\tv-if=\"reassigning === uuidOf(task)\"\n\t\t\t\t\t\t:options=\"userOptions\"\n\t\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Reassign to')\"\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-flow-tasks-reassign-picker\"\n\t\t\t\t\t\t@search=\"searchUsers\"\n\t\t\t\t\t\t@update:modelValue=\"(option) => reassign(task, option)\" />\n\t\t\t\t\t<p v-if=\"rowErrors[uuidOf(task)]\"\n\t\t\t\t\t\tclass=\"cn-flow-tasks__error\"\n\t\t\t\t\t\trole=\"alert\"\n\t\t\t\t\t\tdata-testid=\"cn-flow-tasks-row-error\">\n\t\t\t\t\t\t{{ rowErrors[uuidOf(task)] }}\n\t\t\t\t\t</p>\n\t\t\t\t</li>\n\t\t\t</ul>\n\n\t\t\t<div v-if=\"doneTasks.length > 0\" class=\"cn-flow-tasks__done\">\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:aria-expanded=\"doneOpen ? 'true' : 'false'\"\n\t\t\t\t\tdata-testid=\"cn-flow-tasks-done-toggle\"\n\t\t\t\t\t@click=\"doneOpen = !doneOpen\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Done ({count})', { count: doneTasks.length }) }}\n\t\t\t\t</NcButton>\n\t\t\t\t<ul v-if=\"doneOpen\" class=\"cn-flow-tasks__list\" data-testid=\"cn-flow-tasks-done\">\n\t\t\t\t\t<li v-for=\"task in doneTasks\" :key=\"uuidOf(task)\" class=\"cn-flow-tasks__row\">\n\t\t\t\t\t\t<a :href=\"deepLink(task)\" class=\"cn-flow-tasks__title\">{{ task.title }}</a>\n\t\t\t\t\t\t<span class=\"cn-flow-tasks__state\">{{ stateText(task) }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcDateTimePickerNative, NcLoadingIcon, NcNoteCard, NcSelect, NcTextField } from '@nextcloud/vue'\nimport { taskDeepLink, taskDueLabel } from '../../composables/indexSources.js'\nimport { useTaskInboxStore } from '../../composables/useTaskInboxStore.js'\nimport { searchGroupSharees } from '../../utils/searchGroupSharees.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\n\n/** The verbs this panel has a control for, in the order a row shows them. */\nconst VERBS = ['claim', 'unclaim', 'reassign', 'complete', 'cancel']\n\n/** States after which a task is finished. */\nconst TERMINAL_STATES = ['completed', 'terminated', 'cancelled', 'canceled']\n\n/**\n * CnFlowTasksPanel — the `flow-tasks` source of `CnTasksTab`: the OpenRegister\n * flow tasks anchored on one record. Lists them (open ones first by due date,\n * finished ones folded under \"Done\", overdue marked), creates a task on the\n * record with an assignee (a user, or a group as a pool) and a due date, and\n * offers on each row exactly the verbs in the row's `can` list. A verb the\n * server refuses shows its message on the row and leaves the row unchanged.\n * Rendered by `CnTasksTab` when `source=\"flow-tasks\"`.\n */\nexport default {\n\tname: 'CnFlowTasksPanel',\n\n\tcomponents: { NcButton, NcDateTimePickerNative, NcLoadingIcon, NcNoteCard, NcSelect, NcTextField },\n\n\tprops: {\n\t\t/** Uuid of the record the tasks hang on. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Register of the record (sent as `registerId`). */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Schema of the record (sent as `schemaId`). */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['count'],\n\n\tdata() {\n\t\treturn {\n\t\t\ttasks: [],\n\t\t\tloading: false,\n\t\t\tsaving: false,\n\t\t\ttitle: '',\n\t\t\tdescription: '',\n\t\t\tdue: null,\n\t\t\tassignee: null,\n\t\t\tformError: '',\n\t\t\tassigneeOptions: [],\n\t\t\tuserOptions: [],\n\t\t\tsearching: false,\n\t\t\trowErrors: {},\n\t\t\tbusy: '',\n\t\t\treassigning: '',\n\t\t\tdoneOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\topenTasks() {\n\t\t\treturn this.tasks\n\t\t\t\t.filter((task) => !this.isFinished(task))\n\t\t\t\t.sort((a, b) => {\n\t\t\t\t\tconst left = a.dueAt ? new Date(a.dueAt).getTime() : Infinity\n\t\t\t\t\tconst right = b.dueAt ? new Date(b.dueAt).getTime() : Infinity\n\t\t\t\t\treturn left - right\n\t\t\t\t})\n\t\t},\n\n\t\tdoneTasks() {\n\t\t\treturn this.tasks.filter((task) => this.isFinished(task))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\n\t\topenTasks(list) {\n\t\t\t/** @event count Emitted with the number of open tasks, for the tab badge. */\n\t\t\tthis.$emit('count', list.length)\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tuuidOf(task) {\n\t\t\treturn String(task.uuid || task.id || '')\n\t\t},\n\n\t\tdeepLink(task) {\n\t\t\treturn taskDeepLink(this.uuidOf(task))\n\t\t},\n\n\t\tisFinished(task) {\n\t\t\treturn task.isTerminal === true || TERMINAL_STATES.includes(String(task.state || '').toLowerCase())\n\t\t},\n\n\t\tisOverdue(task) {\n\t\t\tif (task.overdue === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn !!task.dueAt && !this.isFinished(task) && new Date(task.dueAt).getTime() < Date.now()\n\t\t},\n\n\t\tdueText(task) {\n\t\t\tconst label = taskDueLabel(task)\n\t\t\tif (label !== '') {\n\t\t\t\treturn label\n\t\t\t}\n\t\t\tconst d = new Date(task.dueAt)\n\t\t\tconst date = Number.isNaN(d.getTime()) ? String(task.dueAt) : d.toLocaleDateString()\n\t\t\treturn this.isOverdue(task) ? t('nextcloud-vue', 'Overdue: {date}', { date }) : date\n\t\t},\n\n\t\tstateText(task) {\n\t\t\treturn String(task.state || '')\n\t\t},\n\n\t\twhoOf(task) {\n\t\t\tif (task.assignee) {\n\t\t\t\treturn task.assigneeName || task.assignee\n\t\t\t}\n\t\t\tconst groups = Array.isArray(task.candidateGroups) ? task.candidateGroups : []\n\t\t\treturn groups.length > 0 ? t('nextcloud-vue', 'Pool: {groups}', { groups: groups.join(', ') }) : t('nextcloud-vue', 'Unassigned')\n\t\t},\n\n\t\t/**\n\t\t * The verbs a row offers: exactly the ones in its `can` list that this\n\t\t * panel has a control for. Nothing is derived from state, assignee or\n\t\t * requester; a row without `can` offers none.\n\t\t *\n\t\t * @param {object} task The task row.\n\t\t * @return {string[]} The verbs, in display order.\n\t\t */\n\t\tverbsOf(task) {\n\t\t\tconst can = Array.isArray(task.can) ? task.can : []\n\t\t\treturn VERBS.filter((verb) => can.includes(verb))\n\t\t},\n\n\t\tverbLabel(verb) {\n\t\t\tconst labels = {\n\t\t\t\tclaim: t('nextcloud-vue', 'Claim'),\n\t\t\t\tunclaim: t('nextcloud-vue', 'Unclaim'),\n\t\t\t\treassign: t('nextcloud-vue', 'Reassign'),\n\t\t\t\tcomplete: t('nextcloud-vue', 'Complete'),\n\t\t\t\tcancel: t('nextcloud-vue', 'Cancel'),\n\t\t\t}\n\t\t\treturn labels[verb] || verb\n\t\t},\n\n\t\tasync load() {\n\t\t\tif (!this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst { results } = await useTaskInboxStore().fetchFor({ objectUuid: this.objectId, scope: 'all' })\n\t\t\t\tthis.tasks = results\n\t\t\t} catch (error) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnFlowTasksPanel] Loading the tasks failed', error)\n\t\t\t\tthis.tasks = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync searchAssignees(query) {\n\t\t\tthis.searching = true\n\t\t\tconst [users, groups] = await Promise.all([\n\t\t\t\tsearchNextcloudUsers(query || '', { limit: 10 }),\n\t\t\t\tsearchGroupSharees(query || '', { limit: 10 }),\n\t\t\t])\n\t\t\tthis.searching = false\n\t\t\tthis.assigneeOptions = [\n\t\t\t\t...users.map((u) => ({ kind: 'user', id: u.id, label: u.label || u.displayName || u.id })),\n\t\t\t\t...groups.map((g) => ({ kind: 'group', id: g.id, label: t('nextcloud-vue', '{name} (group)', { name: g.label }) })),\n\t\t\t]\n\t\t},\n\n\t\tasync searchUsers(query) {\n\t\t\tconst users = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tthis.userOptions = users.map((u) => ({ kind: 'user', id: u.id, label: u.label || u.displayName || u.id }))\n\t\t},\n\n\t\tasync addTask() {\n\t\t\tif (!this.title.trim() || this.saving) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.formError = ''\n\t\t\tconst result = await useTaskInboxStore().createTask({\n\t\t\t\ttitle: this.title,\n\t\t\t\tdescription: this.description,\n\t\t\t\tdueAt: this.due ? new Date(this.due).toISOString() : '',\n\t\t\t\tanchor: { objectUuid: this.objectId, registerId: this.register, schemaId: this.schema },\n\t\t\t\tassignee: this.assignee ? { kind: this.assignee.kind, id: this.assignee.id } : null,\n\t\t\t})\n\t\t\tthis.saving = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.formError = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer open this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'The task could not be created.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.title = ''\n\t\t\tthis.description = ''\n\t\t\tthis.due = null\n\t\t\tthis.assignee = null\n\t\t\tawait this.load()\n\t\t},\n\n\t\tasync onVerb(task, verb) {\n\t\t\tif (verb === 'reassign') {\n\t\t\t\tthis.reassigning = this.reassigning === this.uuidOf(task) ? '' : this.uuidOf(task)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.run(task, verb, {})\n\t\t},\n\n\t\tasync reassign(task, option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.reassigning = ''\n\t\t\tawait this.run(task, 'reassign', { assignee: option.id })\n\t\t},\n\n\t\tasync run(task, verb, body) {\n\t\t\tconst uuid = this.uuidOf(task)\n\t\t\tthis.busy = uuid\n\t\t\tthis.rowErrors = { ...this.rowErrors, [uuid]: '' }\n\t\t\tconst result = await useTaskInboxStore().runVerb(uuid, verb, body)\n\t\t\tthis.busy = ''\n\t\t\tif (!result.ok) {\n\t\t\t\t// The row stays exactly as it was, with the server's words on it.\n\t\t\t\tthis.rowErrors = { ...this.rowErrors, [uuid]: result.message || t('nextcloud-vue', 'The server refused this.') }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.load()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-flow-tasks__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-flow-tasks__row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 4px 8px;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-flow-tasks__title {\n\tflex: 1 1 100%;\n\tfont-weight: bold;\n}\n\n.cn-flow-tasks__meta,\n.cn-flow-tasks__state {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-flow-tasks__due--overdue {\n\tcolor: var(--color-error-text);\n\tfont-weight: bold;\n}\n\n.cn-flow-tasks__verbs {\n\tdisplay: inline-flex;\n\tgap: 4px;\n\tflex-wrap: wrap;\n}\n\n.cn-flow-tasks__error {\n\tflex: 1 1 100%;\n\tmargin: 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_createVNode","_createBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass","_createTextVNode"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnFlowTasksPanel.vue3.js","sources":["../../../../src/components/CnObjectSidebar/CnFlowTasksPanel.vue?vue&type=template&id=06a42055&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-sidebar-tab cn-flow-tasks\" data-testid=\"cn-flow-tasks-panel\">\n\t\t<!-- Create a task on the record -->\n\t\t<form class=\"cn-sidebar-tab__section\" data-testid=\"cn-flow-tasks-form\" @submit.prevent=\"addTask\">\n\t\t\t<NcTextField\n\t\t\t\tv-model=\"title\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Add task…')\"\n\t\t\t\tdata-testid=\"cn-flow-tasks-title\" />\n\t\t\t<div class=\"cn-sidebar-tab__grid\">\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tv-model=\"due\"\n\t\t\t\t\t:label=\"t('nextcloud-vue', 'Deadline')\"\n\t\t\t\t\ttype=\"date\" />\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"assignee\"\n\t\t\t\t\t:options=\"assigneeOptions\"\n\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Assignee')\"\n\t\t\t\t\t:placeholder=\"t('nextcloud-vue', 'Assignee')\"\n\t\t\t\t\t:loading=\"searching\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:clearable=\"true\"\n\t\t\t\t\tlabel=\"label\"\n\t\t\t\t\tdata-testid=\"cn-flow-tasks-assignee\"\n\t\t\t\t\t@search=\"searchAssignees\" />\n\t\t\t</div>\n\t\t\t<NcTextField\n\t\t\t\tv-model=\"description\"\n\t\t\t\t:label=\"t('nextcloud-vue', 'Description')\" />\n\t\t\t<NcNoteCard v-if=\"formError\" type=\"error\" data-testid=\"cn-flow-tasks-form-error\">\n\t\t\t\t{{ formError }}\n\t\t\t</NcNoteCard>\n\t\t\t<NcButton\n\t\t\t\ttype=\"submit\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!title.trim() || saving\"\n\t\t\t\tdata-testid=\"cn-flow-tasks-add\">\n\t\t\t\t{{ t('nextcloud-vue', 'Add task') }}\n\t\t\t</NcButton>\n\t\t</form>\n\n\t\t<NcLoadingIcon v-if=\"loading\" :name=\"t('nextcloud-vue', 'Loading …')\" />\n\t\t<template v-else>\n\t\t\t<p v-if=\"openTasks.length === 0 && doneTasks.length === 0\" class=\"cn-sidebar-tab__empty\" data-testid=\"cn-flow-tasks-empty\">\n\t\t\t\t{{ t('nextcloud-vue', 'No tasks on this record yet. Personal reminders live in the Integrations tab.') }}\n\t\t\t</p>\n\n\t\t\t<ul v-if=\"openTasks.length > 0\" class=\"cn-flow-tasks__list\" data-testid=\"cn-flow-tasks-open\">\n\t\t\t\t<li v-for=\"task in openTasks\"\n\t\t\t\t\t:key=\"uuidOf(task)\"\n\t\t\t\t\tclass=\"cn-flow-tasks__row\"\n\t\t\t\t\t:data-task=\"uuidOf(task)\">\n\t\t\t\t\t<a :href=\"deepLink(task)\" class=\"cn-flow-tasks__title\">{{ task.title }}</a>\n\t\t\t\t\t<span class=\"cn-flow-tasks__meta\">{{ whoOf(task) }}</span>\n\t\t\t\t\t<span\n\t\t\t\t\t\tv-if=\"task.dueAt\"\n\t\t\t\t\t\tclass=\"cn-flow-tasks__due\"\n\t\t\t\t\t\t:class=\"{ 'cn-flow-tasks__due--overdue': isOverdue(task) }\"\n\t\t\t\t\t\tdata-testid=\"cn-flow-tasks-due\">\n\t\t\t\t\t\t{{ dueText(task) }}\n\t\t\t\t\t</span>\n\t\t\t\t\t<span class=\"cn-flow-tasks__state\">{{ stateText(task) }}</span>\n\t\t\t\t\t<span class=\"cn-flow-tasks__verbs\">\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-for=\"verb in verbsOf(task)\"\n\t\t\t\t\t\t\t:key=\"verb\"\n\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t:disabled=\"busy === uuidOf(task)\"\n\t\t\t\t\t\t\t:data-testid=\"`cn-flow-tasks-verb-${verb}`\"\n\t\t\t\t\t\t\t@click=\"onVerb(task, verb)\">\n\t\t\t\t\t\t\t{{ verbLabel(verb) }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</span>\n\t\t\t\t\t<NcSelect\n\t\t\t\t\t\tv-if=\"reassigning === uuidOf(task)\"\n\t\t\t\t\t\t:options=\"userOptions\"\n\t\t\t\t\t\t:inputLabel=\"t('nextcloud-vue', 'Reassign to')\"\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-flow-tasks-reassign-picker\"\n\t\t\t\t\t\t@search=\"searchUsers\"\n\t\t\t\t\t\t@update:modelValue=\"(option) => reassign(task, option)\" />\n\t\t\t\t\t<p v-if=\"rowErrors[uuidOf(task)]\"\n\t\t\t\t\t\tclass=\"cn-flow-tasks__error\"\n\t\t\t\t\t\trole=\"alert\"\n\t\t\t\t\t\tdata-testid=\"cn-flow-tasks-row-error\">\n\t\t\t\t\t\t{{ rowErrors[uuidOf(task)] }}\n\t\t\t\t\t</p>\n\t\t\t\t</li>\n\t\t\t</ul>\n\n\t\t\t<div v-if=\"doneTasks.length > 0\" class=\"cn-flow-tasks__done\">\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:aria-expanded=\"doneOpen ? 'true' : 'false'\"\n\t\t\t\t\tdata-testid=\"cn-flow-tasks-done-toggle\"\n\t\t\t\t\t@click=\"doneOpen = !doneOpen\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Done ({count})', { count: doneTasks.length }) }}\n\t\t\t\t</NcButton>\n\t\t\t\t<ul v-if=\"doneOpen\" class=\"cn-flow-tasks__list\" data-testid=\"cn-flow-tasks-done\">\n\t\t\t\t\t<li v-for=\"task in doneTasks\" :key=\"uuidOf(task)\" class=\"cn-flow-tasks__row\">\n\t\t\t\t\t\t<a :href=\"deepLink(task)\" class=\"cn-flow-tasks__title\">{{ task.title }}</a>\n\t\t\t\t\t\t<span class=\"cn-flow-tasks__state\">{{ stateText(task) }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</div>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcDateTimePickerNative, NcLoadingIcon, NcNoteCard, NcSelect, NcTextField } from '@nextcloud/vue'\nimport { taskDeepLink, taskDueLabel } from '../../composables/indexSources.js'\nimport { useTaskInboxStore } from '../../composables/useTaskInboxStore.js'\nimport { searchGroupSharees } from '../../utils/searchGroupSharees.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/** The verbs this panel has a control for, in the order a row shows them. */\nconst VERBS = ['claim', 'unclaim', 'reassign', 'complete', 'cancel']\n\n/** States after which a task is finished. */\nconst TERMINAL_STATES = ['completed', 'terminated', 'cancelled', 'canceled']\n\n/**\n * CnFlowTasksPanel — the `flow-tasks` source of `CnTasksTab`: the OpenRegister\n * flow tasks anchored on one record. Lists them (open ones first by due date,\n * finished ones folded under \"Done\", overdue marked), creates a task on the\n * record with an assignee (a user, or a group as a pool) and a due date, and\n * offers on each row exactly the verbs in the row's `can` list. A verb the\n * server refuses shows its message on the row and leaves the row unchanged.\n * Rendered by `CnTasksTab` when `source=\"flow-tasks\"`.\n */\nexport default {\n\tname: 'CnFlowTasksPanel',\n\n\tcomponents: { NcButton, NcDateTimePickerNative, NcLoadingIcon, NcNoteCard, NcSelect, NcTextField },\n\n\tprops: {\n\t\t/** Uuid of the record the tasks hang on. */\n\t\tobjectId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Register of the record (sent as `registerId`). */\n\t\tregister: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Schema of the record (sent as `schemaId`). */\n\t\tschema: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['count'],\n\n\tdata() {\n\t\treturn {\n\t\t\ttasks: [],\n\t\t\tloading: false,\n\t\t\tsaving: false,\n\t\t\ttitle: '',\n\t\t\tdescription: '',\n\t\t\tdue: null,\n\t\t\tassignee: null,\n\t\t\tformError: '',\n\t\t\tassigneeOptions: [],\n\t\t\tuserOptions: [],\n\t\t\tsearching: false,\n\t\t\trowErrors: {},\n\t\t\tbusy: '',\n\t\t\treassigning: '',\n\t\t\tdoneOpen: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\topenTasks() {\n\t\t\treturn this.tasks\n\t\t\t\t.filter((task) => !this.isFinished(task))\n\t\t\t\t.sort((a, b) => {\n\t\t\t\t\tconst left = a.dueAt ? new Date(a.dueAt).getTime() : Infinity\n\t\t\t\t\tconst right = b.dueAt ? new Date(b.dueAt).getTime() : Infinity\n\t\t\t\t\treturn left - right\n\t\t\t\t})\n\t\t},\n\n\t\tdoneTasks() {\n\t\t\treturn this.tasks.filter((task) => this.isFinished(task))\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\n\t\topenTasks(list) {\n\t\t\t/** @event count Emitted with the number of open tasks, for the tab badge. */\n\t\t\tthis.$emit('count', list.length)\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\tuuidOf(task) {\n\t\t\treturn String(task.uuid || task.id || '')\n\t\t},\n\n\t\tdeepLink(task) {\n\t\t\treturn taskDeepLink(this.uuidOf(task))\n\t\t},\n\n\t\tisFinished(task) {\n\t\t\treturn task.isTerminal === true || TERMINAL_STATES.includes(String(task.state || '').toLowerCase())\n\t\t},\n\n\t\tisOverdue(task) {\n\t\t\tif (task.overdue === true) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn !!task.dueAt && !this.isFinished(task) && new Date(task.dueAt).getTime() < Date.now()\n\t\t},\n\n\t\tdueText(task) {\n\t\t\tconst label = taskDueLabel(task)\n\t\t\tif (label !== '') {\n\t\t\t\treturn label\n\t\t\t}\n\t\t\tconst d = new Date(task.dueAt)\n\t\t\tconst date = Number.isNaN(d.getTime()) ? String(task.dueAt) : d.toLocaleDateString(userLocale())\n\t\t\treturn this.isOverdue(task) ? t('nextcloud-vue', 'Overdue: {date}', { date }) : date\n\t\t},\n\n\t\tstateText(task) {\n\t\t\treturn String(task.state || '')\n\t\t},\n\n\t\twhoOf(task) {\n\t\t\tif (task.assignee) {\n\t\t\t\treturn task.assigneeName || task.assignee\n\t\t\t}\n\t\t\tconst groups = Array.isArray(task.candidateGroups) ? task.candidateGroups : []\n\t\t\treturn groups.length > 0 ? t('nextcloud-vue', 'Pool: {groups}', { groups: groups.join(', ') }) : t('nextcloud-vue', 'Unassigned')\n\t\t},\n\n\t\t/**\n\t\t * The verbs a row offers: exactly the ones in its `can` list that this\n\t\t * panel has a control for. Nothing is derived from state, assignee or\n\t\t * requester; a row without `can` offers none.\n\t\t *\n\t\t * @param {object} task The task row.\n\t\t * @return {string[]} The verbs, in display order.\n\t\t */\n\t\tverbsOf(task) {\n\t\t\tconst can = Array.isArray(task.can) ? task.can : []\n\t\t\treturn VERBS.filter((verb) => can.includes(verb))\n\t\t},\n\n\t\tverbLabel(verb) {\n\t\t\tconst labels = {\n\t\t\t\tclaim: t('nextcloud-vue', 'Claim'),\n\t\t\t\tunclaim: t('nextcloud-vue', 'Unclaim'),\n\t\t\t\treassign: t('nextcloud-vue', 'Reassign'),\n\t\t\t\tcomplete: t('nextcloud-vue', 'Complete'),\n\t\t\t\tcancel: t('nextcloud-vue', 'Cancel'),\n\t\t\t}\n\t\t\treturn labels[verb] || verb\n\t\t},\n\n\t\tasync load() {\n\t\t\tif (!this.objectId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst { results } = await useTaskInboxStore().fetchFor({ objectUuid: this.objectId, scope: 'all' })\n\t\t\t\tthis.tasks = results\n\t\t\t} catch (error) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('[CnFlowTasksPanel] Loading the tasks failed', error)\n\t\t\t\tthis.tasks = []\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\tasync searchAssignees(query) {\n\t\t\tthis.searching = true\n\t\t\tconst [users, groups] = await Promise.all([\n\t\t\t\tsearchNextcloudUsers(query || '', { limit: 10 }),\n\t\t\t\tsearchGroupSharees(query || '', { limit: 10 }),\n\t\t\t])\n\t\t\tthis.searching = false\n\t\t\tthis.assigneeOptions = [\n\t\t\t\t...users.map((u) => ({ kind: 'user', id: u.id, label: u.label || u.displayName || u.id })),\n\t\t\t\t...groups.map((g) => ({ kind: 'group', id: g.id, label: t('nextcloud-vue', '{name} (group)', { name: g.label }) })),\n\t\t\t]\n\t\t},\n\n\t\tasync searchUsers(query) {\n\t\t\tconst users = await searchNextcloudUsers(query || '', { limit: 10 })\n\t\t\tthis.userOptions = users.map((u) => ({ kind: 'user', id: u.id, label: u.label || u.displayName || u.id }))\n\t\t},\n\n\t\tasync addTask() {\n\t\t\tif (!this.title.trim() || this.saving) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tthis.formError = ''\n\t\t\tconst result = await useTaskInboxStore().createTask({\n\t\t\t\ttitle: this.title,\n\t\t\t\tdescription: this.description,\n\t\t\t\tdueAt: this.due ? new Date(this.due).toISOString() : '',\n\t\t\t\tanchor: { objectUuid: this.objectId, registerId: this.register, schemaId: this.schema },\n\t\t\t\tassignee: this.assignee ? { kind: this.assignee.kind, id: this.assignee.id } : null,\n\t\t\t})\n\t\t\tthis.saving = false\n\t\t\tif (!result.ok) {\n\t\t\t\tthis.formError = result.status === 404\n\t\t\t\t\t? t('nextcloud-vue', 'You can no longer open this record.')\n\t\t\t\t\t: (result.message || t('nextcloud-vue', 'The task could not be created.'))\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.title = ''\n\t\t\tthis.description = ''\n\t\t\tthis.due = null\n\t\t\tthis.assignee = null\n\t\t\tawait this.load()\n\t\t},\n\n\t\tasync onVerb(task, verb) {\n\t\t\tif (verb === 'reassign') {\n\t\t\t\tthis.reassigning = this.reassigning === this.uuidOf(task) ? '' : this.uuidOf(task)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.run(task, verb, {})\n\t\t},\n\n\t\tasync reassign(task, option) {\n\t\t\tif (!option || !option.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.reassigning = ''\n\t\t\tawait this.run(task, 'reassign', { assignee: option.id })\n\t\t},\n\n\t\tasync run(task, verb, body) {\n\t\t\tconst uuid = this.uuidOf(task)\n\t\t\tthis.busy = uuid\n\t\t\tthis.rowErrors = { ...this.rowErrors, [uuid]: '' }\n\t\t\tconst result = await useTaskInboxStore().runVerb(uuid, verb, body)\n\t\t\tthis.busy = ''\n\t\t\tif (!result.ok) {\n\t\t\t\t// The row stays exactly as it was, with the server's words on it.\n\t\t\t\tthis.rowErrors = { ...this.rowErrors, [uuid]: result.message || t('nextcloud-vue', 'The server refused this.') }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tawait this.load()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-flow-tasks__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-flow-tasks__row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 4px 8px;\n\tpadding: 8px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-flow-tasks__title {\n\tflex: 1 1 100%;\n\tfont-weight: bold;\n}\n\n.cn-flow-tasks__meta,\n.cn-flow-tasks__state {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-flow-tasks__due--overdue {\n\tcolor: var(--color-error-text);\n\tfont-weight: bold;\n}\n\n.cn-flow-tasks__verbs {\n\tdisplay: inline-flex;\n\tgap: 4px;\n\tflex-wrap: wrap;\n}\n\n.cn-flow-tasks__error {\n\tflex: 1 1 100%;\n\tmargin: 0;\n\tcolor: var(--color-error-text);\n}\n</style>\n"],"names":["_openBlock","_createElementBlock","_createElementVNode","_createVNode","_createBlock","_toDisplayString","_Fragment","_renderList","_normalizeClass","_createTextVNode"],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@ import __sfc_main$1 from '../CnNoteComposer/CnNoteComposer.vue.js';
|
|
|
12
12
|
import { extractMentionedIds, extractMentionedGroupIds } from '../../utils/mentions.js';
|
|
13
13
|
import { supportsReplies, threadNotes, quoteFor, threadRootId } from '../../utils/noteThreads.js';
|
|
14
14
|
import { searchNextcloudUsers } from '../../utils/userAutocomplete.js';
|
|
15
|
+
import { userLocale } from '../../utils/userLocale.js';
|
|
15
16
|
import { prefixUrl, buildHeaders } from '../../utils/headers.js';
|
|
16
17
|
|
|
17
18
|
var script = {
|
|
@@ -439,7 +440,7 @@ var script = {
|
|
|
439
440
|
return ''
|
|
440
441
|
}
|
|
441
442
|
try {
|
|
442
|
-
return new Date(dateStr).toLocaleString(
|
|
443
|
+
return new Date(dateStr).toLocaleString(userLocale(), {
|
|
443
444
|
year: 'numeric',
|
|
444
445
|
month: 'short',
|
|
445
446
|
day: 'numeric',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnNotesTab.vue2.js","sources":["../../../../src/components/CnObjectSidebar/CnNotesTab.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<!-- Add / Edit note -->\n\t\t<div class=\"cn-sidebar-tab__action\">\n\t\t\t<!-- Replying: the composer says to whom, and a reply to a reply goes to the top of its thread. -->\n\t\t\t<p\n\t\t\t\tv-if=\"replyTo\"\n\t\t\t\tclass=\"cn-sidebar-tab__replying\"\n\t\t\t\trole=\"status\"\n\t\t\t\tdata-testid=\"cn-notes-replying\">\n\t\t\t\t{{ replyingLabel }}\n\t\t\t\t<NcButton variant=\"tertiary\" @click=\"cancelReply\">\n\t\t\t\t\t{{ cancelLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</p>\n\t\t\t<!-- @slot composer-before An app's own control above the composer, e.g. a template picker. Scope: `{ setText, text }`; `setText(text)` fills the composer, `text` is what it holds now. -->\n\t\t\t<slot name=\"composer-before\" :setText=\"setComposerText\" :text=\"newNoteText\" />\n\t\t\t<CnNoteComposer\n\t\t\t\tclass=\"cn-sidebar-tab__composer\"\n\t\t\t\t:modelValue=\"newNoteText\"\n\t\t\t\t:placeholder=\"addNotePlaceholder\"\n\t\t\t\t:register=\"register\"\n\t\t\t\t:schema=\"schema\"\n\t\t\t\t:objectId=\"objectId\"\n\t\t\t\t:apiBase=\"apiBase\"\n\t\t\t\t@update:modelValue=\"newNoteText = $event\"\n\t\t\t\t@submit=\"submitComposer\" />\n\t\t\t<div class=\"cn-sidebar-tab__action--row\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"editingNoteId\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t@click=\"cancelEdit\">\n\t\t\t\t\t{{ cancelLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t:disabled=\"!newNoteText.trim() || saving\"\n\t\t\t\t\t@click=\"editingNoteId ? saveEdit() : addNote()\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Send :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ editingNoteId ? saveLabel : addNoteLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Notes list -->\n\t\t<!-- Standalone spinner: give it an accessible name so screen readers\n\t\t announce the loading state (WCAG 1.1.1 / 4.1.2 — a bare\n\t\t NcLoadingIcon renders an unlabelled role=\"img\"). -->\n\t\t<NcLoadingIcon v-if=\"loading\" :name=\"loadingLabel\" />\n\t\t<div v-else-if=\"notes.length === 0\" class=\"cn-sidebar-tab__empty\">\n\t\t\t{{ noNotesLabel }}\n\t\t</div>\n\t\t<!-- <ul>, not <div>: NcListItem renders an <li>, which WCAG 1.3.1\n\t\t requires to be contained in a <ul>/<ol> (axe \"listitem\"). -->\n\t\t<ul v-else class=\"cn-sidebar-tab__list\">\n\t\t\t<!-- One <li> per thread; inside it the note first, then its replies (oldest first), as a nested list named after the note. -->\n\t\t\t<li v-for=\"thread in threads\" :key=\"thread.note.id\" class=\"cn-notes-tab__thread\">\n\t\t\t\t<ul class=\"cn-notes-tab__thread-list\" :aria-label=\"threadLabel(thread.note)\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\tv-for=\"row in threadRows(thread)\"\n\t\t\t\t\t\t:key=\"row.note.id\"\n\t\t\t\t\t\t:class=\"{ 'cn-notes-tab__reply': row.isReply }\"\n\t\t\t\t\t\t:name=\"row.note.actorDisplayName || row.note.author || 'Unknown'\"\n\t\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<CommentTextOutline :size=\"32\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t<span class=\"cn-sidebar-tab__message\">\n\t\t\t\t\t\t\t\t<span v-if=\"row.quote\" class=\"cn-notes-tab__quote\" data-testid=\"cn-note-quote\">{{ row.quote }}</span>\n\t\t\t\t\t\t\t\t<CnNoteBody :message=\"row.note.message || row.note.content || ''\" :record=\"record\" :names=\"mentionNames\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #details>\n\t\t\t\t\t\t\t{{ formatDate(row.note.creationDateTime || row.note.created) }}\n\t\t\t\t\t\t\t<!-- An edited note says so where its time is, because that\n\t\t\t\t\t\t\t is where a reader already looks to date what they are\n\t\t\t\t\t\t\t reading. The line names the editor, so nobody has to\n\t\t\t\t\t\t\t open the history to learn who changed it. -->\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"wasEdited(row.note)\"\n\t\t\t\t\t\t\t\tclass=\"cn-notes-tab__edited\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-note-edited\">{{ editedLine(row.note) }}</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-if=\"canReply || canDelete(row.note) || wasEdited(row.note) || noteActions.length > 0\" #actions>\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-if=\"canReply\"\n\t\t\t\t\t\t\t\t:aria-label=\"replyAria(row.note)\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-note-reply-action\"\n\t\t\t\t\t\t\t\t@click=\"startReply(row.note)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<Reply :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ replyLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionButton v-if=\"canDelete(row.note)\" @click=\"startEdit(row.note)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<Pencil :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ editLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-if=\"wasEdited(row.note)\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-note-history-action\"\n\t\t\t\t\t\t\t\t@click=\"openHistory(row.note)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<HistoryIcon :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ historyLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionButton v-if=\"canDelete(row.note)\" @click=\"deleteNote(row.note)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<Delete :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ deleteLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<!-- The consuming app's own per-note actions, after the\n\t\t\t\t\t\t\t library's. They render inside this NcActions and emit\n\t\t\t\t\t\t\t `note-action`; nothing about what they DO lives here. -->\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-for=\"action in noteActions\"\n\t\t\t\t\t\t\t\t:key=\"`${row.note.id}-${action.id}`\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-note-action-${action.id}`\"\n\t\t\t\t\t\t\t\t@click=\"$emit('note-action', { action: action.id, note: row.note })\">\n\t\t\t\t\t\t\t\t<template v-if=\"action.icon\" #icon>\n\t\t\t\t\t\t\t\t\t<component :is=\"action.icon\" :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t</ul>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<CnNoteHistoryDialog\n\t\t\tv-if=\"historyNoteId\"\n\t\t\t:open=\"true\"\n\t\t\t:noteId=\"historyNoteId\"\n\t\t\t:objectId=\"objectId\"\n\t\t\t:register=\"register\"\n\t\t\t:schema=\"schema\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@update:open=\"historyNoteId = null\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport CommentTextOutline from 'vue-material-design-icons/CommentTextOutline.vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport HistoryIcon from 'vue-material-design-icons/History.vue'\nimport Pencil from 'vue-material-design-icons/Pencil.vue'\nimport Reply from 'vue-material-design-icons/Reply.vue'\nimport Send from 'vue-material-design-icons/Send.vue'\nimport CnNoteHistoryDialog from '../../dialogs/CnNoteHistoryDialog.vue'\nimport CnNoteBody from '../CnNoteBody/CnNoteBody.vue'\nimport CnNoteComposer from '../CnNoteComposer/CnNoteComposer.vue'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { extractMentionedGroupIds, extractMentionedIds } from '../../utils/mentions.js'\nimport { quoteFor, supportsReplies, threadNotes, threadRootId } from '../../utils/noteThreads.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\n\nexport default {\n\tname: 'CnNotesTab',\n\n\tcomponents: { NcButton, NcListItem, NcActionButton, NcLoadingIcon, CnNoteBody, CnNoteComposer, CnNoteHistoryDialog, CommentTextOutline, Send, Pencil, Delete, HistoryIcon, Reply },\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Label for the add note button */\n\t\taddNoteLabel: { type: String, default: () => t('nextcloud-vue', 'Add note') },\n\t\t/** Placeholder text for the note input field */\n\t\taddNotePlaceholder: { type: String, default: () => t('nextcloud-vue', 'Write a note…') },\n\t\t/** Label for the edit action */\n\t\teditLabel: { type: String, default: () => t('nextcloud-vue', 'Edit') },\n\t\t/** Label for the save action */\n\t\tsaveLabel: { type: String, default: () => t('nextcloud-vue', 'Save') },\n\t\t/** Label for the cancel button */\n\t\tcancelLabel: { type: String, default: () => t('nextcloud-vue', 'Cancel') },\n\t\t/** Label for the delete action */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete') },\n\t\t/** Text shown when there are no notes */\n\t\tnoNotesLabel: { type: String, default: () => t('nextcloud-vue', 'No notes yet') },\n\t\t/** Text shown while the notes are being fetched */\n\t\tloadingLabel: { type: String, default: () => t('nextcloud-vue', 'Loading notes…') },\n\t\t/** Label for the Reply action (shown only when the backend supports replies) */\n\t\treplyLabel: { type: String, default: () => t('nextcloud-vue', 'Reply') },\n\t\t/** Label for the action that opens a note's earlier versions */\n\t\thistoryLabel: { type: String, default: () => t('nextcloud-vue', 'Show earlier versions') },\n\t\t// WHY THIS PROP EXISTS, since a seam nobody asked for is the kind that\n\t\t// rots. An app-specific act on ONE note had nowhere to live: this\n\t\t// component rendered edit, history and delete and offered no fourth\n\t\t// place. Dossiq sends a single case note to a neighbouring ZGW\n\t\t// register, and its endpoint, guard, route and tests were all in place\n\t\t// while no page could call any of them. Its own change wrote that down\n\t\t// as a blocker rather than declaring a prop nothing read.\n\t\t//\n\t\t// `label` stays the app's to write and translate, so nc-vue phrases\n\t\t// nothing for somebody else's domain and adds no catalogue string here.\n\t\t/**\n\t\t * Per-note actions the consuming app owns, `[{ id, label, icon? }]`.\n\t\t * Each entry renders one NcActionButton in every note's action menu,\n\t\t * after the library's own, and clicking it emits `note-action`. Empty\n\t\t * by default, and an empty list changes nothing. `icon` is optional\n\t\t * and takes an icon component.\n\t\t */\n\t\tnoteActions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t\tvalidator: (actions) => actions.every((action) => action\n\t\t\t\t&& typeof action.id === 'string' && action.id !== ''\n\t\t\t\t&& typeof action.label === 'string' && action.label !== ''),\n\t\t},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * Emitted after a note containing at least one `@mention` was\n\t\t * successfully created or edited, with payload\n\t\t * `{ objectId, register, schema, noteId, mentionedUserIds }`, plus\n\t\t * `mentionedGroupIds` when the note mentions a group (`@\"group/<gid>\"`).\n\t\t * The event also fires for a note that mentions only groups. Expanding a\n\t\t * group to its members is the listener's job.\n\t\t * nc-vue never dispatches server-side notifications itself —\n\t\t * consuming apps listen to this event and notify from their own\n\t\t * backend.\n\t\t */\n\t\t'mention',\n\t\t/**\n\t\t * Emitted when one of the consuming app's `noteActions` is clicked,\n\t\t * with payload `{ action, note }`: the entry's `id` and the whole note\n\t\t * as the backend answered it. The library does the rendering and\n\t\t * nothing else, so what the action means stays in the app.\n\t\t */\n\t\t'note-action',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tnotes: [],\n\t\t\tloading: false,\n\t\t\tnewNoteText: '',\n\t\t\tsaving: false,\n\t\t\teditingNoteId: null,\n\t\t\t/** The note whose earlier versions are open, or null. */\n\t\t\thistoryNoteId: null,\n\t\t\t/**\n\t\t\t * Per-instance cache of mentioned-user display names, keyed by\n\t\t\t * user id. `null` marks an id that could not be resolved (unknown\n\t\t\t * or deleted user) so it is only looked up once.\n\t\t\t */\n\t\t\tmentionNames: {},\n\t\t\t/** The note a reply is being written to, or null. */\n\t\t\treplyTo: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {{apiBase: string, register: string, schema: string, objectId: string}} Where this record's files live, for pasted images. */\n\t\trecord() {\n\t\t\treturn { apiBase: this.apiBase, register: this.register, schema: this.schema, objectId: this.objectId }\n\t\t},\n\n\t\t/** @return {boolean} Whether the backend supports replies: its notes carry a `parentId` key. */\n\t\tcanReply() {\n\t\t\treturn supportsReplies(this.notes)\n\t\t},\n\n\t\t/** @return {Array<{note: object, replies: object[]}>} The notes as threads, in the order they came. */\n\t\tthreads() {\n\t\t\treturn threadNotes(this.notes)\n\t\t},\n\n\t\t/** @return {string} The line above the composer while replying. */\n\t\treplyingLabel() {\n\t\t\treturn this.replyTo ? t('nextcloud-vue', 'Replying to {author}', { author: this.authorOf(this.replyTo) }) : ''\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchNotes()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\tasync fetchNotes() {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/notes`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.notes = data.results || data || []\n\t\t\t\t\tthis.resolveMentionNames()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNotesTab: Failed to fetch notes', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Resolve display names for every mentioned id across the current\n\t\t * notes list. Each id is looked up at most once per component\n\t\t * instance; unresolvable ids are cached as `null`.\n\t\t */\n\t\tasync resolveMentionNames() {\n\t\t\tconst ids = new Set()\n\t\t\tfor (const note of this.notes) {\n\t\t\t\tfor (const id of extractMentionedIds(note.message || note.content || '')) {\n\t\t\t\t\tids.add(id)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait Promise.all([...ids]\n\t\t\t\t.filter((id) => !(id in this.mentionNames))\n\t\t\t\t.map(async (id) => {\n\t\t\t\t\t// Mark as pending (null) first so concurrent calls skip it.\n\t\t\t\t\tthis.mentionNames[id] = null\n\t\t\t\t\tconst results = await searchNextcloudUsers(id)\n\t\t\t\t\tconst match = results.find((user) => user.id === id)\n\t\t\t\t\tif (match) {\n\t\t\t\t\t\tthis.mentionNames[id] = match.label\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Emit the `mention` notification hook for a successfully saved note.\n\t\t *\n\t\t * @param {string} savedText The note text that was persisted.\n\t\t * @param {string|null} noteId The created/edited note's id.\n\t\t */\n\t\temitMentionEvent(savedText, noteId) {\n\t\t\tconst mentionedUserIds = extractMentionedIds(savedText)\n\t\t\tconst mentionedGroupIds = extractMentionedGroupIds(savedText)\n\t\t\tif (mentionedUserIds.length === 0 && mentionedGroupIds.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('mention', {\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tnoteId,\n\t\t\t\tmentionedUserIds,\n\t\t\t\t// Only when a group is mentioned: a note that names none keeps the payload it always had.\n\t\t\t\t...(mentionedGroupIds.length > 0 ? { mentionedGroupIds } : {}),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Save from the composer (Ctrl/Cmd+Enter): the same as the button.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tsubmitComposer() {\n\t\t\tif (!this.newNoteText.trim() || this.saving) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.editingNoteId) {\n\t\t\t\tthis.saveEdit()\n\t\t\t} else {\n\t\t\t\tthis.addNote()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note A note.\n\t\t * @return {string} Its author's name.\n\t\t */\n\t\tauthorOf(note) {\n\t\t\treturn note.actorDisplayName || note.author || 'Unknown'\n\t\t},\n\n\t\t/**\n\t\t * Write a reply to a note. A reply to a reply goes to the top of its thread.\n\t\t *\n\t\t * @param {object} note The note answered.\n\t\t * @return {void}\n\t\t */\n\t\tstartReply(note) {\n\t\t\tthis.editingNoteId = null\n\t\t\tthis.replyTo = note\n\t\t},\n\n\t\tcancelReply() {\n\t\t\tthis.replyTo = null\n\t\t},\n\n\t\t/**\n\t\t * The rows of one thread: the note, then its replies. A reply whose parent\n\t\t * is far up the list carries a one-line quote of it.\n\t\t *\n\t\t * @param {{note: object, replies: object[]}} thread The thread.\n\t\t * @return {Array<{note: object, isReply: boolean, quote: string}>} The rows.\n\t\t */\n\t\tthreadRows(thread) {\n\t\t\tconst flat = this.threads.flatMap((t2) => [t2.note, ...t2.replies])\n\t\t\treturn [\n\t\t\t\t{ note: thread.note, isReply: false, quote: '' },\n\t\t\t\t...thread.replies.map((reply) => ({ note: reply, isReply: true, quote: quoteFor(reply, flat) })),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note A top-level note.\n\t\t * @return {string} The name of its thread for assistive technology.\n\t\t */\n\t\tthreadLabel(note) {\n\t\t\treturn t('nextcloud-vue', 'Note by {author} and its replies', { author: this.authorOf(note) })\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note The note a Reply button answers.\n\t\t * @return {string} The button's accessible name, naming the author.\n\t\t */\n\t\treplyAria(note) {\n\t\t\treturn t('nextcloud-vue', 'Reply to {author}', { author: this.authorOf(note) })\n\t\t},\n\n\t\tasync addNote() {\n\t\t\tif (!this.newNoteText.trim()) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tconst savedText = this.newNoteText.trim()\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/notes`),\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t\t\tbody: JSON.stringify(this.replyTo\n\t\t\t\t\t\t\t? { message: savedText, parentId: threadRootId(this.replyTo, this.notes) }\n\t\t\t\t\t\t\t: { message: savedText }),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tlet noteId = null\n\t\t\t\ttry {\n\t\t\t\t\tconst created = await response.json()\n\t\t\t\t\tnoteId = (created && (created.id || (created.results && created.results.id))) || null\n\t\t\t\t} catch {\n\t\t\t\t\t// Body not JSON — the event still fires with noteId null.\n\t\t\t\t}\n\t\t\t\tthis.emitMentionEvent(savedText, noteId)\n\t\t\t\tthis.newNoteText = ''\n\t\t\t\tthis.replyTo = null\n\t\t\t\tawait this.fetchNotes()\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNotesTab: Failed to add note', err)\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fill the composer from outside, for the `composer-before` slot.\n\t\t *\n\t\t * The app decides what goes in (a template body, a quoted line); the\n\t\t * composer stays the one place the text lives, so sending, editing and\n\t\t * the mention picker all see it exactly as if it had been typed.\n\t\t *\n\t\t * @param {string} text The text the composer should hold.\n\t\t * @return {void}\n\t\t */\n\t\tsetComposerText(text) {\n\t\t\tthis.newNoteText = (text === null || text === undefined) ? '' : String(text)\n\t\t},\n\n\t\tstartEdit(note) {\n\t\t\tthis.replyTo = null\n\t\t\tthis.editingNoteId = note.id\n\t\t\tthis.newNoteText = note.message || note.content || ''\n\t\t},\n\n\t\tcancelEdit() {\n\t\t\tthis.editingNoteId = null\n\t\t\tthis.newNoteText = ''\n\t\t},\n\n\t\tasync saveEdit() {\n\t\t\tif (!this.newNoteText.trim() || !this.editingNoteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tconst savedText = this.newNoteText.trim()\n\t\t\tconst noteId = this.editingNoteId\n\t\t\ttry {\n\t\t\t\tawait fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/notes/${noteId}`),\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: 'PUT',\n\t\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t\t\tbody: JSON.stringify({ message: savedText }),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tthis.emitMentionEvent(savedText, noteId)\n\t\t\t\tthis.editingNoteId = null\n\t\t\t\tthis.newNoteText = ''\n\t\t\t\tawait this.fetchNotes()\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNotesTab: Failed to update note', err)\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\tcanDelete(note) {\n\t\t\treturn note.actorId === OC?.currentUser || note.author === OC?.currentUser\n\t\t},\n\n\t\t/**\n\t\t * Whether this note carries a history to show.\n\t\t *\n\t\t * Read off `versionCount` rather than off `editedAt`: a note edited by\n\t\t * a since-deleted account still has its prior texts, and a marker that\n\t\t * depended on the editor still existing would quietly vanish.\n\t\t *\n\t\t * @param {object} note The note from the backend.\n\t\t * @return {boolean} True when at least one earlier version exists.\n\t\t */\n\t\twasEdited(note) {\n\t\t\treturn Number(note.versionCount || 0) > 0\n\t\t},\n\n\t\t/**\n\t\t * The \"edited\" line beside a note's time.\n\t\t *\n\t\t * @param {object} note The note from the backend.\n\t\t * @return {string} The rendered line.\n\t\t */\n\t\teditedLine(note) {\n\t\t\tconst editor = note.editedByDisplayName || note.editedBy\n\t\t\tif (!editor) {\n\t\t\t\treturn t('nextcloud-vue', 'Edited')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Edited by {editor}', { editor })\n\t\t},\n\n\t\t/**\n\t\t * Open the earlier versions of one note.\n\t\t *\n\t\t * @param {object} note The note to open.\n\t\t */\n\t\topenHistory(note) {\n\t\t\tthis.historyNoteId = note.id\n\t\t},\n\n\t\tasync deleteNote(note) {\n\t\t\ttry {\n\t\t\t\tawait fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/notes/${note.id}`),\n\t\t\t\t\t{ method: 'DELETE', headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tthis.notes = this.notes.filter((n) => n.id !== note.id)\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNotesTab: Failed to delete note', err)\n\t\t\t}\n\t\t},\n\n\t\tformatDate(dateStr) {\n\t\t\tif (!dateStr) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(dateStr).toLocaleString(undefined, {\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\thour: '2-digit',\n\t\t\t\t\tminute: '2-digit',\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn dateStr\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__action { margin-bottom: 16px; }\n\n.cn-sidebar-tab__action--row { display: flex; gap: 8px; align-items: flex-end; margin-top: 8px; }\n\n.cn-sidebar-tab__composer {\n\twidth: 100%;\n}\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }\n\n.cn-notes-tab__thread { list-style: none; }\n\n.cn-notes-tab__thread-list { margin: 0; padding: 0; list-style: none; }\n\n.cn-notes-tab__reply { margin-inline-start: 24px; }\n\n.cn-notes-tab__quote {\n\tdisplay: block;\n\tmargin-bottom: 2px;\n\tpadding-inline-start: 8px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-sidebar-tab__replying {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin: 0 0 4px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-notes-tab__edited {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin-inline-start: 6px;\n\tfont-style: italic;\n}\n\n</style>\n"],"names":["CnNoteBody","CnNoteComposer","CnNoteHistoryDialog","HistoryIcon","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnNotesTab.vue2.js","sources":["../../../../src/components/CnObjectSidebar/CnNotesTab.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<!-- Add / Edit note -->\n\t\t<div class=\"cn-sidebar-tab__action\">\n\t\t\t<!-- Replying: the composer says to whom, and a reply to a reply goes to the top of its thread. -->\n\t\t\t<p\n\t\t\t\tv-if=\"replyTo\"\n\t\t\t\tclass=\"cn-sidebar-tab__replying\"\n\t\t\t\trole=\"status\"\n\t\t\t\tdata-testid=\"cn-notes-replying\">\n\t\t\t\t{{ replyingLabel }}\n\t\t\t\t<NcButton variant=\"tertiary\" @click=\"cancelReply\">\n\t\t\t\t\t{{ cancelLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</p>\n\t\t\t<!-- @slot composer-before An app's own control above the composer, e.g. a template picker. Scope: `{ setText, text }`; `setText(text)` fills the composer, `text` is what it holds now. -->\n\t\t\t<slot name=\"composer-before\" :setText=\"setComposerText\" :text=\"newNoteText\" />\n\t\t\t<CnNoteComposer\n\t\t\t\tclass=\"cn-sidebar-tab__composer\"\n\t\t\t\t:modelValue=\"newNoteText\"\n\t\t\t\t:placeholder=\"addNotePlaceholder\"\n\t\t\t\t:register=\"register\"\n\t\t\t\t:schema=\"schema\"\n\t\t\t\t:objectId=\"objectId\"\n\t\t\t\t:apiBase=\"apiBase\"\n\t\t\t\t@update:modelValue=\"newNoteText = $event\"\n\t\t\t\t@submit=\"submitComposer\" />\n\t\t\t<div class=\"cn-sidebar-tab__action--row\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"editingNoteId\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t@click=\"cancelEdit\">\n\t\t\t\t\t{{ cancelLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t:disabled=\"!newNoteText.trim() || saving\"\n\t\t\t\t\t@click=\"editingNoteId ? saveEdit() : addNote()\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Send :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ editingNoteId ? saveLabel : addNoteLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- Notes list -->\n\t\t<!-- Standalone spinner: give it an accessible name so screen readers\n\t\t announce the loading state (WCAG 1.1.1 / 4.1.2 — a bare\n\t\t NcLoadingIcon renders an unlabelled role=\"img\"). -->\n\t\t<NcLoadingIcon v-if=\"loading\" :name=\"loadingLabel\" />\n\t\t<div v-else-if=\"notes.length === 0\" class=\"cn-sidebar-tab__empty\">\n\t\t\t{{ noNotesLabel }}\n\t\t</div>\n\t\t<!-- <ul>, not <div>: NcListItem renders an <li>, which WCAG 1.3.1\n\t\t requires to be contained in a <ul>/<ol> (axe \"listitem\"). -->\n\t\t<ul v-else class=\"cn-sidebar-tab__list\">\n\t\t\t<!-- One <li> per thread; inside it the note first, then its replies (oldest first), as a nested list named after the note. -->\n\t\t\t<li v-for=\"thread in threads\" :key=\"thread.note.id\" class=\"cn-notes-tab__thread\">\n\t\t\t\t<ul class=\"cn-notes-tab__thread-list\" :aria-label=\"threadLabel(thread.note)\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\tv-for=\"row in threadRows(thread)\"\n\t\t\t\t\t\t:key=\"row.note.id\"\n\t\t\t\t\t\t:class=\"{ 'cn-notes-tab__reply': row.isReply }\"\n\t\t\t\t\t\t:name=\"row.note.actorDisplayName || row.note.author || 'Unknown'\"\n\t\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t\t:forceDisplayActions=\"true\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<CommentTextOutline :size=\"32\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t<span class=\"cn-sidebar-tab__message\">\n\t\t\t\t\t\t\t\t<span v-if=\"row.quote\" class=\"cn-notes-tab__quote\" data-testid=\"cn-note-quote\">{{ row.quote }}</span>\n\t\t\t\t\t\t\t\t<CnNoteBody :message=\"row.note.message || row.note.content || ''\" :record=\"record\" :names=\"mentionNames\" />\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #details>\n\t\t\t\t\t\t\t{{ formatDate(row.note.creationDateTime || row.note.created) }}\n\t\t\t\t\t\t\t<!-- An edited note says so where its time is, because that\n\t\t\t\t\t\t\t is where a reader already looks to date what they are\n\t\t\t\t\t\t\t reading. The line names the editor, so nobody has to\n\t\t\t\t\t\t\t open the history to learn who changed it. -->\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"wasEdited(row.note)\"\n\t\t\t\t\t\t\t\tclass=\"cn-notes-tab__edited\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-note-edited\">{{ editedLine(row.note) }}</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template v-if=\"canReply || canDelete(row.note) || wasEdited(row.note) || noteActions.length > 0\" #actions>\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-if=\"canReply\"\n\t\t\t\t\t\t\t\t:aria-label=\"replyAria(row.note)\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-note-reply-action\"\n\t\t\t\t\t\t\t\t@click=\"startReply(row.note)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<Reply :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ replyLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionButton v-if=\"canDelete(row.note)\" @click=\"startEdit(row.note)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<Pencil :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ editLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-if=\"wasEdited(row.note)\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-note-history-action\"\n\t\t\t\t\t\t\t\t@click=\"openHistory(row.note)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<HistoryIcon :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ historyLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<NcActionButton v-if=\"canDelete(row.note)\" @click=\"deleteNote(row.note)\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<Delete :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ deleteLabel }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t\t<!-- The consuming app's own per-note actions, after the\n\t\t\t\t\t\t\t library's. They render inside this NcActions and emit\n\t\t\t\t\t\t\t `note-action`; nothing about what they DO lives here. -->\n\t\t\t\t\t\t\t<NcActionButton\n\t\t\t\t\t\t\t\tv-for=\"action in noteActions\"\n\t\t\t\t\t\t\t\t:key=\"`${row.note.id}-${action.id}`\"\n\t\t\t\t\t\t\t\t:data-testid=\"`cn-note-action-${action.id}`\"\n\t\t\t\t\t\t\t\t@click=\"$emit('note-action', { action: action.id, note: row.note })\">\n\t\t\t\t\t\t\t\t<template v-if=\"action.icon\" #icon>\n\t\t\t\t\t\t\t\t\t<component :is=\"action.icon\" :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t</ul>\n\t\t\t</li>\n\t\t</ul>\n\n\t\t<CnNoteHistoryDialog\n\t\t\tv-if=\"historyNoteId\"\n\t\t\t:open=\"true\"\n\t\t\t:noteId=\"historyNoteId\"\n\t\t\t:objectId=\"objectId\"\n\t\t\t:register=\"register\"\n\t\t\t:schema=\"schema\"\n\t\t\t:apiBase=\"apiBase\"\n\t\t\t@update:open=\"historyNoteId = null\" />\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcButton, NcListItem, NcLoadingIcon } from '@nextcloud/vue'\nimport CommentTextOutline from 'vue-material-design-icons/CommentTextOutline.vue'\nimport Delete from 'vue-material-design-icons/Delete.vue'\nimport HistoryIcon from 'vue-material-design-icons/History.vue'\nimport Pencil from 'vue-material-design-icons/Pencil.vue'\nimport Reply from 'vue-material-design-icons/Reply.vue'\nimport Send from 'vue-material-design-icons/Send.vue'\nimport CnNoteHistoryDialog from '../../dialogs/CnNoteHistoryDialog.vue'\nimport CnNoteBody from '../CnNoteBody/CnNoteBody.vue'\nimport CnNoteComposer from '../CnNoteComposer/CnNoteComposer.vue'\nimport { buildHeaders, prefixUrl } from '../../utils/index.js'\nimport { extractMentionedGroupIds, extractMentionedIds } from '../../utils/mentions.js'\nimport { quoteFor, supportsReplies, threadNotes, threadRootId } from '../../utils/noteThreads.js'\nimport { searchNextcloudUsers } from '../../utils/userAutocomplete.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\nexport default {\n\tname: 'CnNotesTab',\n\n\tcomponents: { NcButton, NcListItem, NcActionButton, NcLoadingIcon, CnNoteBody, CnNoteComposer, CnNoteHistoryDialog, CommentTextOutline, Send, Pencil, Delete, HistoryIcon, Reply },\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Label for the add note button */\n\t\taddNoteLabel: { type: String, default: () => t('nextcloud-vue', 'Add note') },\n\t\t/** Placeholder text for the note input field */\n\t\taddNotePlaceholder: { type: String, default: () => t('nextcloud-vue', 'Write a note…') },\n\t\t/** Label for the edit action */\n\t\teditLabel: { type: String, default: () => t('nextcloud-vue', 'Edit') },\n\t\t/** Label for the save action */\n\t\tsaveLabel: { type: String, default: () => t('nextcloud-vue', 'Save') },\n\t\t/** Label for the cancel button */\n\t\tcancelLabel: { type: String, default: () => t('nextcloud-vue', 'Cancel') },\n\t\t/** Label for the delete action */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete') },\n\t\t/** Text shown when there are no notes */\n\t\tnoNotesLabel: { type: String, default: () => t('nextcloud-vue', 'No notes yet') },\n\t\t/** Text shown while the notes are being fetched */\n\t\tloadingLabel: { type: String, default: () => t('nextcloud-vue', 'Loading notes…') },\n\t\t/** Label for the Reply action (shown only when the backend supports replies) */\n\t\treplyLabel: { type: String, default: () => t('nextcloud-vue', 'Reply') },\n\t\t/** Label for the action that opens a note's earlier versions */\n\t\thistoryLabel: { type: String, default: () => t('nextcloud-vue', 'Show earlier versions') },\n\t\t// WHY THIS PROP EXISTS, since a seam nobody asked for is the kind that\n\t\t// rots. An app-specific act on ONE note had nowhere to live: this\n\t\t// component rendered edit, history and delete and offered no fourth\n\t\t// place. Dossiq sends a single case note to a neighbouring ZGW\n\t\t// register, and its endpoint, guard, route and tests were all in place\n\t\t// while no page could call any of them. Its own change wrote that down\n\t\t// as a blocker rather than declaring a prop nothing read.\n\t\t//\n\t\t// `label` stays the app's to write and translate, so nc-vue phrases\n\t\t// nothing for somebody else's domain and adds no catalogue string here.\n\t\t/**\n\t\t * Per-note actions the consuming app owns, `[{ id, label, icon? }]`.\n\t\t * Each entry renders one NcActionButton in every note's action menu,\n\t\t * after the library's own, and clicking it emits `note-action`. Empty\n\t\t * by default, and an empty list changes nothing. `icon` is optional\n\t\t * and takes an icon component.\n\t\t */\n\t\tnoteActions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t\tvalidator: (actions) => actions.every((action) => action\n\t\t\t\t&& typeof action.id === 'string' && action.id !== ''\n\t\t\t\t&& typeof action.label === 'string' && action.label !== ''),\n\t\t},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * Emitted after a note containing at least one `@mention` was\n\t\t * successfully created or edited, with payload\n\t\t * `{ objectId, register, schema, noteId, mentionedUserIds }`, plus\n\t\t * `mentionedGroupIds` when the note mentions a group (`@\"group/<gid>\"`).\n\t\t * The event also fires for a note that mentions only groups. Expanding a\n\t\t * group to its members is the listener's job.\n\t\t * nc-vue never dispatches server-side notifications itself —\n\t\t * consuming apps listen to this event and notify from their own\n\t\t * backend.\n\t\t */\n\t\t'mention',\n\t\t/**\n\t\t * Emitted when one of the consuming app's `noteActions` is clicked,\n\t\t * with payload `{ action, note }`: the entry's `id` and the whole note\n\t\t * as the backend answered it. The library does the rendering and\n\t\t * nothing else, so what the action means stays in the app.\n\t\t */\n\t\t'note-action',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tnotes: [],\n\t\t\tloading: false,\n\t\t\tnewNoteText: '',\n\t\t\tsaving: false,\n\t\t\teditingNoteId: null,\n\t\t\t/** The note whose earlier versions are open, or null. */\n\t\t\thistoryNoteId: null,\n\t\t\t/**\n\t\t\t * Per-instance cache of mentioned-user display names, keyed by\n\t\t\t * user id. `null` marks an id that could not be resolved (unknown\n\t\t\t * or deleted user) so it is only looked up once.\n\t\t\t */\n\t\t\tmentionNames: {},\n\t\t\t/** The note a reply is being written to, or null. */\n\t\t\treplyTo: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {{apiBase: string, register: string, schema: string, objectId: string}} Where this record's files live, for pasted images. */\n\t\trecord() {\n\t\t\treturn { apiBase: this.apiBase, register: this.register, schema: this.schema, objectId: this.objectId }\n\t\t},\n\n\t\t/** @return {boolean} Whether the backend supports replies: its notes carry a `parentId` key. */\n\t\tcanReply() {\n\t\t\treturn supportsReplies(this.notes)\n\t\t},\n\n\t\t/** @return {Array<{note: object, replies: object[]}>} The notes as threads, in the order they came. */\n\t\tthreads() {\n\t\t\treturn threadNotes(this.notes)\n\t\t},\n\n\t\t/** @return {string} The line above the composer while replying. */\n\t\treplyingLabel() {\n\t\t\treturn this.replyTo ? t('nextcloud-vue', 'Replying to {author}', { author: this.authorOf(this.replyTo) }) : ''\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchNotes()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\tasync fetchNotes() {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/notes`),\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tthis.notes = data.results || data || []\n\t\t\t\t\tthis.resolveMentionNames()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNotesTab: Failed to fetch notes', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Resolve display names for every mentioned id across the current\n\t\t * notes list. Each id is looked up at most once per component\n\t\t * instance; unresolvable ids are cached as `null`.\n\t\t */\n\t\tasync resolveMentionNames() {\n\t\t\tconst ids = new Set()\n\t\t\tfor (const note of this.notes) {\n\t\t\t\tfor (const id of extractMentionedIds(note.message || note.content || '')) {\n\t\t\t\t\tids.add(id)\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait Promise.all([...ids]\n\t\t\t\t.filter((id) => !(id in this.mentionNames))\n\t\t\t\t.map(async (id) => {\n\t\t\t\t\t// Mark as pending (null) first so concurrent calls skip it.\n\t\t\t\t\tthis.mentionNames[id] = null\n\t\t\t\t\tconst results = await searchNextcloudUsers(id)\n\t\t\t\t\tconst match = results.find((user) => user.id === id)\n\t\t\t\t\tif (match) {\n\t\t\t\t\t\tthis.mentionNames[id] = match.label\n\t\t\t\t\t}\n\t\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Emit the `mention` notification hook for a successfully saved note.\n\t\t *\n\t\t * @param {string} savedText The note text that was persisted.\n\t\t * @param {string|null} noteId The created/edited note's id.\n\t\t */\n\t\temitMentionEvent(savedText, noteId) {\n\t\t\tconst mentionedUserIds = extractMentionedIds(savedText)\n\t\t\tconst mentionedGroupIds = extractMentionedGroupIds(savedText)\n\t\t\tif (mentionedUserIds.length === 0 && mentionedGroupIds.length === 0) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.$emit('mention', {\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tnoteId,\n\t\t\t\tmentionedUserIds,\n\t\t\t\t// Only when a group is mentioned: a note that names none keeps the payload it always had.\n\t\t\t\t...(mentionedGroupIds.length > 0 ? { mentionedGroupIds } : {}),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Save from the composer (Ctrl/Cmd+Enter): the same as the button.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tsubmitComposer() {\n\t\t\tif (!this.newNoteText.trim() || this.saving) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.editingNoteId) {\n\t\t\t\tthis.saveEdit()\n\t\t\t} else {\n\t\t\t\tthis.addNote()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note A note.\n\t\t * @return {string} Its author's name.\n\t\t */\n\t\tauthorOf(note) {\n\t\t\treturn note.actorDisplayName || note.author || 'Unknown'\n\t\t},\n\n\t\t/**\n\t\t * Write a reply to a note. A reply to a reply goes to the top of its thread.\n\t\t *\n\t\t * @param {object} note The note answered.\n\t\t * @return {void}\n\t\t */\n\t\tstartReply(note) {\n\t\t\tthis.editingNoteId = null\n\t\t\tthis.replyTo = note\n\t\t},\n\n\t\tcancelReply() {\n\t\t\tthis.replyTo = null\n\t\t},\n\n\t\t/**\n\t\t * The rows of one thread: the note, then its replies. A reply whose parent\n\t\t * is far up the list carries a one-line quote of it.\n\t\t *\n\t\t * @param {{note: object, replies: object[]}} thread The thread.\n\t\t * @return {Array<{note: object, isReply: boolean, quote: string}>} The rows.\n\t\t */\n\t\tthreadRows(thread) {\n\t\t\tconst flat = this.threads.flatMap((t2) => [t2.note, ...t2.replies])\n\t\t\treturn [\n\t\t\t\t{ note: thread.note, isReply: false, quote: '' },\n\t\t\t\t...thread.replies.map((reply) => ({ note: reply, isReply: true, quote: quoteFor(reply, flat) })),\n\t\t\t]\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note A top-level note.\n\t\t * @return {string} The name of its thread for assistive technology.\n\t\t */\n\t\tthreadLabel(note) {\n\t\t\treturn t('nextcloud-vue', 'Note by {author} and its replies', { author: this.authorOf(note) })\n\t\t},\n\n\t\t/**\n\t\t * @param {object} note The note a Reply button answers.\n\t\t * @return {string} The button's accessible name, naming the author.\n\t\t */\n\t\treplyAria(note) {\n\t\t\treturn t('nextcloud-vue', 'Reply to {author}', { author: this.authorOf(note) })\n\t\t},\n\n\t\tasync addNote() {\n\t\t\tif (!this.newNoteText.trim()) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tconst savedText = this.newNoteText.trim()\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/notes`),\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t\t\tbody: JSON.stringify(this.replyTo\n\t\t\t\t\t\t\t? { message: savedText, parentId: threadRootId(this.replyTo, this.notes) }\n\t\t\t\t\t\t\t: { message: savedText }),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tlet noteId = null\n\t\t\t\ttry {\n\t\t\t\t\tconst created = await response.json()\n\t\t\t\t\tnoteId = (created && (created.id || (created.results && created.results.id))) || null\n\t\t\t\t} catch {\n\t\t\t\t\t// Body not JSON — the event still fires with noteId null.\n\t\t\t\t}\n\t\t\t\tthis.emitMentionEvent(savedText, noteId)\n\t\t\t\tthis.newNoteText = ''\n\t\t\t\tthis.replyTo = null\n\t\t\t\tawait this.fetchNotes()\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNotesTab: Failed to add note', err)\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fill the composer from outside, for the `composer-before` slot.\n\t\t *\n\t\t * The app decides what goes in (a template body, a quoted line); the\n\t\t * composer stays the one place the text lives, so sending, editing and\n\t\t * the mention picker all see it exactly as if it had been typed.\n\t\t *\n\t\t * @param {string} text The text the composer should hold.\n\t\t * @return {void}\n\t\t */\n\t\tsetComposerText(text) {\n\t\t\tthis.newNoteText = (text === null || text === undefined) ? '' : String(text)\n\t\t},\n\n\t\tstartEdit(note) {\n\t\t\tthis.replyTo = null\n\t\t\tthis.editingNoteId = note.id\n\t\t\tthis.newNoteText = note.message || note.content || ''\n\t\t},\n\n\t\tcancelEdit() {\n\t\t\tthis.editingNoteId = null\n\t\t\tthis.newNoteText = ''\n\t\t},\n\n\t\tasync saveEdit() {\n\t\t\tif (!this.newNoteText.trim() || !this.editingNoteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.saving = true\n\t\t\tconst savedText = this.newNoteText.trim()\n\t\t\tconst noteId = this.editingNoteId\n\t\t\ttry {\n\t\t\t\tawait fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/notes/${noteId}`),\n\t\t\t\t\t{\n\t\t\t\t\t\tmethod: 'PUT',\n\t\t\t\t\t\theaders: buildHeaders(),\n\t\t\t\t\t\tbody: JSON.stringify({ message: savedText }),\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t\tthis.emitMentionEvent(savedText, noteId)\n\t\t\t\tthis.editingNoteId = null\n\t\t\t\tthis.newNoteText = ''\n\t\t\t\tawait this.fetchNotes()\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNotesTab: Failed to update note', err)\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\n\t\tcanDelete(note) {\n\t\t\treturn note.actorId === OC?.currentUser || note.author === OC?.currentUser\n\t\t},\n\n\t\t/**\n\t\t * Whether this note carries a history to show.\n\t\t *\n\t\t * Read off `versionCount` rather than off `editedAt`: a note edited by\n\t\t * a since-deleted account still has its prior texts, and a marker that\n\t\t * depended on the editor still existing would quietly vanish.\n\t\t *\n\t\t * @param {object} note The note from the backend.\n\t\t * @return {boolean} True when at least one earlier version exists.\n\t\t */\n\t\twasEdited(note) {\n\t\t\treturn Number(note.versionCount || 0) > 0\n\t\t},\n\n\t\t/**\n\t\t * The \"edited\" line beside a note's time.\n\t\t *\n\t\t * @param {object} note The note from the backend.\n\t\t * @return {string} The rendered line.\n\t\t */\n\t\teditedLine(note) {\n\t\t\tconst editor = note.editedByDisplayName || note.editedBy\n\t\t\tif (!editor) {\n\t\t\t\treturn t('nextcloud-vue', 'Edited')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Edited by {editor}', { editor })\n\t\t},\n\n\t\t/**\n\t\t * Open the earlier versions of one note.\n\t\t *\n\t\t * @param {object} note The note to open.\n\t\t */\n\t\topenHistory(note) {\n\t\t\tthis.historyNoteId = note.id\n\t\t},\n\n\t\tasync deleteNote(note) {\n\t\t\ttry {\n\t\t\t\tawait fetch(\n\t\t\t\t\tprefixUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/notes/${note.id}`),\n\t\t\t\t\t{ method: 'DELETE', headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tthis.notes = this.notes.filter((n) => n.id !== note.id)\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNotesTab: Failed to delete note', err)\n\t\t\t}\n\t\t},\n\n\t\tformatDate(dateStr) {\n\t\t\tif (!dateStr) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(dateStr).toLocaleString(userLocale(), {\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\thour: '2-digit',\n\t\t\t\t\tminute: '2-digit',\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn dateStr\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__action { margin-bottom: 16px; }\n\n.cn-sidebar-tab__action--row { display: flex; gap: 8px; align-items: flex-end; margin-top: 8px; }\n\n.cn-sidebar-tab__composer {\n\twidth: 100%;\n}\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }\n\n.cn-notes-tab__thread { list-style: none; }\n\n.cn-notes-tab__thread-list { margin: 0; padding: 0; list-style: none; }\n\n.cn-notes-tab__reply { margin-inline-start: 24px; }\n\n.cn-notes-tab__quote {\n\tdisplay: block;\n\tmargin-bottom: 2px;\n\tpadding-inline-start: 8px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-sidebar-tab__replying {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tmargin: 0 0 4px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-notes-tab__edited {\n\tcolor: var(--color-text-maxcontrast);\n\tmargin-inline-start: 6px;\n\tfont-style: italic;\n}\n\n</style>\n"],"names":["CnNoteBody","CnNoteComposer","CnNoteHistoryDialog","HistoryIcon","t"],"mappings":"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"}
|