@conduction/nextcloud-vue 2.56.0-beta.37 → 2.56.0-beta.38
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 +28 -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/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/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 +994 -909
- 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 +55 -3
- package/dist/esm/utils/boardReferenceColumns.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 +837 -359
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +994 -909
- 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 +28 -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/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/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 +2 -1
- package/src/store/useObjectStore.js +7 -2
- package/src/utils/boardColumns.js +49 -0
- package/src/utils/boardReferenceColumns.js +54 -2
- 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":"CnVersionHistory.vue2.js","sources":["../../../../src/components/CnVersionHistory/CnVersionHistory.vue"],"sourcesContent":["<!--\n CnVersionHistory — object version-history + field-by-field diff\n viewer for the integration registry.\n\n Lists an OpenRegister object's audit-trail entries (timestamp, user,\n semantic version, action) newest-first, and lets the user open a\n structural diff for one entry, or \"compare\" two checked entries.\n OpenRegister only stores a per-field `changed` delta per entry (no\n full before/after snapshot), so a multi-entry compare is\n reconstructed by folding the range's deltas (`foldAuditTrailEntries`)\n before diffing (`computeObjectDiff`) — see the `version-diff-viewer`\n openspec change's design notes.\n-->\n<template>\n\t<CnDetailCard\n\t\t:title=\"resolvedTitle\"\n\t\t:icon=\"FileCompare\"\n\t\t:collapsible=\"collapsible\"\n\t\t:data-surface=\"surface\">\n\t\t<NcLoadingIcon v-if=\"loading && entries.length === 0\" />\n\t\t<div v-else-if=\"entries.length === 0\" class=\"cn-version-history__empty\">\n\t\t\t{{ noEntriesLabel }}\n\t\t</div>\n\t\t<div v-else-if=\"activeDiff === null\" class=\"cn-version-history__list\">\n\t\t\t<ul class=\"cn-version-history__rows\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"entry in entries\"\n\t\t\t\t\t:key=\"entry.id\"\n\t\t\t\t\tclass=\"cn-version-history__row\">\n\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t:modelValue=\"isSelected(entry.id)\"\n\t\t\t\t\t\t:disabled=\"isSelected(entry.id) === false && selectedIds.length >= 2\"\n\t\t\t\t\t\t:aria-label=\"selectForCompareLabel\"\n\t\t\t\t\t\t@update:modelValue=\"toggleSelected(entry.id, $event)\" />\n\t\t\t\t\t<button class=\"cn-version-history__row-main\" type=\"button\" @click=\"openSingleDiff(entry)\">\n\t\t\t\t\t\t<span class=\"cn-version-history__version\">{{ entry.version || fallbackVersionLabel }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__action\">{{ entry.action || '' }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__when\">{{ formatWhen(entry) }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__user\">{{ formatUser(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div class=\"cn-version-history__toolbar\">\n\t\t\t\t<NcButton\n\t\t\t\t\t:disabled=\"selectedIds.length !== 2\"\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t@click=\"openCompareDiff\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Compare :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ compareLabel }}\n\t\t\t\t</NcButton>\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:disabled=\"loadingMore\"\n\t\t\t\t\t@click=\"loadMore\">\n\t\t\t\t\t{{ loadMoreLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<div v-else class=\"cn-version-history__diff\">\n\t\t\t<div class=\"cn-version-history__diff-toolbar\">\n\t\t\t\t<NcButton variant=\"tertiary\" @click=\"closeDiff\">\n\t\t\t\t\t{{ backLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcCheckboxRadioSwitch :modelValue=\"showAllFields\" @update:modelValue=\"showAllFields = $event\">\n\t\t\t\t\t{{ showAllFieldsLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</div>\n\t\t\t<table v-if=\"visibleDiffRows.length > 0\" class=\"cn-version-history__diff-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>{{ fieldLabel }}</th>\n\t\t\t\t\t\t<th>{{ oldValueLabel }}</th>\n\t\t\t\t\t\t<th>{{ newValueLabel }}</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr v-for=\"row in visibleDiffRows\" :key=\"row.path\" :class=\"rowClass(row.type)\">\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-field\">\n\t\t\t\t\t\t\t{{ row.path }}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-value\">\n\t\t\t\t\t\t\t<component :is=\"valueCellTag(row)\" v-bind=\"valueCellProps(row)\">\n\t\t\t\t\t\t\t\t<template v-if=\"isNestedValue(row) === true\">\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tv-for=\"line in nestedLines(row, 'old')\"\n\t\t\t\t\t\t\t\t\t\t:key=\"line.path\"\n\t\t\t\t\t\t\t\t\t\t:class=\"lineClass(line.type)\">\n\t\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t\t{{ formatScalar(row.oldValue) }}\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-value\">\n\t\t\t\t\t\t\t<component :is=\"valueCellTag(row)\" v-bind=\"valueCellProps(row)\">\n\t\t\t\t\t\t\t\t<template v-if=\"isNestedValue(row) === true\">\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tv-for=\"line in nestedLines(row, 'new')\"\n\t\t\t\t\t\t\t\t\t\t:key=\"line.path\"\n\t\t\t\t\t\t\t\t\t\t:class=\"lineClass(line.type)\">\n\t\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t\t{{ formatScalar(row.newValue) }}\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t\t<div v-else class=\"cn-version-history__diff-empty\">\n\t\t\t\t{{ noChangesLabel }}\n\t\t\t</div>\n\t\t</div>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport Compare from 'vue-material-design-icons/Compare.vue'\nimport FileCompare from 'vue-material-design-icons/FileCompare.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport { foldAuditTrailEntries } from '../../utils/auditTrailDiff.js'\nimport { computeObjectDiff } from '../../utils/computeObjectDiff.js'\nimport { buildHeaders } from '../../utils/index.js'\n\n/**\n * A single row rendered in the top-level diff table.\n *\n * @typedef {object} FieldDiffRow\n * @property {string} path Field name.\n * @property {'added'|'removed'|'changed'|'unchanged'} type Classification.\n * @property {unknown} oldValue Value before.\n * @property {unknown} newValue Value after.\n */\n\n/**\n * Classify one top-level field between two folded states, reusing\n * `computeObjectDiff` to decide equality (so nested objects/arrays are\n * compared structurally, not by reference).\n *\n * @param {string} key Field name.\n * @param {object} oldState Folded \"before\" state.\n * @param {object} newState Folded \"after\" state.\n * @return {FieldDiffRow} The classified row.\n */\nfunction classifyField(key, oldState, newState) {\n\tconst oldMissing = Object.hasOwn(oldState, key) === false\n\tconst newMissing = Object.hasOwn(newState, key) === false\n\tconst oldValue = oldState[key]\n\tconst newValue = newState[key]\n\n\tif (oldMissing === true && newMissing === false) {\n\t\treturn { path: key, type: 'added', oldValue: undefined, newValue }\n\t}\n\tif (oldMissing === false && newMissing === true) {\n\t\treturn { path: key, type: 'removed', oldValue, newValue: undefined }\n\t}\n\tconst nested = computeObjectDiff(oldValue, newValue)\n\tconst isChanged = nested.some((entry) => entry.type !== 'unchanged')\n\treturn { path: key, type: isChanged ? 'changed' : 'unchanged', oldValue, newValue }\n}\n\n/**\n * Build the top-level field-by-field diff table for a folded\n * before/after state pair.\n *\n * @param {object} oldState Folded \"before\" state.\n * @param {object} newState Folded \"after\" state.\n * @return {FieldDiffRow[]} One row per touched field, sorted by field name.\n */\nfunction buildFieldRows(oldState, newState) {\n\tconst keys = Array.from(new Set([...Object.keys(oldState), ...Object.keys(newState)])).sort()\n\treturn keys.map((key) => classifyField(key, oldState, newState))\n}\n\n/**\n * CnVersionHistory — object version-history list plus field-by-field\n * diff viewer, rendered by the integration registry on sidebar-tab\n * and dashboard/detail-widget surfaces alike.\n *\n * Basic usage\n * ```vue\n * <CnVersionHistory\n * :register=\"registerId\"\n * :schema=\"schemaId\"\n * :object-id=\"objectId\"\n * surface=\"detail-page\" />\n * ```\n */\nexport default {\n\tname: 'CnVersionHistory',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, NcButton, NcCheckboxRadioSwitch, Compare },\n\n\tprops: {\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface — passed for AD-19 surface fallback consumers. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (value) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(value),\n\t\t},\n\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Number of history entries to fetch per page. */\n\t\tpageSize: { type: Number, default: 20 },\n\t\t/** Whether the card collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Pre-translated empty-history label. */\n\t\tnoEntriesLabel: { type: String, default: () => t('nextcloud-vue', 'No version history yet') },\n\t\t/** Pre-translated fallback shown when an entry carries no semantic version. */\n\t\tfallbackVersionLabel: { type: String, default: () => t('nextcloud-vue', 'Unversioned change') },\n\t\t/** Pre-translated \"select for compare\" checkbox label. */\n\t\tselectForCompareLabel: { type: String, default: () => t('nextcloud-vue', 'Select for compare') },\n\t\t/** Pre-translated compare-action label. */\n\t\tcompareLabel: { type: String, default: () => t('nextcloud-vue', 'Compare selected') },\n\t\t/** Pre-translated load-more label. */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/** Pre-translated back-to-list label. */\n\t\tbackLabel: { type: String, default: () => t('nextcloud-vue', 'Back to history') },\n\t\t/** Pre-translated \"show all fields\" toggle label. */\n\t\tshowAllFieldsLabel: { type: String, default: () => t('nextcloud-vue', 'Show all fields') },\n\t\t/** Pre-translated diff table field-column header. */\n\t\tfieldLabel: { type: String, default: () => t('nextcloud-vue', 'Field') },\n\t\t/** Pre-translated diff table old-value-column header. */\n\t\toldValueLabel: { type: String, default: () => t('nextcloud-vue', 'Old value') },\n\t\t/** Pre-translated diff table new-value-column header. */\n\t\tnewValueLabel: { type: String, default: () => t('nextcloud-vue', 'New value') },\n\t\t/** Pre-translated label shown when a diff has no visible rows. */\n\t\tnoChangesLabel: { type: String, default: () => t('nextcloud-vue', 'No field changes to show') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tFileCompare: markRaw(FileCompare),\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tselectedIds: [],\n\t\t\t/** `null` = list view; otherwise `{ oldState, newState }` for the open diff. */\n\t\t\tactiveDiff: null,\n\t\t\tshowAllFields: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Version history')\n\t\t},\n\n\t\thasMore() {\n\t\t\treturn this.entries.length < this.total\n\t\t},\n\n\t\tdiffRows() {\n\t\t\tif (this.activeDiff === null) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn buildFieldRows(this.activeDiff.oldState, this.activeDiff.newState)\n\t\t},\n\n\t\tvisibleDiffRows() {\n\t\t\tif (this.showAllFields === true) {\n\t\t\t\treturn this.diffRows\n\t\t\t}\n\t\t\treturn this.diffRows.filter((row) => row.type !== 'unchanged')\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.resetAndFetch()\n\t\t\t\t}\n\t\t\t},\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.selectedIds = []\n\t\t\tthis.activeDiff = null\n\t\t\tthis.fetchEntries()\n\t\t},\n\n\t\tasync fetchEntries() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\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 params = new URLSearchParams()\n\t\t\t\tparams.set('limit', String(this.pageSize))\n\t\t\t\tparams.set('_page', String(this.page))\n\t\t\t\tparams.set('_sort[created]', 'DESC')\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(`${url}?${params.toString()}`, { headers: buildHeaders() })\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\tthis.entries = this.page === 1 ? results : [...this.entries, ...results]\n\t\t\t\t\tthis.total = data.total || this.entries.length\n\t\t\t\t} else if (this.page === 1) {\n\t\t\t\t\tthis.entries = []\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('[CnVersionHistory] failed to fetch version history', err)\n\t\t\t\tif (this.page === 1) {\n\t\t\t\t\tthis.entries = []\n\t\t\t\t}\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\tloadMore() {\n\t\t\tthis.page += 1\n\t\t\tthis.fetchEntries()\n\t\t},\n\n\t\tisSelected(id) {\n\t\t\treturn this.selectedIds.includes(id)\n\t\t},\n\n\t\ttoggleSelected(id, checked) {\n\t\t\tif (checked === true) {\n\t\t\t\tif (this.selectedIds.includes(id) === false && this.selectedIds.length < 2) {\n\t\t\t\t\tthis.selectedIds = [...this.selectedIds, id]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.selectedIds = this.selectedIds.filter((existing) => existing !== id)\n\t\t\t}\n\t\t},\n\n\t\topenSingleDiff(entry) {\n\t\t\tconst { oldState, newState } = foldAuditTrailEntries([entry])\n\t\t\tthis.showAllFields = false\n\t\t\tthis.activeDiff = { oldState, newState }\n\t\t},\n\n\t\topenCompareDiff() {\n\t\t\tif (this.selectedIds.length !== 2) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Entries are fetched newest-first; fold oldest-first so the\n\t\t\t// \"first old\" / \"last new\" semantics land on the right side.\n\t\t\tconst selectedEntries = this.entries.filter((entry) => this.selectedIds.includes(entry.id))\n\t\t\tconst chronological = [...selectedEntries].reverse()\n\t\t\tconst { oldState, newState } = foldAuditTrailEntries(chronological)\n\t\t\tthis.showAllFields = false\n\t\t\tthis.activeDiff = { oldState, newState }\n\t\t},\n\n\t\tcloseDiff() {\n\t\t\tthis.activeDiff = null\n\t\t},\n\n\t\tisNestedValue(row) {\n\t\t\tconst isObj = (v) => v !== null && typeof v === 'object'\n\t\t\treturn isObj(row.oldValue) === true || isObj(row.newValue) === true\n\t\t},\n\n\t\t/**\n\t\t * Build the per-line nested diff for one side of a table cell\n\t\t * whose value is an object/array, so each nested key can be\n\t\t * individually add/remove/change tinted.\n\t\t *\n\t\t * @param {FieldDiffRow} row The parent field row.\n\t\t * @param {'old'|'new'} side Which side is being rendered (both sides render the same nested diff so add/remove/change context matches on both columns).\n\t\t * @return {Array<{path: string, type: string, text: string}>} Rendered lines.\n\t\t */\n\t\tnestedLines(row, side) {\n\t\t\tconst base = row.oldValue !== null && typeof row.oldValue === 'object' ? row.oldValue : {}\n\t\t\tconst next = row.newValue !== null && typeof row.newValue === 'object' ? row.newValue : {}\n\t\t\tconst from = row.type === 'added' ? {} : base\n\t\t\tconst to = row.type === 'removed' ? {} : next\n\t\t\tconst nested = computeObjectDiff(from, to)\n\t\t\tconst visible = this.showAllFields === true ? nested : nested.filter((entry) => entry.type !== 'unchanged')\n\t\t\treturn visible.map((entry) => ({\n\t\t\t\tpath: entry.path,\n\t\t\t\ttype: entry.type,\n\t\t\t\ttext: this.formatNestedLine(entry, side),\n\t\t\t}))\n\t\t},\n\n\t\tformatNestedLine(entry, side) {\n\t\t\tconst label = entry.path === '' ? '·' : entry.path\n\t\t\tif (entry.type === 'changed') {\n\t\t\t\tconst shown = side === 'new' ? entry.newValue : entry.oldValue\n\t\t\t\treturn `${label}: ${this.formatScalar(shown)}`\n\t\t\t}\n\t\t\tconst value = entry.type === 'removed' ? entry.oldValue : entry.newValue\n\t\t\treturn `${label}: ${this.formatScalar(value)}`\n\t\t},\n\n\t\trowClass(type) {\n\t\t\treturn {\n\t\t\t\t'cn-version-history__diff-row': true,\n\t\t\t\t[`cn-version-history__diff-row--${type}`]: true,\n\t\t\t}\n\t\t},\n\n\t\tlineClass(type) {\n\t\t\treturn {\n\t\t\t\t'cn-version-history__diff-line': true,\n\t\t\t\t[`cn-version-history__diff-line--${type}`]: true,\n\t\t\t}\n\t\t},\n\n\t\tvalueCellTag(row) {\n\t\t\treturn this.isNestedValue(row) === true ? 'pre' : 'span'\n\t\t},\n\n\t\tvalueCellProps(row) {\n\t\t\treturn this.isNestedValue(row) === true ? { class: 'cn-version-history__diff-json' } : {}\n\t\t},\n\n\t\tformatScalar(value) {\n\t\t\tif (value === undefined) {\n\t\t\t\treturn '—'\n\t\t\t}\n\t\t\tif (value === null) {\n\t\t\t\treturn 'null'\n\t\t\t}\n\t\t\tif (typeof value === 'object') {\n\t\t\t\ttry {\n\t\t\t\t\treturn JSON.stringify(value)\n\t\t\t\t} catch {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn String(value)\n\t\t},\n\n\t\tformatUser(entry) {\n\t\t\treturn entry.userName || entry.user || t('nextcloud-vue', 'System')\n\t\t},\n\n\t\tformatWhen(entry) {\n\t\t\tconst raw = entry.created || entry.creationDateTime || entry.timestamp\n\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst d = new Date(raw)\n\t\t\tif (Number.isNaN(d.getTime()) === true) {\n\t\t\t\treturn String(raw)\n\t\t\t}\n\t\t\treturn d.toLocaleString()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-history__empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n\n.cn-version-history__rows {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-version-history__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-history__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-history__row-main {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\talign-items: baseline;\n\tflex: 1 1 auto;\n\tbackground: none;\n\tborder: none;\n\tcursor: pointer;\n\ttext-align: left;\n\tfont: inherit;\n\tcolor: inherit;\n\tpadding: 4px;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-version-history__row-main:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-version-history__version {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-history__action {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-version-history__when {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\twhite-space: nowrap;\n}\n\n.cn-version-history__user {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-version-history__toolbar {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-top: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-version-history__diff-toolbar {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-version-history__diff-table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-version-history__diff-table th,\n.cn-version-history__diff-table td {\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding: 6px 8px;\n\ttext-align: left;\n\tvertical-align: top;\n}\n\n.cn-version-history__diff-field {\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\twhite-space: nowrap;\n}\n\n.cn-version-history__diff-json {\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n\tfont-family: monospace;\n\tfont-size: 12px;\n}\n\n.cn-version-history__diff-row--added .cn-version-history__diff-field {\n\tcolor: var(--color-success);\n}\n\n.cn-version-history__diff-row--removed .cn-version-history__diff-field {\n\tcolor: var(--color-error);\n}\n\n.cn-version-history__diff-row--changed .cn-version-history__diff-field {\n\tcolor: var(--color-warning);\n}\n\n.cn-version-history__diff-line--added {\n\tbackground-color: color-mix(in srgb, var(--color-success) 15%, transparent);\n\tcolor: var(--color-success);\n}\n\n.cn-version-history__diff-line--removed {\n\tbackground-color: color-mix(in srgb, var(--color-error) 15%, transparent);\n\tcolor: var(--color-error);\n\ttext-decoration: line-through;\n}\n\n.cn-version-history__diff-line--changed {\n\tbackground-color: color-mix(in srgb, var(--color-warning) 15%, transparent);\n\tcolor: var(--color-warning);\n}\n\n.cn-version-history__diff-line--unchanged {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-version-history__diff-empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n</style>\n"],"names":["CnDetailCard","t"],"mappings":";;;;;;;;;;;AAuIA;AACC;AACA;;AAEA;AACA;AACA;AACA;;;AAGD;;;AAGC;AACA;;AAEA;AACA;AACA;;AAED,SAAS,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE;CAC/C,MAAM,UAAS,GAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAE,KAAI,MAAI;CACxD,MAAM,UAAS,GAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAE,KAAI,MAAI;CACxD,MAAM,QAAO,GAAI,QAAQ,CAAC,GAAG,EAAA;CAC7B,MAAM,QAAO,GAAI,QAAQ,CAAC,GAAG,EAAA;;AAE7B,CAAA,IAAI,UAAW,KAAI,IAAG,IAAK,UAAW,KAAI,KAAK,EAAE;EAChD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAS,EAAA;AAClE,EAAA;AACA,CAAA,IAAI,UAAW,KAAI,KAAM,IAAG,UAAS,KAAM,IAAI,EAAE;EAChD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAU,EAAA;AACpE,EAAA;CACA,MAAM,MAAK,GAAI,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAA;CACnD,MAAM,SAAQ,GAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAK,KAAI,WAAW,EAAA;AACnE,CAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAQ,GAAI,SAAU,GAAE,WAAW,EAAE,QAAQ,EAAE,QAAS,EAAA;AACnF,CAAA;;AAEA;;;AAGC;AACA;AACA;AACA;;AAED,SAAS,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE;AAC3C,CAAA,MAAM,IAAK,GAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAC;CAC5F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;AAChE,CAAA;;AAEA;;;AAGC;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAED,aAAe;CACd,IAAI,EAAE,kBAAkB;;AAExB,CAAA,UAAU,EAAE,gBAAEA,UAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,qBAAqB,EAAE,SAAS;;AAErF,CAAA,KAAK,EAAE;AACN;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;AAC1C;AACA,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;AACxC;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;AAE1C,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,aAAa;GACtB,SAAS,EAAE,CAAC,KAAK,KAAK,CAAC,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;GACzG;;AAED;EACA,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAuB,EAAG;AAC5D;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;;AAEvC,EAAA,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;;AAE9C,EAAA,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAC,EAAG;AACpC;AACA,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,wBAAwB,GAAG;AAC7F;AACA,EAAA,oBAAoB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,oBAAoB,GAAG;;AAE/F,EAAA,qBAAqB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,oBAAoB,GAAG;AAChG;AACA,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,kBAAkB,GAAG;AACrF;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;AAC/E;AACA,EAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,iBAAiB,GAAG;AACjF;AACA,EAAA,kBAAkB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,iBAAiB,GAAG;;AAE1F,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,OAAO,GAAG;;AAExE,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;;AAE/E,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;;AAE/E,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,0BAA0B,GAAG;EAC/F;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;AACN,GAAA,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC;GACjC,OAAO,EAAE,EAAE;GACX,OAAO,EAAE,KAAK;AACd,GAAA,WAAW,EAAE,KAAK;AAClB,GAAA,IAAI,EAAE,CAAC;AACP,GAAA,KAAK,EAAE,CAAC;AACR,GAAA,WAAW,EAAE,EAAE;AACf;AACA,GAAA,UAAU,EAAE,IAAI;AAChB,GAAA,aAAa,EAAE,KAAK;AACrB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT,EAAA,aAAa,GAAG;GACf,OAAO,IAAI,CAAC,KAAM,IAAGA,SAAC,CAAC,eAAe,EAAE,iBAAiB,CAAA;GACzD;;AAED,EAAA,OAAO,GAAG;AACT,GAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAO,GAAE,IAAI,CAAC,KAAI;GACtC;;EAED,QAAQ,GAAG;GACV,IAAI,IAAI,CAAC,UAAS,KAAM,IAAI,EAAE;AAC7B,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,OAAO,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAA;GACxE;;AAED,EAAA,eAAe,GAAG;GACjB,IAAI,IAAI,CAAC,aAAc,KAAI,IAAI,EAAE;AAChC,IAAA,OAAO,IAAI,CAAC,QAAO;AACpB,IAAA;GACA,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,IAAG,KAAM,WAAW,CAAA;GAC7D;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,QAAQ,EAAE;AACT,GAAA,SAAS,EAAE,IAAI;GACf,OAAO,CAAC,EAAE,EAAE;AACX,IAAA,IAAI,EAAE,EAAE;AACP,KAAA,IAAI,CAAC,aAAa,GAAC;AACpB,KAAA;IACA;GACD;EACD;;AAED,CAAA,OAAO,EAAE;AACR,EAAA,aAAa,GAAG;GACf,IAAI,CAAC,OAAO,EAAA;AACZ,GAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AAChB,GAAA,IAAI,CAAC,WAAU,GAAI,GAAC;AACpB,GAAA,IAAI,CAAC,aAAa,KAAG;AACrB,GAAA,IAAI,CAAC,YAAY,GAAC;GAClB;;AAED,EAAA,MAAM,YAAY,GAAG;GACpB,IAAI,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE;IACrD,MAAK;AACN,IAAA;GACA,IAAI,CAAC,OAAM,GAAI,IAAI,CAAC,IAAG,KAAM,EAAA;GAC7B,IAAI,CAAC,WAAU,GAAI,IAAI,CAAC,IAAG,GAAI,EAAA;AAC/B,GAAA,IAAI;AACH,IAAA,MAAM,MAAK,GAAI,IAAI,eAAe,GAAC;AACnC,IAAA,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAA;AACzC,IAAA,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAA;AACrC,IAAA,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,EAAA;IACnC,MAAM,GAAE,GAAI,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAA;AAC/G,IAAA,MAAM,QAAS,GAAE,MAAM,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AACvF,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;KAChB,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;AACjC,KAAA,MAAM,OAAM,GAAI,IAAI,CAAC,OAAQ,IAAG,IAAK,IAAG,GAAC;AACzC,KAAA,IAAI,CAAC,OAAQ,GAAE,IAAI,CAAC,IAAK,KAAI,CAAE,GAAE,OAAQ,GAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,OAAO,EAAA;AACvE,KAAA,IAAI,CAAC,KAAM,GAAE,IAAI,CAAC,KAAM,IAAG,IAAI,CAAC,OAAO,CAAC,OAAK;KAC5C,MAAK,IAAI,IAAI,CAAC,IAAG,KAAM,CAAC,EAAE;AAC3B,KAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AACjB,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,GAAG,EAAA;AACvE,IAAA,IAAI,IAAI,CAAC,IAAK,KAAI,CAAC,EAAE;AACpB,KAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AACjB,KAAA;AACD,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,OAAQ,GAAE,MAAI;AACnB,IAAA,IAAI,CAAC,WAAU,GAAI,MAAI;AACxB,IAAA;GACA;;EAED,QAAQ,GAAG;GACV,IAAI,CAAC,IAAK,IAAG,EAAA;AACb,GAAA,IAAI,CAAC,YAAY,GAAC;GAClB;;AAED,EAAA,UAAU,CAAC,EAAE,EAAE;AACd,GAAA,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAA;GACnC;;EAED,cAAc,CAAC,EAAE,EAAE,OAAO,EAAE;AAC3B,GAAA,IAAI,OAAQ,KAAI,IAAI,EAAE;AACrB,IAAA,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAI,IAAK,IAAI,CAAC,WAAW,CAAC,MAAO,GAAE,CAAC,EAAE;AAC3E,KAAA,IAAI,CAAC,WAAY,GAAE,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,EAAA;AAC5C,KAAA;IACC,MAAK;AACN,IAAA,IAAI,CAAC,WAAU,GAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,KAAK,QAAS,KAAI,EAAE,EAAA;AACzE,IAAA;GACA;;AAED,EAAA,cAAc,CAAC,KAAK,EAAE;GACrB,MAAM,EAAE,QAAQ,EAAE,QAAO,EAAI,GAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,EAAA;GAC5D,IAAI,CAAC,gBAAgB,MAAI;AACzB,GAAA,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,QAAS,GAAA;GACvC;;AAED,EAAA,eAAe,GAAG;AACjB,GAAA,IAAI,IAAI,CAAC,WAAW,CAAC,MAAO,KAAI,CAAC,EAAE;IAClC,MAAK;AACN,IAAA;;;AAGA,GAAA,MAAM,eAAc,GAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAA;GAC1F,MAAM,gBAAgB,CAAC,GAAG,eAAe,CAAC,CAAC,OAAO,GAAC;GACnD,MAAM,EAAE,QAAQ,EAAE,QAAS,EAAA,GAAI,qBAAqB,CAAC,aAAa,EAAA;GAClE,IAAI,CAAC,gBAAgB,MAAI;AACzB,GAAA,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,QAAS,GAAA;GACvC;;EAED,SAAS,GAAG;AACX,GAAA,IAAI,CAAC,aAAa,KAAG;GACrB;;AAED,EAAA,aAAa,CAAC,GAAG,EAAE;AAClB,GAAA,MAAM,KAAI,GAAI,CAAC,CAAC,KAAK,CAAE,KAAI,QAAQ,OAAO,MAAM,SAAO;GACvD,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAA,KAAM,IAAG,IAAK,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAE,KAAI,IAAG;GAClE;;AAED;;;AAGC;AACA;AACA;AACA;AACA;;AAED,EAAA,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE;AACtB,GAAA,MAAM,IAAK,GAAE,GAAG,CAAC,QAAO,KAAM,IAAG,IAAK,OAAO,GAAG,CAAC,aAAa,QAAS,GAAE,GAAG,CAAC,QAAO,GAAI,GAAC;AACzF,GAAA,MAAM,IAAK,GAAE,GAAG,CAAC,QAAO,KAAM,IAAG,IAAK,OAAO,GAAG,CAAC,aAAa,QAAS,GAAE,GAAG,CAAC,QAAO,GAAI,GAAC;AACzF,GAAA,MAAM,IAAK,GAAE,GAAG,CAAC,IAAK,KAAI,OAAM,GAAI,EAAC,GAAI,KAAG;AAC5C,GAAA,MAAM,EAAG,GAAE,GAAG,CAAC,IAAK,KAAI,SAAQ,GAAI,EAAC,GAAI,KAAG;AAC5C,GAAA,MAAM,SAAS,iBAAiB,CAAC,IAAI,EAAE,EAAE,EAAA;AACzC,GAAA,MAAM,OAAQ,GAAE,IAAI,CAAC,aAAY,KAAM,OAAO,MAAO,GAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAG,KAAM,WAAW,EAAA;GAC1G,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM;AAC9B,IAAA,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,IAAA,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,IAAA,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC;AACzC,IAAC,CAAC,CAAA;GACF;;EAED,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE;AAC7B,GAAA,MAAM,KAAM,GAAE,KAAK,CAAC,IAAK,KAAI,EAAG,GAAE,GAAE,GAAI,KAAK,CAAC,KAAG;GACjD,IAAI,KAAK,CAAC,IAAG,KAAM,SAAS,EAAE;IAC7B,MAAM,KAAI,GAAI,IAAG,KAAM,KAAM,GAAE,KAAK,CAAC,QAAS,GAAE,KAAK,CAAC,SAAO;AAC7D,IAAA,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;AAC9C,IAAA;AACA,GAAA,MAAM,KAAM,GAAE,KAAK,CAAC,IAAG,KAAM,SAAQ,GAAI,KAAK,CAAC,QAAS,GAAE,KAAK,CAAC,SAAO;AACvE,GAAA,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;GAC7C;;AAED,EAAA,QAAQ,CAAC,IAAI,EAAE;AACd,GAAA,OAAO;AACN,IAAA,8BAA8B,EAAE,IAAI;IACpC,CAAC,CAAC,8BAA8B,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI;AAChD,IAAA;GACA;;AAED,EAAA,SAAS,CAAC,IAAI,EAAE;AACf,GAAA,OAAO;AACN,IAAA,+BAA+B,EAAE,IAAI;IACrC,CAAC,CAAC,+BAA+B,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI;AACjD,IAAA;GACA;;AAED,EAAA,YAAY,CAAC,GAAG,EAAE;GACjB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAE,KAAI,IAAG,GAAI,KAAI,GAAI,MAAK;GACvD;;AAED,EAAA,cAAc,CAAC,GAAG,EAAE;AACnB,GAAA,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAA,KAAM,IAAG,GAAI,EAAE,KAAK,EAAE,+BAAgC,EAAA,GAAI,EAAC;GACxF;;AAED,EAAA,YAAY,CAAC,KAAK,EAAE;AACnB,GAAA,IAAI,UAAU,SAAS,EAAE;AACxB,IAAA,OAAO,GAAE;AACV,IAAA;AACA,GAAA,IAAI,KAAI,KAAM,IAAI,EAAE;IACnB,OAAO,MAAK;AACb,IAAA;GACA,IAAI,OAAO,UAAU,QAAQ,EAAE;AAC9B,IAAA,IAAI;KACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;AAC5B,KAAA,CAAE,MAAM;AACP,KAAA,OAAO,MAAM,CAAC,KAAK,CAAA;AACpB,KAAA;AACD,IAAA;AACA,GAAA,OAAO,MAAM,CAAC,KAAK,CAAA;GACnB;;AAED,EAAA,UAAU,CAAC,KAAK,EAAE;GACjB,OAAO,KAAK,CAAC,QAAO,IAAK,KAAK,CAAC,IAAK,IAAGA,SAAC,CAAC,eAAe,EAAE,QAAQ,CAAA;GAClE;;AAED,EAAA,UAAU,CAAC,KAAK,EAAE;AACjB,GAAA,MAAM,GAAI,GAAE,KAAK,CAAC,OAAQ,IAAG,KAAK,CAAC,gBAAiB,IAAG,KAAK,CAAC,UAAQ;AACrE,GAAA,IAAI,GAAI,KAAI,SAAU,IAAG,GAAE,KAAM,IAAI,EAAE;AACtC,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,MAAM,CAAA,GAAI,IAAI,IAAI,CAAC,GAAG,EAAA;AACtB,GAAA,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAE,KAAI,IAAI,EAAE;AACvC,IAAA,OAAO,MAAM,CAAC,GAAG,CAAA;AAClB,IAAA;GACA,OAAO,CAAC,CAAC,cAAc,EAAC;GACxB;EACD;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"CnVersionHistory.vue2.js","sources":["../../../../src/components/CnVersionHistory/CnVersionHistory.vue"],"sourcesContent":["<!--\n CnVersionHistory — object version-history + field-by-field diff\n viewer for the integration registry.\n\n Lists an OpenRegister object's audit-trail entries (timestamp, user,\n semantic version, action) newest-first, and lets the user open a\n structural diff for one entry, or \"compare\" two checked entries.\n OpenRegister only stores a per-field `changed` delta per entry (no\n full before/after snapshot), so a multi-entry compare is\n reconstructed by folding the range's deltas (`foldAuditTrailEntries`)\n before diffing (`computeObjectDiff`) — see the `version-diff-viewer`\n openspec change's design notes.\n-->\n<template>\n\t<CnDetailCard\n\t\t:title=\"resolvedTitle\"\n\t\t:icon=\"FileCompare\"\n\t\t:collapsible=\"collapsible\"\n\t\t:data-surface=\"surface\">\n\t\t<NcLoadingIcon v-if=\"loading && entries.length === 0\" />\n\t\t<div v-else-if=\"entries.length === 0\" class=\"cn-version-history__empty\">\n\t\t\t{{ noEntriesLabel }}\n\t\t</div>\n\t\t<div v-else-if=\"activeDiff === null\" class=\"cn-version-history__list\">\n\t\t\t<ul class=\"cn-version-history__rows\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"entry in entries\"\n\t\t\t\t\t:key=\"entry.id\"\n\t\t\t\t\tclass=\"cn-version-history__row\">\n\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t:modelValue=\"isSelected(entry.id)\"\n\t\t\t\t\t\t:disabled=\"isSelected(entry.id) === false && selectedIds.length >= 2\"\n\t\t\t\t\t\t:aria-label=\"selectForCompareLabel\"\n\t\t\t\t\t\t@update:modelValue=\"toggleSelected(entry.id, $event)\" />\n\t\t\t\t\t<button class=\"cn-version-history__row-main\" type=\"button\" @click=\"openSingleDiff(entry)\">\n\t\t\t\t\t\t<span class=\"cn-version-history__version\">{{ entry.version || fallbackVersionLabel }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__action\">{{ entry.action || '' }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__when\">{{ formatWhen(entry) }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__user\">{{ formatUser(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div class=\"cn-version-history__toolbar\">\n\t\t\t\t<NcButton\n\t\t\t\t\t:disabled=\"selectedIds.length !== 2\"\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t@click=\"openCompareDiff\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Compare :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ compareLabel }}\n\t\t\t\t</NcButton>\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:disabled=\"loadingMore\"\n\t\t\t\t\t@click=\"loadMore\">\n\t\t\t\t\t{{ loadMoreLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<div v-else class=\"cn-version-history__diff\">\n\t\t\t<div class=\"cn-version-history__diff-toolbar\">\n\t\t\t\t<NcButton variant=\"tertiary\" @click=\"closeDiff\">\n\t\t\t\t\t{{ backLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcCheckboxRadioSwitch :modelValue=\"showAllFields\" @update:modelValue=\"showAllFields = $event\">\n\t\t\t\t\t{{ showAllFieldsLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</div>\n\t\t\t<table v-if=\"visibleDiffRows.length > 0\" class=\"cn-version-history__diff-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>{{ fieldLabel }}</th>\n\t\t\t\t\t\t<th>{{ oldValueLabel }}</th>\n\t\t\t\t\t\t<th>{{ newValueLabel }}</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr v-for=\"row in visibleDiffRows\" :key=\"row.path\" :class=\"rowClass(row.type)\">\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-field\">\n\t\t\t\t\t\t\t{{ row.path }}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-value\">\n\t\t\t\t\t\t\t<component :is=\"valueCellTag(row)\" v-bind=\"valueCellProps(row)\">\n\t\t\t\t\t\t\t\t<template v-if=\"isNestedValue(row) === true\">\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tv-for=\"line in nestedLines(row, 'old')\"\n\t\t\t\t\t\t\t\t\t\t:key=\"line.path\"\n\t\t\t\t\t\t\t\t\t\t:class=\"lineClass(line.type)\">\n\t\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t\t{{ formatScalar(row.oldValue) }}\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-value\">\n\t\t\t\t\t\t\t<component :is=\"valueCellTag(row)\" v-bind=\"valueCellProps(row)\">\n\t\t\t\t\t\t\t\t<template v-if=\"isNestedValue(row) === true\">\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tv-for=\"line in nestedLines(row, 'new')\"\n\t\t\t\t\t\t\t\t\t\t:key=\"line.path\"\n\t\t\t\t\t\t\t\t\t\t:class=\"lineClass(line.type)\">\n\t\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t\t{{ formatScalar(row.newValue) }}\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t\t<div v-else class=\"cn-version-history__diff-empty\">\n\t\t\t\t{{ noChangesLabel }}\n\t\t\t</div>\n\t\t</div>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport Compare from 'vue-material-design-icons/Compare.vue'\nimport FileCompare from 'vue-material-design-icons/FileCompare.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport { foldAuditTrailEntries } from '../../utils/auditTrailDiff.js'\nimport { computeObjectDiff } from '../../utils/computeObjectDiff.js'\nimport { buildHeaders } from '../../utils/index.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * A single row rendered in the top-level diff table.\n *\n * @typedef {object} FieldDiffRow\n * @property {string} path Field name.\n * @property {'added'|'removed'|'changed'|'unchanged'} type Classification.\n * @property {unknown} oldValue Value before.\n * @property {unknown} newValue Value after.\n */\n\n/**\n * Classify one top-level field between two folded states, reusing\n * `computeObjectDiff` to decide equality (so nested objects/arrays are\n * compared structurally, not by reference).\n *\n * @param {string} key Field name.\n * @param {object} oldState Folded \"before\" state.\n * @param {object} newState Folded \"after\" state.\n * @return {FieldDiffRow} The classified row.\n */\nfunction classifyField(key, oldState, newState) {\n\tconst oldMissing = Object.hasOwn(oldState, key) === false\n\tconst newMissing = Object.hasOwn(newState, key) === false\n\tconst oldValue = oldState[key]\n\tconst newValue = newState[key]\n\n\tif (oldMissing === true && newMissing === false) {\n\t\treturn { path: key, type: 'added', oldValue: undefined, newValue }\n\t}\n\tif (oldMissing === false && newMissing === true) {\n\t\treturn { path: key, type: 'removed', oldValue, newValue: undefined }\n\t}\n\tconst nested = computeObjectDiff(oldValue, newValue)\n\tconst isChanged = nested.some((entry) => entry.type !== 'unchanged')\n\treturn { path: key, type: isChanged ? 'changed' : 'unchanged', oldValue, newValue }\n}\n\n/**\n * Build the top-level field-by-field diff table for a folded\n * before/after state pair.\n *\n * @param {object} oldState Folded \"before\" state.\n * @param {object} newState Folded \"after\" state.\n * @return {FieldDiffRow[]} One row per touched field, sorted by field name.\n */\nfunction buildFieldRows(oldState, newState) {\n\tconst keys = Array.from(new Set([...Object.keys(oldState), ...Object.keys(newState)])).sort()\n\treturn keys.map((key) => classifyField(key, oldState, newState))\n}\n\n/**\n * CnVersionHistory — object version-history list plus field-by-field\n * diff viewer, rendered by the integration registry on sidebar-tab\n * and dashboard/detail-widget surfaces alike.\n *\n * Basic usage\n * ```vue\n * <CnVersionHistory\n * :register=\"registerId\"\n * :schema=\"schemaId\"\n * :object-id=\"objectId\"\n * surface=\"detail-page\" />\n * ```\n */\nexport default {\n\tname: 'CnVersionHistory',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, NcButton, NcCheckboxRadioSwitch, Compare },\n\n\tprops: {\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface — passed for AD-19 surface fallback consumers. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (value) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(value),\n\t\t},\n\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Number of history entries to fetch per page. */\n\t\tpageSize: { type: Number, default: 20 },\n\t\t/** Whether the card collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Pre-translated empty-history label. */\n\t\tnoEntriesLabel: { type: String, default: () => t('nextcloud-vue', 'No version history yet') },\n\t\t/** Pre-translated fallback shown when an entry carries no semantic version. */\n\t\tfallbackVersionLabel: { type: String, default: () => t('nextcloud-vue', 'Unversioned change') },\n\t\t/** Pre-translated \"select for compare\" checkbox label. */\n\t\tselectForCompareLabel: { type: String, default: () => t('nextcloud-vue', 'Select for compare') },\n\t\t/** Pre-translated compare-action label. */\n\t\tcompareLabel: { type: String, default: () => t('nextcloud-vue', 'Compare selected') },\n\t\t/** Pre-translated load-more label. */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/** Pre-translated back-to-list label. */\n\t\tbackLabel: { type: String, default: () => t('nextcloud-vue', 'Back to history') },\n\t\t/** Pre-translated \"show all fields\" toggle label. */\n\t\tshowAllFieldsLabel: { type: String, default: () => t('nextcloud-vue', 'Show all fields') },\n\t\t/** Pre-translated diff table field-column header. */\n\t\tfieldLabel: { type: String, default: () => t('nextcloud-vue', 'Field') },\n\t\t/** Pre-translated diff table old-value-column header. */\n\t\toldValueLabel: { type: String, default: () => t('nextcloud-vue', 'Old value') },\n\t\t/** Pre-translated diff table new-value-column header. */\n\t\tnewValueLabel: { type: String, default: () => t('nextcloud-vue', 'New value') },\n\t\t/** Pre-translated label shown when a diff has no visible rows. */\n\t\tnoChangesLabel: { type: String, default: () => t('nextcloud-vue', 'No field changes to show') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tFileCompare: markRaw(FileCompare),\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tselectedIds: [],\n\t\t\t/** `null` = list view; otherwise `{ oldState, newState }` for the open diff. */\n\t\t\tactiveDiff: null,\n\t\t\tshowAllFields: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Version history')\n\t\t},\n\n\t\thasMore() {\n\t\t\treturn this.entries.length < this.total\n\t\t},\n\n\t\tdiffRows() {\n\t\t\tif (this.activeDiff === null) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn buildFieldRows(this.activeDiff.oldState, this.activeDiff.newState)\n\t\t},\n\n\t\tvisibleDiffRows() {\n\t\t\tif (this.showAllFields === true) {\n\t\t\t\treturn this.diffRows\n\t\t\t}\n\t\t\treturn this.diffRows.filter((row) => row.type !== 'unchanged')\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.resetAndFetch()\n\t\t\t\t}\n\t\t\t},\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.selectedIds = []\n\t\t\tthis.activeDiff = null\n\t\t\tthis.fetchEntries()\n\t\t},\n\n\t\tasync fetchEntries() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\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 params = new URLSearchParams()\n\t\t\t\tparams.set('limit', String(this.pageSize))\n\t\t\t\tparams.set('_page', String(this.page))\n\t\t\t\tparams.set('_sort[created]', 'DESC')\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(`${url}?${params.toString()}`, { headers: buildHeaders() })\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\tthis.entries = this.page === 1 ? results : [...this.entries, ...results]\n\t\t\t\t\tthis.total = data.total || this.entries.length\n\t\t\t\t} else if (this.page === 1) {\n\t\t\t\t\tthis.entries = []\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('[CnVersionHistory] failed to fetch version history', err)\n\t\t\t\tif (this.page === 1) {\n\t\t\t\t\tthis.entries = []\n\t\t\t\t}\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\tloadMore() {\n\t\t\tthis.page += 1\n\t\t\tthis.fetchEntries()\n\t\t},\n\n\t\tisSelected(id) {\n\t\t\treturn this.selectedIds.includes(id)\n\t\t},\n\n\t\ttoggleSelected(id, checked) {\n\t\t\tif (checked === true) {\n\t\t\t\tif (this.selectedIds.includes(id) === false && this.selectedIds.length < 2) {\n\t\t\t\t\tthis.selectedIds = [...this.selectedIds, id]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.selectedIds = this.selectedIds.filter((existing) => existing !== id)\n\t\t\t}\n\t\t},\n\n\t\topenSingleDiff(entry) {\n\t\t\tconst { oldState, newState } = foldAuditTrailEntries([entry])\n\t\t\tthis.showAllFields = false\n\t\t\tthis.activeDiff = { oldState, newState }\n\t\t},\n\n\t\topenCompareDiff() {\n\t\t\tif (this.selectedIds.length !== 2) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Entries are fetched newest-first; fold oldest-first so the\n\t\t\t// \"first old\" / \"last new\" semantics land on the right side.\n\t\t\tconst selectedEntries = this.entries.filter((entry) => this.selectedIds.includes(entry.id))\n\t\t\tconst chronological = [...selectedEntries].reverse()\n\t\t\tconst { oldState, newState } = foldAuditTrailEntries(chronological)\n\t\t\tthis.showAllFields = false\n\t\t\tthis.activeDiff = { oldState, newState }\n\t\t},\n\n\t\tcloseDiff() {\n\t\t\tthis.activeDiff = null\n\t\t},\n\n\t\tisNestedValue(row) {\n\t\t\tconst isObj = (v) => v !== null && typeof v === 'object'\n\t\t\treturn isObj(row.oldValue) === true || isObj(row.newValue) === true\n\t\t},\n\n\t\t/**\n\t\t * Build the per-line nested diff for one side of a table cell\n\t\t * whose value is an object/array, so each nested key can be\n\t\t * individually add/remove/change tinted.\n\t\t *\n\t\t * @param {FieldDiffRow} row The parent field row.\n\t\t * @param {'old'|'new'} side Which side is being rendered (both sides render the same nested diff so add/remove/change context matches on both columns).\n\t\t * @return {Array<{path: string, type: string, text: string}>} Rendered lines.\n\t\t */\n\t\tnestedLines(row, side) {\n\t\t\tconst base = row.oldValue !== null && typeof row.oldValue === 'object' ? row.oldValue : {}\n\t\t\tconst next = row.newValue !== null && typeof row.newValue === 'object' ? row.newValue : {}\n\t\t\tconst from = row.type === 'added' ? {} : base\n\t\t\tconst to = row.type === 'removed' ? {} : next\n\t\t\tconst nested = computeObjectDiff(from, to)\n\t\t\tconst visible = this.showAllFields === true ? nested : nested.filter((entry) => entry.type !== 'unchanged')\n\t\t\treturn visible.map((entry) => ({\n\t\t\t\tpath: entry.path,\n\t\t\t\ttype: entry.type,\n\t\t\t\ttext: this.formatNestedLine(entry, side),\n\t\t\t}))\n\t\t},\n\n\t\tformatNestedLine(entry, side) {\n\t\t\tconst label = entry.path === '' ? '·' : entry.path\n\t\t\tif (entry.type === 'changed') {\n\t\t\t\tconst shown = side === 'new' ? entry.newValue : entry.oldValue\n\t\t\t\treturn `${label}: ${this.formatScalar(shown)}`\n\t\t\t}\n\t\t\tconst value = entry.type === 'removed' ? entry.oldValue : entry.newValue\n\t\t\treturn `${label}: ${this.formatScalar(value)}`\n\t\t},\n\n\t\trowClass(type) {\n\t\t\treturn {\n\t\t\t\t'cn-version-history__diff-row': true,\n\t\t\t\t[`cn-version-history__diff-row--${type}`]: true,\n\t\t\t}\n\t\t},\n\n\t\tlineClass(type) {\n\t\t\treturn {\n\t\t\t\t'cn-version-history__diff-line': true,\n\t\t\t\t[`cn-version-history__diff-line--${type}`]: true,\n\t\t\t}\n\t\t},\n\n\t\tvalueCellTag(row) {\n\t\t\treturn this.isNestedValue(row) === true ? 'pre' : 'span'\n\t\t},\n\n\t\tvalueCellProps(row) {\n\t\t\treturn this.isNestedValue(row) === true ? { class: 'cn-version-history__diff-json' } : {}\n\t\t},\n\n\t\tformatScalar(value) {\n\t\t\tif (value === undefined) {\n\t\t\t\treturn '—'\n\t\t\t}\n\t\t\tif (value === null) {\n\t\t\t\treturn 'null'\n\t\t\t}\n\t\t\tif (typeof value === 'object') {\n\t\t\t\ttry {\n\t\t\t\t\treturn JSON.stringify(value)\n\t\t\t\t} catch {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn String(value)\n\t\t},\n\n\t\tformatUser(entry) {\n\t\t\treturn entry.userName || entry.user || t('nextcloud-vue', 'System')\n\t\t},\n\n\t\tformatWhen(entry) {\n\t\t\tconst raw = entry.created || entry.creationDateTime || entry.timestamp\n\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst d = new Date(raw)\n\t\t\tif (Number.isNaN(d.getTime()) === true) {\n\t\t\t\treturn String(raw)\n\t\t\t}\n\t\t\treturn d.toLocaleString(userLocale())\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-history__empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n\n.cn-version-history__rows {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-version-history__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-history__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-history__row-main {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\talign-items: baseline;\n\tflex: 1 1 auto;\n\tbackground: none;\n\tborder: none;\n\tcursor: pointer;\n\ttext-align: left;\n\tfont: inherit;\n\tcolor: inherit;\n\tpadding: 4px;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-version-history__row-main:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-version-history__version {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-history__action {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-version-history__when {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\twhite-space: nowrap;\n}\n\n.cn-version-history__user {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-version-history__toolbar {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-top: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-version-history__diff-toolbar {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-version-history__diff-table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-version-history__diff-table th,\n.cn-version-history__diff-table td {\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding: 6px 8px;\n\ttext-align: left;\n\tvertical-align: top;\n}\n\n.cn-version-history__diff-field {\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\twhite-space: nowrap;\n}\n\n.cn-version-history__diff-json {\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n\tfont-family: monospace;\n\tfont-size: 12px;\n}\n\n.cn-version-history__diff-row--added .cn-version-history__diff-field {\n\tcolor: var(--color-success);\n}\n\n.cn-version-history__diff-row--removed .cn-version-history__diff-field {\n\tcolor: var(--color-error);\n}\n\n.cn-version-history__diff-row--changed .cn-version-history__diff-field {\n\tcolor: var(--color-warning);\n}\n\n.cn-version-history__diff-line--added {\n\tbackground-color: color-mix(in srgb, var(--color-success) 15%, transparent);\n\tcolor: var(--color-success);\n}\n\n.cn-version-history__diff-line--removed {\n\tbackground-color: color-mix(in srgb, var(--color-error) 15%, transparent);\n\tcolor: var(--color-error);\n\ttext-decoration: line-through;\n}\n\n.cn-version-history__diff-line--changed {\n\tbackground-color: color-mix(in srgb, var(--color-warning) 15%, transparent);\n\tcolor: var(--color-warning);\n}\n\n.cn-version-history__diff-line--unchanged {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-version-history__diff-empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n</style>\n"],"names":["CnDetailCard","t"],"mappings":";;;;;;;;;;;;AAwIA;AACC;AACA;;AAEA;AACA;AACA;AACA;;;AAGD;;;AAGC;AACA;;AAEA;AACA;AACA;;AAED,SAAS,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE;CAC/C,MAAM,UAAS,GAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAE,KAAI,MAAI;CACxD,MAAM,UAAS,GAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAE,KAAI,MAAI;CACxD,MAAM,QAAO,GAAI,QAAQ,CAAC,GAAG,EAAA;CAC7B,MAAM,QAAO,GAAI,QAAQ,CAAC,GAAG,EAAA;;AAE7B,CAAA,IAAI,UAAW,KAAI,IAAG,IAAK,UAAW,KAAI,KAAK,EAAE;EAChD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAS,EAAA;AAClE,EAAA;AACA,CAAA,IAAI,UAAW,KAAI,KAAM,IAAG,UAAS,KAAM,IAAI,EAAE;EAChD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAU,EAAA;AACpE,EAAA;CACA,MAAM,MAAK,GAAI,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAA;CACnD,MAAM,SAAQ,GAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAK,KAAI,WAAW,EAAA;AACnE,CAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,SAAQ,GAAI,SAAU,GAAE,WAAW,EAAE,QAAQ,EAAE,QAAS,EAAA;AACnF,CAAA;;AAEA;;;AAGC;AACA;AACA;AACA;;AAED,SAAS,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE;AAC3C,CAAA,MAAM,IAAK,GAAE,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAC;CAC5F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;AAChE,CAAA;;AAEA;;;AAGC;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAED,aAAe;CACd,IAAI,EAAE,kBAAkB;;AAExB,CAAA,UAAU,EAAE,gBAAEA,UAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,qBAAqB,EAAE,SAAS;;AAErF,CAAA,KAAK,EAAE;AACN;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;AAC1C;AACA,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;AACxC;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;AAE1C,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,aAAa;GACtB,SAAS,EAAE,CAAC,KAAK,KAAK,CAAC,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;GACzG;;AAED;EACA,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAuB,EAAG;AAC5D;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;;AAEvC,EAAA,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;;AAE9C,EAAA,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAC,EAAG;AACpC;AACA,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,wBAAwB,GAAG;AAC7F;AACA,EAAA,oBAAoB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,oBAAoB,GAAG;;AAE/F,EAAA,qBAAqB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,oBAAoB,GAAG;AAChG;AACA,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,kBAAkB,GAAG;AACrF;AACA,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;AAC/E;AACA,EAAA,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,iBAAiB,GAAG;AACjF;AACA,EAAA,kBAAkB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,iBAAiB,GAAG;;AAE1F,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,OAAO,GAAG;;AAExE,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;;AAE/E,EAAA,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,WAAW,GAAG;;AAE/E,EAAA,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,0BAA0B,GAAG;EAC/F;;AAED,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;AACN,GAAA,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC;GACjC,OAAO,EAAE,EAAE;GACX,OAAO,EAAE,KAAK;AACd,GAAA,WAAW,EAAE,KAAK;AAClB,GAAA,IAAI,EAAE,CAAC;AACP,GAAA,KAAK,EAAE,CAAC;AACR,GAAA,WAAW,EAAE,EAAE;AACf;AACA,GAAA,UAAU,EAAE,IAAI;AAChB,GAAA,aAAa,EAAE,KAAK;AACrB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT,EAAA,aAAa,GAAG;GACf,OAAO,IAAI,CAAC,KAAM,IAAGA,SAAC,CAAC,eAAe,EAAE,iBAAiB,CAAA;GACzD;;AAED,EAAA,OAAO,GAAG;AACT,GAAA,OAAO,IAAI,CAAC,OAAO,CAAC,MAAO,GAAE,IAAI,CAAC,KAAI;GACtC;;EAED,QAAQ,GAAG;GACV,IAAI,IAAI,CAAC,UAAS,KAAM,IAAI,EAAE;AAC7B,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,OAAO,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAA;GACxE;;AAED,EAAA,eAAe,GAAG;GACjB,IAAI,IAAI,CAAC,aAAc,KAAI,IAAI,EAAE;AAChC,IAAA,OAAO,IAAI,CAAC,QAAO;AACpB,IAAA;GACA,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,IAAG,KAAM,WAAW,CAAA;GAC7D;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,QAAQ,EAAE;AACT,GAAA,SAAS,EAAE,IAAI;GACf,OAAO,CAAC,EAAE,EAAE;AACX,IAAA,IAAI,EAAE,EAAE;AACP,KAAA,IAAI,CAAC,aAAa,GAAC;AACpB,KAAA;IACA;GACD;EACD;;AAED,CAAA,OAAO,EAAE;AACR,EAAA,aAAa,GAAG;GACf,IAAI,CAAC,OAAO,EAAA;AACZ,GAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AAChB,GAAA,IAAI,CAAC,WAAU,GAAI,GAAC;AACpB,GAAA,IAAI,CAAC,aAAa,KAAG;AACrB,GAAA,IAAI,CAAC,YAAY,GAAC;GAClB;;AAED,EAAA,MAAM,YAAY,GAAG;GACpB,IAAI,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE;IACrD,MAAK;AACN,IAAA;GACA,IAAI,CAAC,OAAM,GAAI,IAAI,CAAC,IAAG,KAAM,EAAA;GAC7B,IAAI,CAAC,WAAU,GAAI,IAAI,CAAC,IAAG,GAAI,EAAA;AAC/B,GAAA,IAAI;AACH,IAAA,MAAM,MAAK,GAAI,IAAI,eAAe,GAAC;AACnC,IAAA,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAA;AACzC,IAAA,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAA;AACrC,IAAA,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,EAAA;IACnC,MAAM,GAAE,GAAI,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAA;AAC/G,IAAA,MAAM,QAAS,GAAE,MAAM,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AACvF,IAAA,IAAI,QAAQ,CAAC,EAAE,EAAE;KAChB,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;AACjC,KAAA,MAAM,OAAM,GAAI,IAAI,CAAC,OAAQ,IAAG,IAAK,IAAG,GAAC;AACzC,KAAA,IAAI,CAAC,OAAQ,GAAE,IAAI,CAAC,IAAK,KAAI,CAAE,GAAE,OAAQ,GAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,OAAO,EAAA;AACvE,KAAA,IAAI,CAAC,KAAM,GAAE,IAAI,CAAC,KAAM,IAAG,IAAI,CAAC,OAAO,CAAC,OAAK;KAC5C,MAAK,IAAI,IAAI,CAAC,IAAG,KAAM,CAAC,EAAE;AAC3B,KAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AACjB,KAAA;IACC,CAAA,OAAO,GAAG,EAAE;AACb;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,GAAG,EAAA;AACvE,IAAA,IAAI,IAAI,CAAC,IAAK,KAAI,CAAC,EAAE;AACpB,KAAA,IAAI,CAAC,OAAQ,GAAE,GAAC;AACjB,KAAA;AACD,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,OAAQ,GAAE,MAAI;AACnB,IAAA,IAAI,CAAC,WAAU,GAAI,MAAI;AACxB,IAAA;GACA;;EAED,QAAQ,GAAG;GACV,IAAI,CAAC,IAAK,IAAG,EAAA;AACb,GAAA,IAAI,CAAC,YAAY,GAAC;GAClB;;AAED,EAAA,UAAU,CAAC,EAAE,EAAE;AACd,GAAA,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAA;GACnC;;EAED,cAAc,CAAC,EAAE,EAAE,OAAO,EAAE;AAC3B,GAAA,IAAI,OAAQ,KAAI,IAAI,EAAE;AACrB,IAAA,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAI,IAAK,IAAI,CAAC,WAAW,CAAC,MAAO,GAAE,CAAC,EAAE;AAC3E,KAAA,IAAI,CAAC,WAAY,GAAE,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,EAAA;AAC5C,KAAA;IACC,MAAK;AACN,IAAA,IAAI,CAAC,WAAU,GAAI,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,QAAQ,KAAK,QAAS,KAAI,EAAE,EAAA;AACzE,IAAA;GACA;;AAED,EAAA,cAAc,CAAC,KAAK,EAAE;GACrB,MAAM,EAAE,QAAQ,EAAE,QAAO,EAAI,GAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,EAAA;GAC5D,IAAI,CAAC,gBAAgB,MAAI;AACzB,GAAA,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,QAAS,GAAA;GACvC;;AAED,EAAA,eAAe,GAAG;AACjB,GAAA,IAAI,IAAI,CAAC,WAAW,CAAC,MAAO,KAAI,CAAC,EAAE;IAClC,MAAK;AACN,IAAA;;;AAGA,GAAA,MAAM,eAAc,GAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAA;GAC1F,MAAM,gBAAgB,CAAC,GAAG,eAAe,CAAC,CAAC,OAAO,GAAC;GACnD,MAAM,EAAE,QAAQ,EAAE,QAAS,EAAA,GAAI,qBAAqB,CAAC,aAAa,EAAA;GAClE,IAAI,CAAC,gBAAgB,MAAI;AACzB,GAAA,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,QAAS,GAAA;GACvC;;EAED,SAAS,GAAG;AACX,GAAA,IAAI,CAAC,aAAa,KAAG;GACrB;;AAED,EAAA,aAAa,CAAC,GAAG,EAAE;AAClB,GAAA,MAAM,KAAI,GAAI,CAAC,CAAC,KAAK,CAAE,KAAI,QAAQ,OAAO,MAAM,SAAO;GACvD,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAA,KAAM,IAAG,IAAK,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAE,KAAI,IAAG;GAClE;;AAED;;;AAGC;AACA;AACA;AACA;AACA;;AAED,EAAA,WAAW,CAAC,GAAG,EAAE,IAAI,EAAE;AACtB,GAAA,MAAM,IAAK,GAAE,GAAG,CAAC,QAAO,KAAM,IAAG,IAAK,OAAO,GAAG,CAAC,aAAa,QAAS,GAAE,GAAG,CAAC,QAAO,GAAI,GAAC;AACzF,GAAA,MAAM,IAAK,GAAE,GAAG,CAAC,QAAO,KAAM,IAAG,IAAK,OAAO,GAAG,CAAC,aAAa,QAAS,GAAE,GAAG,CAAC,QAAO,GAAI,GAAC;AACzF,GAAA,MAAM,IAAK,GAAE,GAAG,CAAC,IAAK,KAAI,OAAM,GAAI,EAAC,GAAI,KAAG;AAC5C,GAAA,MAAM,EAAG,GAAE,GAAG,CAAC,IAAK,KAAI,SAAQ,GAAI,EAAC,GAAI,KAAG;AAC5C,GAAA,MAAM,SAAS,iBAAiB,CAAC,IAAI,EAAE,EAAE,EAAA;AACzC,GAAA,MAAM,OAAQ,GAAE,IAAI,CAAC,aAAY,KAAM,OAAO,MAAO,GAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,IAAG,KAAM,WAAW,EAAA;GAC1G,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,MAAM;AAC9B,IAAA,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,IAAA,IAAI,EAAE,KAAK,CAAC,IAAI;AAChB,IAAA,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,CAAC;AACzC,IAAC,CAAC,CAAA;GACF;;EAED,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE;AAC7B,GAAA,MAAM,KAAM,GAAE,KAAK,CAAC,IAAK,KAAI,EAAG,GAAE,GAAE,GAAI,KAAK,CAAC,KAAG;GACjD,IAAI,KAAK,CAAC,IAAG,KAAM,SAAS,EAAE;IAC7B,MAAM,KAAI,GAAI,IAAG,KAAM,KAAM,GAAE,KAAK,CAAC,QAAS,GAAE,KAAK,CAAC,SAAO;AAC7D,IAAA,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;AAC9C,IAAA;AACA,GAAA,MAAM,KAAM,GAAE,KAAK,CAAC,IAAG,KAAM,SAAQ,GAAI,KAAK,CAAC,QAAS,GAAE,KAAK,CAAC,SAAO;AACvE,GAAA,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAA;GAC7C;;AAED,EAAA,QAAQ,CAAC,IAAI,EAAE;AACd,GAAA,OAAO;AACN,IAAA,8BAA8B,EAAE,IAAI;IACpC,CAAC,CAAC,8BAA8B,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI;AAChD,IAAA;GACA;;AAED,EAAA,SAAS,CAAC,IAAI,EAAE;AACf,GAAA,OAAO;AACN,IAAA,+BAA+B,EAAE,IAAI;IACrC,CAAC,CAAC,+BAA+B,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI;AACjD,IAAA;GACA;;AAED,EAAA,YAAY,CAAC,GAAG,EAAE;GACjB,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAE,KAAI,IAAG,GAAI,KAAI,GAAI,MAAK;GACvD;;AAED,EAAA,cAAc,CAAC,GAAG,EAAE;AACnB,GAAA,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAA,KAAM,IAAG,GAAI,EAAE,KAAK,EAAE,+BAAgC,EAAA,GAAI,EAAC;GACxF;;AAED,EAAA,YAAY,CAAC,KAAK,EAAE;AACnB,GAAA,IAAI,UAAU,SAAS,EAAE;AACxB,IAAA,OAAO,GAAE;AACV,IAAA;AACA,GAAA,IAAI,KAAI,KAAM,IAAI,EAAE;IACnB,OAAO,MAAK;AACb,IAAA;GACA,IAAI,OAAO,UAAU,QAAQ,EAAE;AAC9B,IAAA,IAAI;KACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;AAC5B,KAAA,CAAE,MAAM;AACP,KAAA,OAAO,MAAM,CAAC,KAAK,CAAA;AACpB,KAAA;AACD,IAAA;AACA,GAAA,OAAO,MAAM,CAAC,KAAK,CAAA;GACnB;;AAED,EAAA,UAAU,CAAC,KAAK,EAAE;GACjB,OAAO,KAAK,CAAC,QAAO,IAAK,KAAK,CAAC,IAAK,IAAGA,SAAC,CAAC,eAAe,EAAE,QAAQ,CAAA;GAClE;;AAED,EAAA,UAAU,CAAC,KAAK,EAAE;AACjB,GAAA,MAAM,GAAI,GAAE,KAAK,CAAC,OAAQ,IAAG,KAAK,CAAC,gBAAiB,IAAG,KAAK,CAAC,UAAQ;AACrE,GAAA,IAAI,GAAI,KAAI,SAAU,IAAG,GAAE,KAAM,IAAI,EAAE;AACtC,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,MAAM,CAAA,GAAI,IAAI,IAAI,CAAC,GAAG,EAAA;AACtB,GAAA,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAE,KAAI,IAAI,EAAE;AACvC,IAAA,OAAO,MAAM,CAAC,GAAG,CAAA;AAClB,IAAA;AACA,GAAA,OAAO,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,CAAA;GACpC;EACD;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnVersionHistory.vue3.js","sources":["../../../../src/components/CnVersionHistory/CnVersionHistory.vue?vue&type=template&id=5888d95c&lang.js"],"sourcesContent":["<!--\n CnVersionHistory — object version-history + field-by-field diff\n viewer for the integration registry.\n\n Lists an OpenRegister object's audit-trail entries (timestamp, user,\n semantic version, action) newest-first, and lets the user open a\n structural diff for one entry, or \"compare\" two checked entries.\n OpenRegister only stores a per-field `changed` delta per entry (no\n full before/after snapshot), so a multi-entry compare is\n reconstructed by folding the range's deltas (`foldAuditTrailEntries`)\n before diffing (`computeObjectDiff`) — see the `version-diff-viewer`\n openspec change's design notes.\n-->\n<template>\n\t<CnDetailCard\n\t\t:title=\"resolvedTitle\"\n\t\t:icon=\"FileCompare\"\n\t\t:collapsible=\"collapsible\"\n\t\t:data-surface=\"surface\">\n\t\t<NcLoadingIcon v-if=\"loading && entries.length === 0\" />\n\t\t<div v-else-if=\"entries.length === 0\" class=\"cn-version-history__empty\">\n\t\t\t{{ noEntriesLabel }}\n\t\t</div>\n\t\t<div v-else-if=\"activeDiff === null\" class=\"cn-version-history__list\">\n\t\t\t<ul class=\"cn-version-history__rows\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"entry in entries\"\n\t\t\t\t\t:key=\"entry.id\"\n\t\t\t\t\tclass=\"cn-version-history__row\">\n\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t:modelValue=\"isSelected(entry.id)\"\n\t\t\t\t\t\t:disabled=\"isSelected(entry.id) === false && selectedIds.length >= 2\"\n\t\t\t\t\t\t:aria-label=\"selectForCompareLabel\"\n\t\t\t\t\t\t@update:modelValue=\"toggleSelected(entry.id, $event)\" />\n\t\t\t\t\t<button class=\"cn-version-history__row-main\" type=\"button\" @click=\"openSingleDiff(entry)\">\n\t\t\t\t\t\t<span class=\"cn-version-history__version\">{{ entry.version || fallbackVersionLabel }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__action\">{{ entry.action || '' }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__when\">{{ formatWhen(entry) }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__user\">{{ formatUser(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div class=\"cn-version-history__toolbar\">\n\t\t\t\t<NcButton\n\t\t\t\t\t:disabled=\"selectedIds.length !== 2\"\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t@click=\"openCompareDiff\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Compare :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ compareLabel }}\n\t\t\t\t</NcButton>\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:disabled=\"loadingMore\"\n\t\t\t\t\t@click=\"loadMore\">\n\t\t\t\t\t{{ loadMoreLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<div v-else class=\"cn-version-history__diff\">\n\t\t\t<div class=\"cn-version-history__diff-toolbar\">\n\t\t\t\t<NcButton variant=\"tertiary\" @click=\"closeDiff\">\n\t\t\t\t\t{{ backLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcCheckboxRadioSwitch :modelValue=\"showAllFields\" @update:modelValue=\"showAllFields = $event\">\n\t\t\t\t\t{{ showAllFieldsLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</div>\n\t\t\t<table v-if=\"visibleDiffRows.length > 0\" class=\"cn-version-history__diff-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>{{ fieldLabel }}</th>\n\t\t\t\t\t\t<th>{{ oldValueLabel }}</th>\n\t\t\t\t\t\t<th>{{ newValueLabel }}</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr v-for=\"row in visibleDiffRows\" :key=\"row.path\" :class=\"rowClass(row.type)\">\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-field\">\n\t\t\t\t\t\t\t{{ row.path }}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-value\">\n\t\t\t\t\t\t\t<component :is=\"valueCellTag(row)\" v-bind=\"valueCellProps(row)\">\n\t\t\t\t\t\t\t\t<template v-if=\"isNestedValue(row) === true\">\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tv-for=\"line in nestedLines(row, 'old')\"\n\t\t\t\t\t\t\t\t\t\t:key=\"line.path\"\n\t\t\t\t\t\t\t\t\t\t:class=\"lineClass(line.type)\">\n\t\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t\t{{ formatScalar(row.oldValue) }}\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-value\">\n\t\t\t\t\t\t\t<component :is=\"valueCellTag(row)\" v-bind=\"valueCellProps(row)\">\n\t\t\t\t\t\t\t\t<template v-if=\"isNestedValue(row) === true\">\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tv-for=\"line in nestedLines(row, 'new')\"\n\t\t\t\t\t\t\t\t\t\t:key=\"line.path\"\n\t\t\t\t\t\t\t\t\t\t:class=\"lineClass(line.type)\">\n\t\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t\t{{ formatScalar(row.newValue) }}\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t\t<div v-else class=\"cn-version-history__diff-empty\">\n\t\t\t\t{{ noChangesLabel }}\n\t\t\t</div>\n\t\t</div>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport Compare from 'vue-material-design-icons/Compare.vue'\nimport FileCompare from 'vue-material-design-icons/FileCompare.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport { foldAuditTrailEntries } from '../../utils/auditTrailDiff.js'\nimport { computeObjectDiff } from '../../utils/computeObjectDiff.js'\nimport { buildHeaders } from '../../utils/index.js'\n\n/**\n * A single row rendered in the top-level diff table.\n *\n * @typedef {object} FieldDiffRow\n * @property {string} path Field name.\n * @property {'added'|'removed'|'changed'|'unchanged'} type Classification.\n * @property {unknown} oldValue Value before.\n * @property {unknown} newValue Value after.\n */\n\n/**\n * Classify one top-level field between two folded states, reusing\n * `computeObjectDiff` to decide equality (so nested objects/arrays are\n * compared structurally, not by reference).\n *\n * @param {string} key Field name.\n * @param {object} oldState Folded \"before\" state.\n * @param {object} newState Folded \"after\" state.\n * @return {FieldDiffRow} The classified row.\n */\nfunction classifyField(key, oldState, newState) {\n\tconst oldMissing = Object.hasOwn(oldState, key) === false\n\tconst newMissing = Object.hasOwn(newState, key) === false\n\tconst oldValue = oldState[key]\n\tconst newValue = newState[key]\n\n\tif (oldMissing === true && newMissing === false) {\n\t\treturn { path: key, type: 'added', oldValue: undefined, newValue }\n\t}\n\tif (oldMissing === false && newMissing === true) {\n\t\treturn { path: key, type: 'removed', oldValue, newValue: undefined }\n\t}\n\tconst nested = computeObjectDiff(oldValue, newValue)\n\tconst isChanged = nested.some((entry) => entry.type !== 'unchanged')\n\treturn { path: key, type: isChanged ? 'changed' : 'unchanged', oldValue, newValue }\n}\n\n/**\n * Build the top-level field-by-field diff table for a folded\n * before/after state pair.\n *\n * @param {object} oldState Folded \"before\" state.\n * @param {object} newState Folded \"after\" state.\n * @return {FieldDiffRow[]} One row per touched field, sorted by field name.\n */\nfunction buildFieldRows(oldState, newState) {\n\tconst keys = Array.from(new Set([...Object.keys(oldState), ...Object.keys(newState)])).sort()\n\treturn keys.map((key) => classifyField(key, oldState, newState))\n}\n\n/**\n * CnVersionHistory — object version-history list plus field-by-field\n * diff viewer, rendered by the integration registry on sidebar-tab\n * and dashboard/detail-widget surfaces alike.\n *\n * Basic usage\n * ```vue\n * <CnVersionHistory\n * :register=\"registerId\"\n * :schema=\"schemaId\"\n * :object-id=\"objectId\"\n * surface=\"detail-page\" />\n * ```\n */\nexport default {\n\tname: 'CnVersionHistory',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, NcButton, NcCheckboxRadioSwitch, Compare },\n\n\tprops: {\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface — passed for AD-19 surface fallback consumers. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (value) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(value),\n\t\t},\n\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Number of history entries to fetch per page. */\n\t\tpageSize: { type: Number, default: 20 },\n\t\t/** Whether the card collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Pre-translated empty-history label. */\n\t\tnoEntriesLabel: { type: String, default: () => t('nextcloud-vue', 'No version history yet') },\n\t\t/** Pre-translated fallback shown when an entry carries no semantic version. */\n\t\tfallbackVersionLabel: { type: String, default: () => t('nextcloud-vue', 'Unversioned change') },\n\t\t/** Pre-translated \"select for compare\" checkbox label. */\n\t\tselectForCompareLabel: { type: String, default: () => t('nextcloud-vue', 'Select for compare') },\n\t\t/** Pre-translated compare-action label. */\n\t\tcompareLabel: { type: String, default: () => t('nextcloud-vue', 'Compare selected') },\n\t\t/** Pre-translated load-more label. */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/** Pre-translated back-to-list label. */\n\t\tbackLabel: { type: String, default: () => t('nextcloud-vue', 'Back to history') },\n\t\t/** Pre-translated \"show all fields\" toggle label. */\n\t\tshowAllFieldsLabel: { type: String, default: () => t('nextcloud-vue', 'Show all fields') },\n\t\t/** Pre-translated diff table field-column header. */\n\t\tfieldLabel: { type: String, default: () => t('nextcloud-vue', 'Field') },\n\t\t/** Pre-translated diff table old-value-column header. */\n\t\toldValueLabel: { type: String, default: () => t('nextcloud-vue', 'Old value') },\n\t\t/** Pre-translated diff table new-value-column header. */\n\t\tnewValueLabel: { type: String, default: () => t('nextcloud-vue', 'New value') },\n\t\t/** Pre-translated label shown when a diff has no visible rows. */\n\t\tnoChangesLabel: { type: String, default: () => t('nextcloud-vue', 'No field changes to show') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tFileCompare: markRaw(FileCompare),\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tselectedIds: [],\n\t\t\t/** `null` = list view; otherwise `{ oldState, newState }` for the open diff. */\n\t\t\tactiveDiff: null,\n\t\t\tshowAllFields: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Version history')\n\t\t},\n\n\t\thasMore() {\n\t\t\treturn this.entries.length < this.total\n\t\t},\n\n\t\tdiffRows() {\n\t\t\tif (this.activeDiff === null) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn buildFieldRows(this.activeDiff.oldState, this.activeDiff.newState)\n\t\t},\n\n\t\tvisibleDiffRows() {\n\t\t\tif (this.showAllFields === true) {\n\t\t\t\treturn this.diffRows\n\t\t\t}\n\t\t\treturn this.diffRows.filter((row) => row.type !== 'unchanged')\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.resetAndFetch()\n\t\t\t\t}\n\t\t\t},\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.selectedIds = []\n\t\t\tthis.activeDiff = null\n\t\t\tthis.fetchEntries()\n\t\t},\n\n\t\tasync fetchEntries() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\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 params = new URLSearchParams()\n\t\t\t\tparams.set('limit', String(this.pageSize))\n\t\t\t\tparams.set('_page', String(this.page))\n\t\t\t\tparams.set('_sort[created]', 'DESC')\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(`${url}?${params.toString()}`, { headers: buildHeaders() })\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\tthis.entries = this.page === 1 ? results : [...this.entries, ...results]\n\t\t\t\t\tthis.total = data.total || this.entries.length\n\t\t\t\t} else if (this.page === 1) {\n\t\t\t\t\tthis.entries = []\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('[CnVersionHistory] failed to fetch version history', err)\n\t\t\t\tif (this.page === 1) {\n\t\t\t\t\tthis.entries = []\n\t\t\t\t}\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\tloadMore() {\n\t\t\tthis.page += 1\n\t\t\tthis.fetchEntries()\n\t\t},\n\n\t\tisSelected(id) {\n\t\t\treturn this.selectedIds.includes(id)\n\t\t},\n\n\t\ttoggleSelected(id, checked) {\n\t\t\tif (checked === true) {\n\t\t\t\tif (this.selectedIds.includes(id) === false && this.selectedIds.length < 2) {\n\t\t\t\t\tthis.selectedIds = [...this.selectedIds, id]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.selectedIds = this.selectedIds.filter((existing) => existing !== id)\n\t\t\t}\n\t\t},\n\n\t\topenSingleDiff(entry) {\n\t\t\tconst { oldState, newState } = foldAuditTrailEntries([entry])\n\t\t\tthis.showAllFields = false\n\t\t\tthis.activeDiff = { oldState, newState }\n\t\t},\n\n\t\topenCompareDiff() {\n\t\t\tif (this.selectedIds.length !== 2) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Entries are fetched newest-first; fold oldest-first so the\n\t\t\t// \"first old\" / \"last new\" semantics land on the right side.\n\t\t\tconst selectedEntries = this.entries.filter((entry) => this.selectedIds.includes(entry.id))\n\t\t\tconst chronological = [...selectedEntries].reverse()\n\t\t\tconst { oldState, newState } = foldAuditTrailEntries(chronological)\n\t\t\tthis.showAllFields = false\n\t\t\tthis.activeDiff = { oldState, newState }\n\t\t},\n\n\t\tcloseDiff() {\n\t\t\tthis.activeDiff = null\n\t\t},\n\n\t\tisNestedValue(row) {\n\t\t\tconst isObj = (v) => v !== null && typeof v === 'object'\n\t\t\treturn isObj(row.oldValue) === true || isObj(row.newValue) === true\n\t\t},\n\n\t\t/**\n\t\t * Build the per-line nested diff for one side of a table cell\n\t\t * whose value is an object/array, so each nested key can be\n\t\t * individually add/remove/change tinted.\n\t\t *\n\t\t * @param {FieldDiffRow} row The parent field row.\n\t\t * @param {'old'|'new'} side Which side is being rendered (both sides render the same nested diff so add/remove/change context matches on both columns).\n\t\t * @return {Array<{path: string, type: string, text: string}>} Rendered lines.\n\t\t */\n\t\tnestedLines(row, side) {\n\t\t\tconst base = row.oldValue !== null && typeof row.oldValue === 'object' ? row.oldValue : {}\n\t\t\tconst next = row.newValue !== null && typeof row.newValue === 'object' ? row.newValue : {}\n\t\t\tconst from = row.type === 'added' ? {} : base\n\t\t\tconst to = row.type === 'removed' ? {} : next\n\t\t\tconst nested = computeObjectDiff(from, to)\n\t\t\tconst visible = this.showAllFields === true ? nested : nested.filter((entry) => entry.type !== 'unchanged')\n\t\t\treturn visible.map((entry) => ({\n\t\t\t\tpath: entry.path,\n\t\t\t\ttype: entry.type,\n\t\t\t\ttext: this.formatNestedLine(entry, side),\n\t\t\t}))\n\t\t},\n\n\t\tformatNestedLine(entry, side) {\n\t\t\tconst label = entry.path === '' ? '·' : entry.path\n\t\t\tif (entry.type === 'changed') {\n\t\t\t\tconst shown = side === 'new' ? entry.newValue : entry.oldValue\n\t\t\t\treturn `${label}: ${this.formatScalar(shown)}`\n\t\t\t}\n\t\t\tconst value = entry.type === 'removed' ? entry.oldValue : entry.newValue\n\t\t\treturn `${label}: ${this.formatScalar(value)}`\n\t\t},\n\n\t\trowClass(type) {\n\t\t\treturn {\n\t\t\t\t'cn-version-history__diff-row': true,\n\t\t\t\t[`cn-version-history__diff-row--${type}`]: true,\n\t\t\t}\n\t\t},\n\n\t\tlineClass(type) {\n\t\t\treturn {\n\t\t\t\t'cn-version-history__diff-line': true,\n\t\t\t\t[`cn-version-history__diff-line--${type}`]: true,\n\t\t\t}\n\t\t},\n\n\t\tvalueCellTag(row) {\n\t\t\treturn this.isNestedValue(row) === true ? 'pre' : 'span'\n\t\t},\n\n\t\tvalueCellProps(row) {\n\t\t\treturn this.isNestedValue(row) === true ? { class: 'cn-version-history__diff-json' } : {}\n\t\t},\n\n\t\tformatScalar(value) {\n\t\t\tif (value === undefined) {\n\t\t\t\treturn '—'\n\t\t\t}\n\t\t\tif (value === null) {\n\t\t\t\treturn 'null'\n\t\t\t}\n\t\t\tif (typeof value === 'object') {\n\t\t\t\ttry {\n\t\t\t\t\treturn JSON.stringify(value)\n\t\t\t\t} catch {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn String(value)\n\t\t},\n\n\t\tformatUser(entry) {\n\t\t\treturn entry.userName || entry.user || t('nextcloud-vue', 'System')\n\t\t},\n\n\t\tformatWhen(entry) {\n\t\t\tconst raw = entry.created || entry.creationDateTime || entry.timestamp\n\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst d = new Date(raw)\n\t\t\tif (Number.isNaN(d.getTime()) === true) {\n\t\t\t\treturn String(raw)\n\t\t\t}\n\t\t\treturn d.toLocaleString()\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-history__empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n\n.cn-version-history__rows {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-version-history__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-history__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-history__row-main {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\talign-items: baseline;\n\tflex: 1 1 auto;\n\tbackground: none;\n\tborder: none;\n\tcursor: pointer;\n\ttext-align: left;\n\tfont: inherit;\n\tcolor: inherit;\n\tpadding: 4px;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-version-history__row-main:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-version-history__version {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-history__action {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-version-history__when {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\twhite-space: nowrap;\n}\n\n.cn-version-history__user {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-version-history__toolbar {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-top: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-version-history__diff-toolbar {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-version-history__diff-table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-version-history__diff-table th,\n.cn-version-history__diff-table td {\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding: 6px 8px;\n\ttext-align: left;\n\tvertical-align: top;\n}\n\n.cn-version-history__diff-field {\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\twhite-space: nowrap;\n}\n\n.cn-version-history__diff-json {\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n\tfont-family: monospace;\n\tfont-size: 12px;\n}\n\n.cn-version-history__diff-row--added .cn-version-history__diff-field {\n\tcolor: var(--color-success);\n}\n\n.cn-version-history__diff-row--removed .cn-version-history__diff-field {\n\tcolor: var(--color-error);\n}\n\n.cn-version-history__diff-row--changed .cn-version-history__diff-field {\n\tcolor: var(--color-warning);\n}\n\n.cn-version-history__diff-line--added {\n\tbackground-color: color-mix(in srgb, var(--color-success) 15%, transparent);\n\tcolor: var(--color-success);\n}\n\n.cn-version-history__diff-line--removed {\n\tbackground-color: color-mix(in srgb, var(--color-error) 15%, transparent);\n\tcolor: var(--color-error);\n\ttext-decoration: line-through;\n}\n\n.cn-version-history__diff-line--changed {\n\tbackground-color: color-mix(in srgb, var(--color-warning) 15%, transparent);\n\tcolor: var(--color-warning);\n}\n\n.cn-version-history__diff-line--unchanged {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-version-history__diff-empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n</style>\n"],"names":["_createBlock","_toDisplayString","_openBlock","_createElementBlock","_createElementVNode","_Fragment","_renderList","_createVNode","_createTextVNode","_normalizeClass","_resolveDynamicComponent","_mergeProps"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnVersionHistory.vue3.js","sources":["../../../../src/components/CnVersionHistory/CnVersionHistory.vue?vue&type=template&id=0fca5a52&lang.js"],"sourcesContent":["<!--\n CnVersionHistory — object version-history + field-by-field diff\n viewer for the integration registry.\n\n Lists an OpenRegister object's audit-trail entries (timestamp, user,\n semantic version, action) newest-first, and lets the user open a\n structural diff for one entry, or \"compare\" two checked entries.\n OpenRegister only stores a per-field `changed` delta per entry (no\n full before/after snapshot), so a multi-entry compare is\n reconstructed by folding the range's deltas (`foldAuditTrailEntries`)\n before diffing (`computeObjectDiff`) — see the `version-diff-viewer`\n openspec change's design notes.\n-->\n<template>\n\t<CnDetailCard\n\t\t:title=\"resolvedTitle\"\n\t\t:icon=\"FileCompare\"\n\t\t:collapsible=\"collapsible\"\n\t\t:data-surface=\"surface\">\n\t\t<NcLoadingIcon v-if=\"loading && entries.length === 0\" />\n\t\t<div v-else-if=\"entries.length === 0\" class=\"cn-version-history__empty\">\n\t\t\t{{ noEntriesLabel }}\n\t\t</div>\n\t\t<div v-else-if=\"activeDiff === null\" class=\"cn-version-history__list\">\n\t\t\t<ul class=\"cn-version-history__rows\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"entry in entries\"\n\t\t\t\t\t:key=\"entry.id\"\n\t\t\t\t\tclass=\"cn-version-history__row\">\n\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t:modelValue=\"isSelected(entry.id)\"\n\t\t\t\t\t\t:disabled=\"isSelected(entry.id) === false && selectedIds.length >= 2\"\n\t\t\t\t\t\t:aria-label=\"selectForCompareLabel\"\n\t\t\t\t\t\t@update:modelValue=\"toggleSelected(entry.id, $event)\" />\n\t\t\t\t\t<button class=\"cn-version-history__row-main\" type=\"button\" @click=\"openSingleDiff(entry)\">\n\t\t\t\t\t\t<span class=\"cn-version-history__version\">{{ entry.version || fallbackVersionLabel }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__action\">{{ entry.action || '' }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__when\">{{ formatWhen(entry) }}</span>\n\t\t\t\t\t\t<span class=\"cn-version-history__user\">{{ formatUser(entry) }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<div class=\"cn-version-history__toolbar\">\n\t\t\t\t<NcButton\n\t\t\t\t\t:disabled=\"selectedIds.length !== 2\"\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t@click=\"openCompareDiff\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Compare :size=\"18\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ compareLabel }}\n\t\t\t\t</NcButton>\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:disabled=\"loadingMore\"\n\t\t\t\t\t@click=\"loadMore\">\n\t\t\t\t\t{{ loadMoreLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<div v-else class=\"cn-version-history__diff\">\n\t\t\t<div class=\"cn-version-history__diff-toolbar\">\n\t\t\t\t<NcButton variant=\"tertiary\" @click=\"closeDiff\">\n\t\t\t\t\t{{ backLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcCheckboxRadioSwitch :modelValue=\"showAllFields\" @update:modelValue=\"showAllFields = $event\">\n\t\t\t\t\t{{ showAllFieldsLabel }}\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t</div>\n\t\t\t<table v-if=\"visibleDiffRows.length > 0\" class=\"cn-version-history__diff-table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th>{{ fieldLabel }}</th>\n\t\t\t\t\t\t<th>{{ oldValueLabel }}</th>\n\t\t\t\t\t\t<th>{{ newValueLabel }}</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr v-for=\"row in visibleDiffRows\" :key=\"row.path\" :class=\"rowClass(row.type)\">\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-field\">\n\t\t\t\t\t\t\t{{ row.path }}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-value\">\n\t\t\t\t\t\t\t<component :is=\"valueCellTag(row)\" v-bind=\"valueCellProps(row)\">\n\t\t\t\t\t\t\t\t<template v-if=\"isNestedValue(row) === true\">\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tv-for=\"line in nestedLines(row, 'old')\"\n\t\t\t\t\t\t\t\t\t\t:key=\"line.path\"\n\t\t\t\t\t\t\t\t\t\t:class=\"lineClass(line.type)\">\n\t\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t\t{{ formatScalar(row.oldValue) }}\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td class=\"cn-version-history__diff-value\">\n\t\t\t\t\t\t\t<component :is=\"valueCellTag(row)\" v-bind=\"valueCellProps(row)\">\n\t\t\t\t\t\t\t\t<template v-if=\"isNestedValue(row) === true\">\n\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\tv-for=\"line in nestedLines(row, 'new')\"\n\t\t\t\t\t\t\t\t\t\t:key=\"line.path\"\n\t\t\t\t\t\t\t\t\t\t:class=\"lineClass(line.type)\">\n\t\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t\t\t\t{{ formatScalar(row.newValue) }}\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t</component>\n\t\t\t\t\t\t</td>\n\t\t\t\t\t</tr>\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t\t<div v-else class=\"cn-version-history__diff-empty\">\n\t\t\t\t{{ noChangesLabel }}\n\t\t\t</div>\n\t\t</div>\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon } from '@nextcloud/vue'\nimport { markRaw } from 'vue'\nimport Compare from 'vue-material-design-icons/Compare.vue'\nimport FileCompare from 'vue-material-design-icons/FileCompare.vue'\nimport CnDetailCard from '../CnDetailCard/CnDetailCard.vue'\nimport { foldAuditTrailEntries } from '../../utils/auditTrailDiff.js'\nimport { computeObjectDiff } from '../../utils/computeObjectDiff.js'\nimport { buildHeaders } from '../../utils/index.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * A single row rendered in the top-level diff table.\n *\n * @typedef {object} FieldDiffRow\n * @property {string} path Field name.\n * @property {'added'|'removed'|'changed'|'unchanged'} type Classification.\n * @property {unknown} oldValue Value before.\n * @property {unknown} newValue Value after.\n */\n\n/**\n * Classify one top-level field between two folded states, reusing\n * `computeObjectDiff` to decide equality (so nested objects/arrays are\n * compared structurally, not by reference).\n *\n * @param {string} key Field name.\n * @param {object} oldState Folded \"before\" state.\n * @param {object} newState Folded \"after\" state.\n * @return {FieldDiffRow} The classified row.\n */\nfunction classifyField(key, oldState, newState) {\n\tconst oldMissing = Object.hasOwn(oldState, key) === false\n\tconst newMissing = Object.hasOwn(newState, key) === false\n\tconst oldValue = oldState[key]\n\tconst newValue = newState[key]\n\n\tif (oldMissing === true && newMissing === false) {\n\t\treturn { path: key, type: 'added', oldValue: undefined, newValue }\n\t}\n\tif (oldMissing === false && newMissing === true) {\n\t\treturn { path: key, type: 'removed', oldValue, newValue: undefined }\n\t}\n\tconst nested = computeObjectDiff(oldValue, newValue)\n\tconst isChanged = nested.some((entry) => entry.type !== 'unchanged')\n\treturn { path: key, type: isChanged ? 'changed' : 'unchanged', oldValue, newValue }\n}\n\n/**\n * Build the top-level field-by-field diff table for a folded\n * before/after state pair.\n *\n * @param {object} oldState Folded \"before\" state.\n * @param {object} newState Folded \"after\" state.\n * @return {FieldDiffRow[]} One row per touched field, sorted by field name.\n */\nfunction buildFieldRows(oldState, newState) {\n\tconst keys = Array.from(new Set([...Object.keys(oldState), ...Object.keys(newState)])).sort()\n\treturn keys.map((key) => classifyField(key, oldState, newState))\n}\n\n/**\n * CnVersionHistory — object version-history list plus field-by-field\n * diff viewer, rendered by the integration registry on sidebar-tab\n * and dashboard/detail-widget surfaces alike.\n *\n * Basic usage\n * ```vue\n * <CnVersionHistory\n * :register=\"registerId\"\n * :schema=\"schemaId\"\n * :object-id=\"objectId\"\n * surface=\"detail-page\" />\n * ```\n */\nexport default {\n\tname: 'CnVersionHistory',\n\n\tcomponents: { CnDetailCard, NcLoadingIcon, NcButton, NcCheckboxRadioSwitch, Compare },\n\n\tprops: {\n\t\t/** OpenRegister register id (slug or uuid). */\n\t\tregister: { type: String, required: true },\n\t\t/** OpenRegister schema id (slug or uuid). */\n\t\tschema: { type: String, required: true },\n\t\t/** Parent object id. */\n\t\tobjectId: { type: String, required: true },\n\t\t/** Rendering surface — passed for AD-19 surface fallback consumers. */\n\t\tsurface: {\n\t\t\ttype: String,\n\t\t\tdefault: 'detail-page',\n\t\t\tvalidator: (value) => ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'].includes(value),\n\t\t},\n\n\t\t/** Base API URL. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Number of history entries to fetch per page. */\n\t\tpageSize: { type: Number, default: 20 },\n\t\t/** Whether the card collapses. */\n\t\tcollapsible: { type: Boolean, default: false },\n\t\t/** Override the card title (defaults to the translated label). */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Pre-translated empty-history label. */\n\t\tnoEntriesLabel: { type: String, default: () => t('nextcloud-vue', 'No version history yet') },\n\t\t/** Pre-translated fallback shown when an entry carries no semantic version. */\n\t\tfallbackVersionLabel: { type: String, default: () => t('nextcloud-vue', 'Unversioned change') },\n\t\t/** Pre-translated \"select for compare\" checkbox label. */\n\t\tselectForCompareLabel: { type: String, default: () => t('nextcloud-vue', 'Select for compare') },\n\t\t/** Pre-translated compare-action label. */\n\t\tcompareLabel: { type: String, default: () => t('nextcloud-vue', 'Compare selected') },\n\t\t/** Pre-translated load-more label. */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/** Pre-translated back-to-list label. */\n\t\tbackLabel: { type: String, default: () => t('nextcloud-vue', 'Back to history') },\n\t\t/** Pre-translated \"show all fields\" toggle label. */\n\t\tshowAllFieldsLabel: { type: String, default: () => t('nextcloud-vue', 'Show all fields') },\n\t\t/** Pre-translated diff table field-column header. */\n\t\tfieldLabel: { type: String, default: () => t('nextcloud-vue', 'Field') },\n\t\t/** Pre-translated diff table old-value-column header. */\n\t\toldValueLabel: { type: String, default: () => t('nextcloud-vue', 'Old value') },\n\t\t/** Pre-translated diff table new-value-column header. */\n\t\tnewValueLabel: { type: String, default: () => t('nextcloud-vue', 'New value') },\n\t\t/** Pre-translated label shown when a diff has no visible rows. */\n\t\tnoChangesLabel: { type: String, default: () => t('nextcloud-vue', 'No field changes to show') },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tFileCompare: markRaw(FileCompare),\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tselectedIds: [],\n\t\t\t/** `null` = list view; otherwise `{ oldState, newState }` for the open diff. */\n\t\t\tactiveDiff: null,\n\t\t\tshowAllFields: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', 'Version history')\n\t\t},\n\n\t\thasMore() {\n\t\t\treturn this.entries.length < this.total\n\t\t},\n\n\t\tdiffRows() {\n\t\t\tif (this.activeDiff === null) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn buildFieldRows(this.activeDiff.oldState, this.activeDiff.newState)\n\t\t},\n\n\t\tvisibleDiffRows() {\n\t\t\tif (this.showAllFields === true) {\n\t\t\t\treturn this.diffRows\n\t\t\t}\n\t\t\treturn this.diffRows.filter((row) => row.type !== 'unchanged')\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.resetAndFetch()\n\t\t\t\t}\n\t\t\t},\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.selectedIds = []\n\t\t\tthis.activeDiff = null\n\t\t\tthis.fetchEntries()\n\t\t},\n\n\t\tasync fetchEntries() {\n\t\t\tif (!this.register || !this.schema || !this.objectId) {\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 params = new URLSearchParams()\n\t\t\t\tparams.set('limit', String(this.pageSize))\n\t\t\t\tparams.set('_page', String(this.page))\n\t\t\t\tparams.set('_sort[created]', 'DESC')\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(`${url}?${params.toString()}`, { headers: buildHeaders() })\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\tthis.entries = this.page === 1 ? results : [...this.entries, ...results]\n\t\t\t\t\tthis.total = data.total || this.entries.length\n\t\t\t\t} else if (this.page === 1) {\n\t\t\t\t\tthis.entries = []\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('[CnVersionHistory] failed to fetch version history', err)\n\t\t\t\tif (this.page === 1) {\n\t\t\t\t\tthis.entries = []\n\t\t\t\t}\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\tloadMore() {\n\t\t\tthis.page += 1\n\t\t\tthis.fetchEntries()\n\t\t},\n\n\t\tisSelected(id) {\n\t\t\treturn this.selectedIds.includes(id)\n\t\t},\n\n\t\ttoggleSelected(id, checked) {\n\t\t\tif (checked === true) {\n\t\t\t\tif (this.selectedIds.includes(id) === false && this.selectedIds.length < 2) {\n\t\t\t\t\tthis.selectedIds = [...this.selectedIds, id]\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.selectedIds = this.selectedIds.filter((existing) => existing !== id)\n\t\t\t}\n\t\t},\n\n\t\topenSingleDiff(entry) {\n\t\t\tconst { oldState, newState } = foldAuditTrailEntries([entry])\n\t\t\tthis.showAllFields = false\n\t\t\tthis.activeDiff = { oldState, newState }\n\t\t},\n\n\t\topenCompareDiff() {\n\t\t\tif (this.selectedIds.length !== 2) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t// Entries are fetched newest-first; fold oldest-first so the\n\t\t\t// \"first old\" / \"last new\" semantics land on the right side.\n\t\t\tconst selectedEntries = this.entries.filter((entry) => this.selectedIds.includes(entry.id))\n\t\t\tconst chronological = [...selectedEntries].reverse()\n\t\t\tconst { oldState, newState } = foldAuditTrailEntries(chronological)\n\t\t\tthis.showAllFields = false\n\t\t\tthis.activeDiff = { oldState, newState }\n\t\t},\n\n\t\tcloseDiff() {\n\t\t\tthis.activeDiff = null\n\t\t},\n\n\t\tisNestedValue(row) {\n\t\t\tconst isObj = (v) => v !== null && typeof v === 'object'\n\t\t\treturn isObj(row.oldValue) === true || isObj(row.newValue) === true\n\t\t},\n\n\t\t/**\n\t\t * Build the per-line nested diff for one side of a table cell\n\t\t * whose value is an object/array, so each nested key can be\n\t\t * individually add/remove/change tinted.\n\t\t *\n\t\t * @param {FieldDiffRow} row The parent field row.\n\t\t * @param {'old'|'new'} side Which side is being rendered (both sides render the same nested diff so add/remove/change context matches on both columns).\n\t\t * @return {Array<{path: string, type: string, text: string}>} Rendered lines.\n\t\t */\n\t\tnestedLines(row, side) {\n\t\t\tconst base = row.oldValue !== null && typeof row.oldValue === 'object' ? row.oldValue : {}\n\t\t\tconst next = row.newValue !== null && typeof row.newValue === 'object' ? row.newValue : {}\n\t\t\tconst from = row.type === 'added' ? {} : base\n\t\t\tconst to = row.type === 'removed' ? {} : next\n\t\t\tconst nested = computeObjectDiff(from, to)\n\t\t\tconst visible = this.showAllFields === true ? nested : nested.filter((entry) => entry.type !== 'unchanged')\n\t\t\treturn visible.map((entry) => ({\n\t\t\t\tpath: entry.path,\n\t\t\t\ttype: entry.type,\n\t\t\t\ttext: this.formatNestedLine(entry, side),\n\t\t\t}))\n\t\t},\n\n\t\tformatNestedLine(entry, side) {\n\t\t\tconst label = entry.path === '' ? '·' : entry.path\n\t\t\tif (entry.type === 'changed') {\n\t\t\t\tconst shown = side === 'new' ? entry.newValue : entry.oldValue\n\t\t\t\treturn `${label}: ${this.formatScalar(shown)}`\n\t\t\t}\n\t\t\tconst value = entry.type === 'removed' ? entry.oldValue : entry.newValue\n\t\t\treturn `${label}: ${this.formatScalar(value)}`\n\t\t},\n\n\t\trowClass(type) {\n\t\t\treturn {\n\t\t\t\t'cn-version-history__diff-row': true,\n\t\t\t\t[`cn-version-history__diff-row--${type}`]: true,\n\t\t\t}\n\t\t},\n\n\t\tlineClass(type) {\n\t\t\treturn {\n\t\t\t\t'cn-version-history__diff-line': true,\n\t\t\t\t[`cn-version-history__diff-line--${type}`]: true,\n\t\t\t}\n\t\t},\n\n\t\tvalueCellTag(row) {\n\t\t\treturn this.isNestedValue(row) === true ? 'pre' : 'span'\n\t\t},\n\n\t\tvalueCellProps(row) {\n\t\t\treturn this.isNestedValue(row) === true ? { class: 'cn-version-history__diff-json' } : {}\n\t\t},\n\n\t\tformatScalar(value) {\n\t\t\tif (value === undefined) {\n\t\t\t\treturn '—'\n\t\t\t}\n\t\t\tif (value === null) {\n\t\t\t\treturn 'null'\n\t\t\t}\n\t\t\tif (typeof value === 'object') {\n\t\t\t\ttry {\n\t\t\t\t\treturn JSON.stringify(value)\n\t\t\t\t} catch {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn String(value)\n\t\t},\n\n\t\tformatUser(entry) {\n\t\t\treturn entry.userName || entry.user || t('nextcloud-vue', 'System')\n\t\t},\n\n\t\tformatWhen(entry) {\n\t\t\tconst raw = entry.created || entry.creationDateTime || entry.timestamp\n\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst d = new Date(raw)\n\t\t\tif (Number.isNaN(d.getTime()) === true) {\n\t\t\t\treturn String(raw)\n\t\t\t}\n\t\t\treturn d.toLocaleString(userLocale())\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-version-history__empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n\n.cn-version-history__rows {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n}\n\n.cn-version-history__row {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 6px 0;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-version-history__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-version-history__row-main {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\talign-items: baseline;\n\tflex: 1 1 auto;\n\tbackground: none;\n\tborder: none;\n\tcursor: pointer;\n\ttext-align: left;\n\tfont: inherit;\n\tcolor: inherit;\n\tpadding: 4px;\n\tborder-radius: var(--border-radius);\n}\n\n.cn-version-history__row-main:hover {\n\tbackground-color: var(--color-background-hover);\n}\n\n.cn-version-history__version {\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-version-history__action {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-version-history__when {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.85em;\n\twhite-space: nowrap;\n}\n\n.cn-version-history__user {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.9em;\n}\n\n.cn-version-history__toolbar {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-top: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-version-history__diff-toolbar {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\talign-items: center;\n\tgap: 8px;\n\tmargin-bottom: 8px;\n\tflex-wrap: wrap;\n}\n\n.cn-version-history__diff-table {\n\twidth: 100%;\n\tborder-collapse: collapse;\n}\n\n.cn-version-history__diff-table th,\n.cn-version-history__diff-table td {\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding: 6px 8px;\n\ttext-align: left;\n\tvertical-align: top;\n}\n\n.cn-version-history__diff-field {\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\twhite-space: nowrap;\n}\n\n.cn-version-history__diff-json {\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n\tfont-family: monospace;\n\tfont-size: 12px;\n}\n\n.cn-version-history__diff-row--added .cn-version-history__diff-field {\n\tcolor: var(--color-success);\n}\n\n.cn-version-history__diff-row--removed .cn-version-history__diff-field {\n\tcolor: var(--color-error);\n}\n\n.cn-version-history__diff-row--changed .cn-version-history__diff-field {\n\tcolor: var(--color-warning);\n}\n\n.cn-version-history__diff-line--added {\n\tbackground-color: color-mix(in srgb, var(--color-success) 15%, transparent);\n\tcolor: var(--color-success);\n}\n\n.cn-version-history__diff-line--removed {\n\tbackground-color: color-mix(in srgb, var(--color-error) 15%, transparent);\n\tcolor: var(--color-error);\n\ttext-decoration: line-through;\n}\n\n.cn-version-history__diff-line--changed {\n\tbackground-color: color-mix(in srgb, var(--color-warning) 15%, transparent);\n\tcolor: var(--color-warning);\n}\n\n.cn-version-history__diff-line--unchanged {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-version-history__diff-empty {\n\tcolor: var(--color-text-maxcontrast);\n\ttext-align: center;\n\tpadding: 12px 0;\n}\n</style>\n"],"names":["_createBlock","_toDisplayString","_openBlock","_createElementBlock","_createElementVNode","_Fragment","_renderList","_createVNode","_createTextVNode","_normalizeClass","_resolveDynamicComponent","_mergeProps"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnNoteHistoryDialog.vue2.js';
|
|
|
2
2
|
import { render } from './CnNoteHistoryDialog.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-0dcefccf";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -4,6 +4,7 @@ import AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue
|
|
|
4
4
|
import History from 'vue-material-design-icons/History.vue';
|
|
5
5
|
import __sfc_main from '../components/CnDialog/CnDialog.vue.js';
|
|
6
6
|
import { dialogBoardMixin } from '../mixins/dialogBoard.js';
|
|
7
|
+
import { userLocale } from '../utils/userLocale.js';
|
|
7
8
|
import { prefixUrl, buildHeaders } from '../utils/headers.js';
|
|
8
9
|
|
|
9
10
|
var script = {
|
|
@@ -120,7 +121,7 @@ var script = {
|
|
|
120
121
|
return ''
|
|
121
122
|
}
|
|
122
123
|
try {
|
|
123
|
-
return new Date(dateStr).toLocaleString(
|
|
124
|
+
return new Date(dateStr).toLocaleString(userLocale(), {
|
|
124
125
|
year: 'numeric',
|
|
125
126
|
month: 'short',
|
|
126
127
|
day: 'numeric',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnNoteHistoryDialog.vue2.js","sources":["../../../src/dialogs/CnNoteHistoryDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<!--\n CnNoteHistoryDialog — what a note said before it was edited.\n\n Lives in src/dialogs/ per the ADR-004 modal/dialog file-isolation rule:\n NcDialog markup never sits inline in the component that opens it.\n\n A note is a Nextcloud comment and an edit overwrites its message, so\n OpenRegister keeps every prior text beside the comment. On open this fetches\n GET /apps/openregister/api/objects/{register}/{schema}/{objectId}/notes/{noteId}/versions\n which answers `{ results, total }` with the versions newest first. Each row\n carries the text that was replaced, the author it was attributed to, who\n replaced it and when.\n\n The list is read-only. Restoring an old text is a new note that references\n the old one, not a rewrite of the record.\n\n Emits:\n - update:open (false) — when the dialog is closed\n-->\n<template>\n\t<CnDialog\n\t\t:look=\"look\"\n\t\t:width=\"width\"\n\t\tdefaultWidth=\"wizard\"\n\t\t:eyebrow=\"eyebrow\"\n\t\t:subtitle=\"subtitle\"\n\t\t:open=\"open\"\n\t\t:name=\"dialogName\"\n\t\t:closeOnClickOutside=\"true\"\n\t\tsize=\"normal\"\n\t\t@update:open=\"$emit('update:open', $event)\">\n\t\t<div\n\t\t\tclass=\"cn-note-history\"\n\t\t\tdata-testid=\"cn-modal\"\n\t\t\tdata-testid-modal=\"cn-note-history-dialog\">\n\t\t\t<NcLoadingIcon v-if=\"loading\" :name=\"loadingLabel\" />\n\n\t\t\t<NcEmptyContent v-else-if=\"failed\" :name=\"errorLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<AlertCircleOutline :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\n\t\t\t<NcEmptyContent v-else-if=\"versions.length === 0\" :name=\"emptyLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<HistoryIcon :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\n\t\t\t<ol v-else class=\"cn-note-history__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"version in versions\"\n\t\t\t\t\t:key=\"version.id || version.uuid\"\n\t\t\t\t\tclass=\"cn-note-history__item\"\n\t\t\t\t\tdata-testid=\"cn-note-history-version\">\n\t\t\t\t\t<p class=\"cn-note-history__meta\">\n\t\t\t\t\t\t{{ metaLine(version) }}\n\t\t\t\t\t</p>\n\t\t\t\t\t<p class=\"cn-note-history__message\">\n\t\t\t\t\t\t{{ version.message }}\n\t\t\t\t\t</p>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</div>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport HistoryIcon from 'vue-material-design-icons/History.vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\nimport { dialogBoardMixin } from '../mixins/dialogBoard.js'\nimport { buildHeaders, prefixUrl } from '../utils/index.js'\n\nexport default {\n\tname: 'CnNoteHistoryDialog',\n\n\tcomponents: { CnDialog, NcEmptyContent, NcLoadingIcon, AlertCircleOutline, HistoryIcon },\n\n\tmixins: [dialogBoardMixin],\n\n\tprops: {\n\t\t/** Whether the dialog is open */\n\t\topen: { type: Boolean, default: false },\n\t\t/** The note whose earlier versions are listed */\n\t\tnoteId: { type: [String, Number], default: '' },\n\t\t/** ID of the object the note hangs on */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema slug */\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/** Title of the dialog */\n\t\tdialogName: { type: String, default: () => t('nextcloud-vue', 'Earlier versions') },\n\t\t/** Text shown while the versions are being fetched */\n\t\tloadingLabel: { type: String, default: () => t('nextcloud-vue', 'Loading earlier versions…') },\n\t\t/** Text shown when this note was never edited */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'Nobody has changed this note') },\n\t\t/** Text shown when the versions could not be read */\n\t\terrorLabel: { type: String, default: () => t('nextcloud-vue', 'The earlier versions could not be loaded') },\n\t},\n\n\temits: ['update:open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tversions: [],\n\t\t\tloading: false,\n\t\t\tfailed: false,\n\t\t}\n\t},\n\n\twatch: {\n\t\topen: {\n\t\t\timmediate: true,\n\t\t\thandler(isOpen) {\n\t\t\t\tif (isOpen) {\n\t\t\t\t\tthis.fetchVersions()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the note's earlier versions, newest first.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchVersions() {\n\t\t\tif (!this.register || !this.schema || !this.noteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\tthis.versions = []\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/${this.noteId}/versions`),\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\t// A failed read says so. Rendering an empty list here would\n\t\t\t\t\t// claim the note was never edited, which is a different\n\t\t\t\t\t// statement and the one the reader would believe.\n\t\t\t\t\tthis.failed = true\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tthis.versions = data.results || []\n\t\t\t} catch (err) {\n\t\t\t\tthis.failed = true\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNoteHistoryDialog: Failed to fetch note versions', 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 * The line above a prior text: who wrote it, who replaced it, when.\n\t\t *\n\t\t * @param {object} version One row from the versions endpoint.\n\t\t * @return {string} The rendered line.\n\t\t */\n\t\tmetaLine(version) {\n\t\t\tconst author = version.authorDisplayName || version.author || t('nextcloud-vue', 'Unknown')\n\t\t\tconst editor = version.editedByDisplayName || version.editedBy || t('nextcloud-vue', 'Unknown')\n\t\t\treturn t('nextcloud-vue', 'Written by {author}, replaced by {editor} on {date}', {\n\t\t\t\tauthor,\n\t\t\t\teditor,\n\t\t\t\tdate: this.formatDate(version.editedAt),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Render a moment in the reader's own locale.\n\t\t *\n\t\t * @param {string} dateStr An ISO-8601 moment.\n\t\t * @return {string} The formatted moment, or the raw string.\n\t\t */\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-note-history { padding: 4px 0; }\n\n.cn-note-history__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-note-history__item {\n\tborder-inline-start: 2px solid var(--color-border);\n\tpadding-inline-start: 12px;\n}\n\n.cn-note-history__meta {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n\tmargin: 0 0 2px;\n}\n\n.cn-note-history__message {\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["CnDialog","HistoryIcon","t"],"mappings":";;;;;;;;AAiFA,aAAe;CACd,IAAI,EAAE,qBAAqB;;AAE3B,CAAA,UAAU,EAAE,YAAEA,UAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,kBAAkB,eAAEC,SAAa;;CAExF,MAAM,EAAE,CAAC,gBAAgB,CAAC;;AAE1B,CAAA,KAAK,EAAE;;AAEN,EAAA,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;AACvC;AACA,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI;AAC/C;AACA,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;AAE1C,EAAA,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;;AAEvC,EAAA,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI;AACrC;EACA,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAuB,EAAG;AAC5D;AACA,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,kBAAkB,GAAG;AACnF;AACA,EAAA,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,2BAA2B,GAAG;AAC9F;AACA,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,8BAA8B,GAAG;AAC/F;AACA,EAAA,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,0CAA0C,GAAG;EAC3G;;AAED,CAAA,KAAK,EAAE,CAAC,aAAa,CAAC;;AAEtB,CAAA,IAAI,GAAG;AACN,EAAA,OAAO;GACN,QAAQ,EAAE,EAAE;GACZ,OAAO,EAAE,KAAK;GACd,MAAM,EAAE,KAAK;AACd,GAAA;EACA;;AAED,CAAA,KAAK,EAAE;EACN,IAAI,EAAE;AACL,GAAA,SAAS,EAAE,IAAI;AACf,GAAA,OAAO,CAAC,MAAM,EAAE;IACf,IAAI,MAAM,EAAE;AACX,KAAA,IAAI,CAAC,aAAa,GAAC;AACpB,KAAA;IACA;GACD;EACD;;AAED,CAAA,OAAO,EAAE;AACR;AACC;AACA;;;AAGD,EAAA,MAAM,aAAa,GAAG;GACrB,IAAI,CAAC,IAAI,CAAC,QAAO,IAAK,CAAC,IAAI,CAAC,MAAO,IAAG,CAAC,IAAI,CAAC,MAAM,EAAE;IACnD,MAAK;AACN,IAAA;AACA,GAAA,IAAI,CAAC,OAAM,GAAI,KAAG;AAClB,GAAA,IAAI,CAAC,MAAO,GAAE,MAAI;AAClB,GAAA,IAAI,CAAC,QAAO,GAAI,GAAC;AACjB,GAAA,IAAI;IACH,MAAM,WAAW,MAAM,KAAK;KAC3B,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;KACnH,EAAE,OAAO,EAAE,YAAY,EAAC,EAAG;AAC5B,MAAA;AACA,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;;AAEjB;AACA;AACA,KAAA,IAAI,CAAC,MAAK,GAAI,KAAG;KACjB,MAAK;AACN,KAAA;IACA,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;IACjC,IAAI,CAAC,QAAS,GAAE,IAAI,CAAC,OAAM,IAAK,GAAC;IAChC,CAAA,OAAO,GAAG,EAAE;AACb,IAAA,IAAI,CAAC,MAAK,GAAI,KAAG;AACjB;AACA,IAAA,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,GAAG,EAAA;AACxE,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,OAAQ,GAAE,MAAI;AACpB,IAAA;GACA;;AAED;;AAEC;;AAEA;;AAED,EAAA,QAAQ,CAAC,OAAO,EAAE;AACjB,GAAA,MAAM,MAAK,GAAI,OAAO,CAAC,iBAAkB,IAAG,OAAO,CAAC,MAAK,IAAKA,SAAC,CAAC,eAAe,EAAE,SAAS,EAAA;AAC1F,GAAA,MAAM,MAAO,GAAE,OAAO,CAAC,mBAAoB,IAAG,OAAO,CAAC,YAAYA,SAAC,CAAC,eAAe,EAAE,SAAS,EAAA;AAC9F,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,qDAAqD,EAAE;AAChF,IAAA,MAAM;AACN,IAAA,MAAM;AACN,IAAA,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC;IACvC,CAAA;GACD;;AAED;AACC;AACA;AACA;;;AAGD,EAAA,UAAU,CAAC,OAAO,EAAE;GACnB,IAAI,CAAC,OAAO,EAAE;AACb,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,IAAI;IACH,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE;AAClD,KAAA,IAAI,EAAE,SAAS;KACf,KAAK,EAAE,OAAO;KACd,GAAG,EAAE,SAAS;AACd,KAAA,IAAI,EAAE,SAAS;AACf,KAAA,MAAM,EAAE,SAAS;KACjB,CAAA;AACF,IAAA,CAAE,MAAM;IACP,OAAO,OAAM;AACd,IAAA;GACA;EACD;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"CnNoteHistoryDialog.vue2.js","sources":["../../../src/dialogs/CnNoteHistoryDialog.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<!--\n CnNoteHistoryDialog — what a note said before it was edited.\n\n Lives in src/dialogs/ per the ADR-004 modal/dialog file-isolation rule:\n NcDialog markup never sits inline in the component that opens it.\n\n A note is a Nextcloud comment and an edit overwrites its message, so\n OpenRegister keeps every prior text beside the comment. On open this fetches\n GET /apps/openregister/api/objects/{register}/{schema}/{objectId}/notes/{noteId}/versions\n which answers `{ results, total }` with the versions newest first. Each row\n carries the text that was replaced, the author it was attributed to, who\n replaced it and when.\n\n The list is read-only. Restoring an old text is a new note that references\n the old one, not a rewrite of the record.\n\n Emits:\n - update:open (false) — when the dialog is closed\n-->\n<template>\n\t<CnDialog\n\t\t:look=\"look\"\n\t\t:width=\"width\"\n\t\tdefaultWidth=\"wizard\"\n\t\t:eyebrow=\"eyebrow\"\n\t\t:subtitle=\"subtitle\"\n\t\t:open=\"open\"\n\t\t:name=\"dialogName\"\n\t\t:closeOnClickOutside=\"true\"\n\t\tsize=\"normal\"\n\t\t@update:open=\"$emit('update:open', $event)\">\n\t\t<div\n\t\t\tclass=\"cn-note-history\"\n\t\t\tdata-testid=\"cn-modal\"\n\t\t\tdata-testid-modal=\"cn-note-history-dialog\">\n\t\t\t<NcLoadingIcon v-if=\"loading\" :name=\"loadingLabel\" />\n\n\t\t\t<NcEmptyContent v-else-if=\"failed\" :name=\"errorLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<AlertCircleOutline :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\n\t\t\t<NcEmptyContent v-else-if=\"versions.length === 0\" :name=\"emptyLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<HistoryIcon :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\n\t\t\t<ol v-else class=\"cn-note-history__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"version in versions\"\n\t\t\t\t\t:key=\"version.id || version.uuid\"\n\t\t\t\t\tclass=\"cn-note-history__item\"\n\t\t\t\t\tdata-testid=\"cn-note-history-version\">\n\t\t\t\t\t<p class=\"cn-note-history__meta\">\n\t\t\t\t\t\t{{ metaLine(version) }}\n\t\t\t\t\t</p>\n\t\t\t\t\t<p class=\"cn-note-history__message\">\n\t\t\t\t\t\t{{ version.message }}\n\t\t\t\t\t</p>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</div>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport HistoryIcon from 'vue-material-design-icons/History.vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\nimport { dialogBoardMixin } from '../mixins/dialogBoard.js'\nimport { buildHeaders, prefixUrl } from '../utils/index.js'\nimport { userLocale } from '../utils/userLocale.js'\n\nexport default {\n\tname: 'CnNoteHistoryDialog',\n\n\tcomponents: { CnDialog, NcEmptyContent, NcLoadingIcon, AlertCircleOutline, HistoryIcon },\n\n\tmixins: [dialogBoardMixin],\n\n\tprops: {\n\t\t/** Whether the dialog is open */\n\t\topen: { type: Boolean, default: false },\n\t\t/** The note whose earlier versions are listed */\n\t\tnoteId: { type: [String, Number], default: '' },\n\t\t/** ID of the object the note hangs on */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema slug */\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/** Title of the dialog */\n\t\tdialogName: { type: String, default: () => t('nextcloud-vue', 'Earlier versions') },\n\t\t/** Text shown while the versions are being fetched */\n\t\tloadingLabel: { type: String, default: () => t('nextcloud-vue', 'Loading earlier versions…') },\n\t\t/** Text shown when this note was never edited */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'Nobody has changed this note') },\n\t\t/** Text shown when the versions could not be read */\n\t\terrorLabel: { type: String, default: () => t('nextcloud-vue', 'The earlier versions could not be loaded') },\n\t},\n\n\temits: ['update:open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tversions: [],\n\t\t\tloading: false,\n\t\t\tfailed: false,\n\t\t}\n\t},\n\n\twatch: {\n\t\topen: {\n\t\t\timmediate: true,\n\t\t\thandler(isOpen) {\n\t\t\t\tif (isOpen) {\n\t\t\t\t\tthis.fetchVersions()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the note's earlier versions, newest first.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchVersions() {\n\t\t\tif (!this.register || !this.schema || !this.noteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\tthis.versions = []\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/${this.noteId}/versions`),\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\t// A failed read says so. Rendering an empty list here would\n\t\t\t\t\t// claim the note was never edited, which is a different\n\t\t\t\t\t// statement and the one the reader would believe.\n\t\t\t\t\tthis.failed = true\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tthis.versions = data.results || []\n\t\t\t} catch (err) {\n\t\t\t\tthis.failed = true\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNoteHistoryDialog: Failed to fetch note versions', 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 * The line above a prior text: who wrote it, who replaced it, when.\n\t\t *\n\t\t * @param {object} version One row from the versions endpoint.\n\t\t * @return {string} The rendered line.\n\t\t */\n\t\tmetaLine(version) {\n\t\t\tconst author = version.authorDisplayName || version.author || t('nextcloud-vue', 'Unknown')\n\t\t\tconst editor = version.editedByDisplayName || version.editedBy || t('nextcloud-vue', 'Unknown')\n\t\t\treturn t('nextcloud-vue', 'Written by {author}, replaced by {editor} on {date}', {\n\t\t\t\tauthor,\n\t\t\t\teditor,\n\t\t\t\tdate: this.formatDate(version.editedAt),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Render a moment in the reader's own locale.\n\t\t *\n\t\t * @param {string} dateStr An ISO-8601 moment.\n\t\t * @return {string} The formatted moment, or the raw string.\n\t\t */\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-note-history { padding: 4px 0; }\n\n.cn-note-history__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-note-history__item {\n\tborder-inline-start: 2px solid var(--color-border);\n\tpadding-inline-start: 12px;\n}\n\n.cn-note-history__meta {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n\tmargin: 0 0 2px;\n}\n\n.cn-note-history__message {\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["CnDialog","HistoryIcon","t"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnNoteHistoryDialog.vue3.js","sources":["../../../src/dialogs/CnNoteHistoryDialog.vue?vue&type=template&id=
|
|
1
|
+
{"version":3,"file":"CnNoteHistoryDialog.vue3.js","sources":["../../../src/dialogs/CnNoteHistoryDialog.vue?vue&type=template&id=0dcefccf&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<!--\n CnNoteHistoryDialog — what a note said before it was edited.\n\n Lives in src/dialogs/ per the ADR-004 modal/dialog file-isolation rule:\n NcDialog markup never sits inline in the component that opens it.\n\n A note is a Nextcloud comment and an edit overwrites its message, so\n OpenRegister keeps every prior text beside the comment. On open this fetches\n GET /apps/openregister/api/objects/{register}/{schema}/{objectId}/notes/{noteId}/versions\n which answers `{ results, total }` with the versions newest first. Each row\n carries the text that was replaced, the author it was attributed to, who\n replaced it and when.\n\n The list is read-only. Restoring an old text is a new note that references\n the old one, not a rewrite of the record.\n\n Emits:\n - update:open (false) — when the dialog is closed\n-->\n<template>\n\t<CnDialog\n\t\t:look=\"look\"\n\t\t:width=\"width\"\n\t\tdefaultWidth=\"wizard\"\n\t\t:eyebrow=\"eyebrow\"\n\t\t:subtitle=\"subtitle\"\n\t\t:open=\"open\"\n\t\t:name=\"dialogName\"\n\t\t:closeOnClickOutside=\"true\"\n\t\tsize=\"normal\"\n\t\t@update:open=\"$emit('update:open', $event)\">\n\t\t<div\n\t\t\tclass=\"cn-note-history\"\n\t\t\tdata-testid=\"cn-modal\"\n\t\t\tdata-testid-modal=\"cn-note-history-dialog\">\n\t\t\t<NcLoadingIcon v-if=\"loading\" :name=\"loadingLabel\" />\n\n\t\t\t<NcEmptyContent v-else-if=\"failed\" :name=\"errorLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<AlertCircleOutline :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\n\t\t\t<NcEmptyContent v-else-if=\"versions.length === 0\" :name=\"emptyLabel\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<HistoryIcon :size=\"48\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\n\t\t\t<ol v-else class=\"cn-note-history__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"version in versions\"\n\t\t\t\t\t:key=\"version.id || version.uuid\"\n\t\t\t\t\tclass=\"cn-note-history__item\"\n\t\t\t\t\tdata-testid=\"cn-note-history-version\">\n\t\t\t\t\t<p class=\"cn-note-history__meta\">\n\t\t\t\t\t\t{{ metaLine(version) }}\n\t\t\t\t\t</p>\n\t\t\t\t\t<p class=\"cn-note-history__message\">\n\t\t\t\t\t\t{{ version.message }}\n\t\t\t\t\t</p>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</div>\n\t</CnDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcEmptyContent, NcLoadingIcon } from '@nextcloud/vue'\nimport AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'\nimport HistoryIcon from 'vue-material-design-icons/History.vue'\nimport CnDialog from '../components/CnDialog/CnDialog.vue'\nimport { dialogBoardMixin } from '../mixins/dialogBoard.js'\nimport { buildHeaders, prefixUrl } from '../utils/index.js'\nimport { userLocale } from '../utils/userLocale.js'\n\nexport default {\n\tname: 'CnNoteHistoryDialog',\n\n\tcomponents: { CnDialog, NcEmptyContent, NcLoadingIcon, AlertCircleOutline, HistoryIcon },\n\n\tmixins: [dialogBoardMixin],\n\n\tprops: {\n\t\t/** Whether the dialog is open */\n\t\topen: { type: Boolean, default: false },\n\t\t/** The note whose earlier versions are listed */\n\t\tnoteId: { type: [String, Number], default: '' },\n\t\t/** ID of the object the note hangs on */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** OpenRegister schema slug */\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/** Title of the dialog */\n\t\tdialogName: { type: String, default: () => t('nextcloud-vue', 'Earlier versions') },\n\t\t/** Text shown while the versions are being fetched */\n\t\tloadingLabel: { type: String, default: () => t('nextcloud-vue', 'Loading earlier versions…') },\n\t\t/** Text shown when this note was never edited */\n\t\temptyLabel: { type: String, default: () => t('nextcloud-vue', 'Nobody has changed this note') },\n\t\t/** Text shown when the versions could not be read */\n\t\terrorLabel: { type: String, default: () => t('nextcloud-vue', 'The earlier versions could not be loaded') },\n\t},\n\n\temits: ['update:open'],\n\n\tdata() {\n\t\treturn {\n\t\t\tversions: [],\n\t\t\tloading: false,\n\t\t\tfailed: false,\n\t\t}\n\t},\n\n\twatch: {\n\t\topen: {\n\t\t\timmediate: true,\n\t\t\thandler(isOpen) {\n\t\t\t\tif (isOpen) {\n\t\t\t\t\tthis.fetchVersions()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Read the note's earlier versions, newest first.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync fetchVersions() {\n\t\t\tif (!this.register || !this.schema || !this.noteId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tthis.failed = false\n\t\t\tthis.versions = []\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/${this.noteId}/versions`),\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\t// A failed read says so. Rendering an empty list here would\n\t\t\t\t\t// claim the note was never edited, which is a different\n\t\t\t\t\t// statement and the one the reader would believe.\n\t\t\t\t\tthis.failed = true\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tthis.versions = data.results || []\n\t\t\t} catch (err) {\n\t\t\t\tthis.failed = true\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnNoteHistoryDialog: Failed to fetch note versions', 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 * The line above a prior text: who wrote it, who replaced it, when.\n\t\t *\n\t\t * @param {object} version One row from the versions endpoint.\n\t\t * @return {string} The rendered line.\n\t\t */\n\t\tmetaLine(version) {\n\t\t\tconst author = version.authorDisplayName || version.author || t('nextcloud-vue', 'Unknown')\n\t\t\tconst editor = version.editedByDisplayName || version.editedBy || t('nextcloud-vue', 'Unknown')\n\t\t\treturn t('nextcloud-vue', 'Written by {author}, replaced by {editor} on {date}', {\n\t\t\t\tauthor,\n\t\t\t\teditor,\n\t\t\t\tdate: this.formatDate(version.editedAt),\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Render a moment in the reader's own locale.\n\t\t *\n\t\t * @param {string} dateStr An ISO-8601 moment.\n\t\t * @return {string} The formatted moment, or the raw string.\n\t\t */\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-note-history { padding: 4px 0; }\n\n.cn-note-history__list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-note-history__item {\n\tborder-inline-start: 2px solid var(--color-border);\n\tpadding-inline-start: 12px;\n}\n\n.cn-note-history__meta {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n\tmargin: 0 0 2px;\n}\n\n.cn-note-history__message {\n\tmargin: 0;\n\twhite-space: pre-wrap;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["_createBlock","_createElementVNode","_createVNode"],"mappings":";;;AA6DM,EAAA,OAAG;AACJ,EAAA,aAAG,EAAA,UAAA;AACH,EAAA,mBAAe,EAAC,wBAAmB;;;;;;;;;;;;;;;;uBAdpCA;QACG,EAAE,IAAI,CAAA,IAAA;SACL,EAAE,IAAI,CAAA,KAAA;AACX,IAAA,YAAW,EAAC,QAAI;;AAEhB,IAAA,QAAQ,EAAC,IAAS,CAAA,QAAA;AACjB,IAAA,IAAE,EAAA,MAAA,CAAA,IAAA;QACC,EAAE,MAAW,CAAA,UAAA;AACf,IAAA,mBAAiB,EAAG,IAAG;QACtB,EAAC,QAAQ;IACV,eAAS,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,IAAK,CAAA,KAAA,CAAA,aAAA,EAAgB,MAAK,CAAA,CAAA,CAAA;;qBACrC;AAAA,MAAAC,kBAAA,QAAA;cAIqB,CAAA,OAAA;0BAApBD,WAAoB,CAAA,wBAAA,EAAA;;AAAA,cAAA,IAAA,EAAA,MAAA,CAAA,YAAA;;aAElB,KAAA,CAAA,MAAA;;;AAAA,gBAAA,IAAA,EAAA,MAAA,CAAA,UAAA;;AACD,gBAAA,IAAA,UACF,MAAE;kBAAFE,WAAE,CAAA,6BAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -2,7 +2,7 @@ import script from './CnActivityCard.vue2.js';
|
|
|
2
2
|
import { render } from './CnActivityCard.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-287c17fa";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -10,6 +10,7 @@ import TagOutline from 'vue-material-design-icons/TagOutline.vue';
|
|
|
10
10
|
import Timeline from 'vue-material-design-icons/Timeline.vue';
|
|
11
11
|
import __sfc_main from '../../../components/CnDetailCard/CnDetailCard.vue.js';
|
|
12
12
|
import __sfc_main$1 from '../../../components/CnVisibilityChip/CnVisibilityChip.vue.js';
|
|
13
|
+
import { userLocale } from '../../../utils/userLocale.js';
|
|
13
14
|
import { prefixUrl, buildHeaders } from '../../../utils/headers.js';
|
|
14
15
|
|
|
15
16
|
const VALID_SURFACES = ['user-dashboard', 'app-dashboard', 'detail-page', 'single-entity'];
|
|
@@ -196,7 +197,7 @@ var script = {
|
|
|
196
197
|
return translate('nextcloud-vue', 'Yesterday')
|
|
197
198
|
}
|
|
198
199
|
try {
|
|
199
|
-
return date.toLocaleDateString(
|
|
200
|
+
return date.toLocaleDateString(userLocale(), { weekday: 'short', day: 'numeric', month: 'short' })
|
|
200
201
|
} catch {
|
|
201
202
|
return date.toISOString().split('T')[0]
|
|
202
203
|
}
|
|
@@ -208,7 +209,7 @@ var script = {
|
|
|
208
209
|
return ''
|
|
209
210
|
}
|
|
210
211
|
try {
|
|
211
|
-
return ts.toLocaleTimeString(
|
|
212
|
+
return ts.toLocaleTimeString(userLocale(), { hour: '2-digit', minute: '2-digit' })
|
|
212
213
|
} catch {
|
|
213
214
|
return ts.toISOString().split('T')[1].slice(0, 5)
|
|
214
215
|
}
|