@conduction/nextcloud-vue 2.56.0-beta.37 → 2.56.0-beta.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue.js +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js +3 -2
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue3.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue.js +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js +5 -4
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue3.js.map +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue.js +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js +2 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +2 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +156 -14
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +105 -74
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue.js +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js +2 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue.js +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js +2 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +6 -5
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue.js +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js +2 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js.map +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +2 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +2 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +2 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue.js +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js +3 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js.map +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js +2 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue3.js.map +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue.js +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js +2 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue.js +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js +3 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js.map +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue3.js.map +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue.js +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue2.js +3 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue2.js.map +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue3.js.map +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue.js +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js +2 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js.map +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +49 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +3 -3
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue.js +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js +2 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js.map +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -5
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +2 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue.js +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js +3 -2
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +28 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +82 -75
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js +5 -4
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue3.js.map +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue.js +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js +2 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js.map +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue3.js.map +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue.js +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js +2 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js.map +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue3.js.map +1 -1
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js +2 -0
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js +2 -2
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue.js +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +2 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue.js +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js +2 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js.map +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +36 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +55 -40
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue.js +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js +2 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +2 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue.js +1 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js +2 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue.js +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js +2 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +3 -26
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue.js +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js +2 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js.map +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js +3 -2
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js +4 -3
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -2
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js +6 -5
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +35 -2
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +38 -2
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +1068 -962
- package/dist/esm/store/useObjectStore.js +7 -2
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/boardColumns.js +50 -1
- package/dist/esm/utils/boardColumns.js.map +1 -1
- package/dist/esm/utils/boardReferenceColumns.js +115 -4
- package/dist/esm/utils/boardReferenceColumns.js.map +1 -1
- package/dist/esm/utils/contentHeaderLink.js +48 -1
- package/dist/esm/utils/contentHeaderLink.js.map +1 -1
- package/dist/esm/utils/schema.js +5 -4
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/userLocale.js +30 -0
- package/dist/esm/utils/userLocale.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1088 -476
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1068 -962
- package/l10n/en.json +35 -2
- package/l10n/nl.json +38 -2
- package/package.json +1 -1
- package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +3 -2
- package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +5 -4
- package/src/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue +2 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +2 -1
- package/src/components/CnBoardView/CnBoardView.vue +189 -24
- package/src/components/CnCalendarEventPicker/CnCalendarEventPicker.vue +2 -1
- package/src/components/CnCalendarWidget/CnCalendarWidget.vue +2 -1
- package/src/components/CnChartWidget/CnChartWidget.vue +6 -5
- package/src/components/CnCollectivePagePicker/CnCollectivePagePicker.vue +2 -1
- package/src/components/CnConversationThread/CnConversationThread.vue +2 -1
- package/src/components/CnCountdownWidget/CnCountdownWidget.vue +2 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +2 -1
- package/src/components/CnDataMatrix/CnDataMatrix.vue +2 -1
- package/src/components/CnDetailPage/CnDetailHeaderChips.vue +2 -1
- package/src/components/CnEmailPicker/CnEmailPicker.vue +2 -1
- package/src/components/CnFederationStatus/CnFederationStatus.vue +3 -1
- package/src/components/CnFileManager/CnFileManager.vue +2 -1
- package/src/components/CnFilePreview/CnFilePreview.vue +2 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +54 -6
- package/src/components/CnFollowToggle/CnFollowToggle.vue +2 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +30 -4
- package/src/components/CnNotesCard/CnNotesCard.vue +2 -1
- package/src/components/CnObjectCalendar/CnObjectCalendar.vue +3 -2
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +36 -0
- package/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +5 -4
- package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +2 -1
- package/src/components/CnObjectSidebar/CnFlowTasksPanel.vue +2 -1
- package/src/components/CnObjectSidebar/CnNotesTab.vue +2 -1
- package/src/components/CnObjectSidebar/CnTasksTab.vue +2 -1
- package/src/components/CnPropertySourceField/CnPropertySourceField.vue +2 -1
- package/src/components/CnRoadmapItem/CnRoadmapItem.vue +2 -1
- package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +4 -2
- package/src/components/CnStatsBlock/CnStatsBlock.vue +2 -1
- package/src/components/CnSummaryAggregates/CnSummaryAggregates.vue +2 -1
- package/src/components/CnTabsWidget/CnTabsWidget.vue +71 -0
- package/src/components/CnTasksCard/CnTasksCard.vue +2 -1
- package/src/components/CnTimelineWidget/CnTimelineWidget.vue +2 -1
- package/src/components/CnTranslatedBadge/CnTranslatedBadge.vue +2 -1
- package/src/components/CnVersionHistory/CnVersionHistory.vue +2 -1
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +3 -26
- package/src/css/board.css +40 -0
- package/src/dialogs/CnNoteHistoryDialog.vue +2 -1
- package/src/integrations/builtin/activity/CnActivityCard.vue +3 -2
- package/src/integrations/builtin/activity/CnActivityTab.vue +4 -3
- package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +3 -2
- package/src/integrations/builtin/calendar/CnCalendarCard.vue +2 -1
- package/src/integrations/builtin/calendar/CnCalendarTab.vue +6 -5
- package/src/integrations/builtin/contactmoment/CnContactmomentCard.vue +2 -1
- package/src/integrations/builtin/cospend/CnCospendTab.vue +2 -1
- package/src/integrations/builtin/deck/CnDeckTab.vue +2 -1
- package/src/integrations/builtin/email/CnEmailCard.vue +2 -1
- package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +2 -1
- package/src/integrations/builtin/field-inspection/CnFieldInspectionTab.vue +2 -1
- package/src/integrations/builtin/photos/CnPhotosTab.vue +2 -1
- package/src/schemas/app-manifest-v2.schema.json +4 -1
- package/src/store/useObjectStore.js +7 -2
- package/src/utils/boardColumns.js +49 -0
- package/src/utils/boardReferenceColumns.js +114 -3
- package/src/utils/contentHeaderLink.js +47 -0
- package/src/utils/schema.js +5 -4
- package/src/utils/userLocale.js +26 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnTimelineWidget.vue2.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineWidget.vue"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<section class=\"cn-timeline-widget\" data-testid=\"cn-timeline-widget\" :aria-busy=\"loading ? 'true' : 'false'\">\n\t\t<h3 v-if=\"resolvedTitle\" class=\"cn-timeline-widget__title\">\n\t\t\t{{ resolvedTitle }}\n\t\t</h3>\n\n\t\t<div v-if=\"loading && events.length === 0\" class=\"cn-timeline-widget__loading\">\n\t\t\t<NcLoadingIcon :size=\"24\" aria-hidden=\"true\" />\n\t\t\t<span>{{ loadingLabel }}</span>\n\t\t</div>\n\n\t\t<template v-else>\n\t\t\t<!-- A failed read is not an empty history: say which part is missing. -->\n\t\t\t<NcNoteCard v-if=\"failedSources.length > 0\" type=\"warning\" data-testid=\"cn-timeline-widget-error\">\n\t\t\t\t{{ failedText }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"events.length === 0\" class=\"cn-timeline-widget__empty\" data-testid=\"cn-timeline-widget-empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\n\t\t\t<ol v-else class=\"cn-timeline-widget__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"event in events\"\n\t\t\t\t\t:key=\"event.id\"\n\t\t\t\t\tclass=\"cn-timeline-widget__event\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-widget__event--upcoming': event.upcoming }\"\n\t\t\t\t\t:data-source=\"event.source\"\n\t\t\t\t\tdata-testid=\"cn-timeline-widget-event\">\n\t\t\t\t\t<span class=\"cn-timeline-widget__dot\" aria-hidden=\"true\" />\n\t\t\t\t\t<div class=\"cn-timeline-widget__body\">\n\t\t\t\t\t\t<time class=\"cn-timeline-widget__when\" :datetime=\"event.at.toISOString()\">\n\t\t\t\t\t\t\t{{ formatMoment(event) }}\n\t\t\t\t\t\t</time>\n\t\t\t\t\t\t<span v-if=\"event.upcoming\" class=\"cn-timeline-widget__badge\">\n\t\t\t\t\t\t\t{{ upcomingLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<p class=\"cn-timeline-widget__label\">\n\t\t\t\t\t\t\t{{ translate(event.label) }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"event.detail\" class=\"cn-timeline-widget__detail\">\n\t\t\t\t\t\t\t{{ event.detail }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</template>\n\t</section>\n</template>\n\n<script>\nimport { getLanguage, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { auditEvents, fieldEvents, listEvents, relatedEvents, sortEvents, timelineEntryEvents } from '../../utils/timelineEvents.js'\n\n/**\n * CnTimelineWidget — an object's dated events in time order (`timeline`\n * widget type for detail pages).\n *\n * Generalises dossiq's case timeline. It merges up to four sources, all\n * optional, into one list:\n *\n * - `fields`: the object's own date properties, `[{ field, label }]`. A\n * dotted path reaches metadata, such as `@self.created`.\n * - `related`: related objects, `[{ register?, schema, field, dateField?,\n * label, titleField? }]`. Rows of `schema` whose `field` holds this object's\n * id become events at their `dateField` (default `@self.created`).\n * - `auditTrail: true`: the object's audit trail, one event per change.\n * - `timeline: true`: OpenRegister's timeline of notes, calls and messages.\n *\n * Oldest first by default (`order: 'desc'` flips it). A moment after now is\n * marked upcoming, in words as well as style.\n *\n * ```json\n * { \"type\": \"timeline\", \"content\": {\n * \"title\": \"Timeline\",\n * \"fields\": [\n * { \"field\": \"@self.created\", \"label\": \"Booking created\" },\n * { \"field\": \"depositClearedAt\", \"label\": \"Deposit cleared\" },\n * { \"field\": \"confirmationSentAt\", \"label\": \"Confirmation mail sent\" },\n * { \"field\": \"startsAt\", \"label\": \"Starts\" },\n * { \"field\": \"endsAt\", \"label\": \"Ends\" }\n * ] } }\n * ```\n *\n * The object comes from the detail page's context, like `audit-trail`:\n * explicit props win, then the injects, then `content`.\n *\n * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n */\nexport default {\n\tname: 'CnTimelineWidget',\n\n\tcomponents: {\n\t\tNcLoadingIcon,\n\t\tNcNoteCard,\n\t},\n\n\tinject: {\n\t\t/** Detail-page object context from CnDetailPage (a ref or a raw bag). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Detail object context holder from CnPageRenderer (`{ value: { objectData, ... } }`). */\n\t\tcnDetailObjectContext: { default: null },\n\t\t/** Consumer translation function; labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Register slug; object context spread as props by CnWidgetGrid. */\n\t\tregister: { type: String, default: '' },\n\t\t/**\n\t\t * Schema slug, or the schema object the detail context supplies.\n\t\t *\n\t\t * @type {string|object}\n\t\t */\n\t\tschema: { type: [String, Object], default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** The object itself, when the host already has it. */\n\t\tobject: { type: Object, default: null },\n\t\t/** Card title override. */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Stored widget content: `{ title, fields, related, auditTrail, timeline, order }`. */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: false,\n\t\t\trelatedRows: {},\n\t\t\tauditEntries: [],\n\t\t\ttimelineEntries: [],\n\t\t\tfailedSources: [],\n\t\t\tfetchedObject: null,\n\t\t\tloadSeq: 0,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tctx() {\n\t\t\tconst raw = this.cnObjectContext\n\t\t\tconst inj = raw && (raw.value !== undefined ? raw.value : raw)\n\t\t\tconst holder = this.cnDetailObjectContext && this.cnDetailObjectContext.value\n\t\t\treturn inj || holder || {}\n\t\t},\n\n\t\tresolvedObjectId() {\n\t\t\treturn this.objectId || this.ctx.objectId || this.content.objectId || ''\n\t\t},\n\n\t\tresolvedRegister() {\n\t\t\treturn this.register || this.ctx.register || this.content.register || ''\n\t\t},\n\n\t\tresolvedSchema() {\n\t\t\tconst s = this.schema || this.ctx.schema || this.content.schema || ''\n\t\t\treturn typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''\n\t\t},\n\n\t\t/**\n\t\t * The object: explicit prop, then the page context, then a fetch of\n\t\t * our own when only the id is known.\n\t\t *\n\t\t * @return {object|null}\n\t\t */\n\t\tresolvedObject() {\n\t\t\treturn this.object || this.ctx.object || this.ctx.objectData || this.fetchedObject || null\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\tconst raw = this.title || this.content.title || ''\n\t\t\treturn raw ? this.translate(raw) : ''\n\t\t},\n\n\t\tfieldsConfig() {\n\t\t\treturn Array.isArray(this.content.fields) ? this.content.fields : []\n\t\t},\n\n\t\trelatedConfig() {\n\t\t\treturn Array.isArray(this.content.related) ? this.content.related.filter((r) => r && r.schema && r.field) : []\n\t\t},\n\n\t\t/**\n\t\t * Every event from every source, in time order.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tevents() {\n\t\t\tconst now = new Date()\n\t\t\tconst all = [\n\t\t\t\t...fieldEvents(this.resolvedObject || {}, this.fieldsConfig, now),\n\t\t\t\t...listEvents(this.resolvedObject || {}, this.content.lists, now),\n\t\t\t\t...this.relatedConfig.flatMap((cfg, i) => relatedEvents(this.relatedRows[i] || [], cfg, now)),\n\t\t\t\t...auditEvents(this.auditEntries, this.describeAudit, now),\n\t\t\t\t...timelineEntryEvents(this.timelineEntries, t('nextcloud-vue', 'Note'), now),\n\t\t\t]\n\t\t\treturn sortEvents(all, this.content.order === 'desc' ? 'desc' : 'asc')\n\t\t},\n\n\t\t/**\n\t\t * A signature of what to fetch, so a change refetches once.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tloadKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\tid: this.resolvedObjectId,\n\t\t\t\tregister: this.resolvedRegister,\n\t\t\t\tschema: this.resolvedSchema,\n\t\t\t\trelated: this.relatedConfig,\n\t\t\t\taudit: this.content.auditTrail === true,\n\t\t\t\ttimeline: this.content.timeline === true,\n\t\t\t\tneedObject: this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData),\n\t\t\t})\n\t\t},\n\n\t\tfailedText() {\n\t\t\treturn t('nextcloud-vue', 'Part of the timeline could not load: {parts}.', {\n\t\t\t\tparts: this.failedSources.map((s) => this.sourceName(s)).join(', '),\n\t\t\t})\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing has happened yet.')\n\t\t},\n\n\t\tupcomingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Upcoming')\n\t\t},\n\t},\n\n\twatch: {\n\t\tloadKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\tsourceName(source) {\n\t\t\tif (source === 'audit') {\n\t\t\t\treturn t('nextcloud-vue', 'changes')\n\t\t\t}\n\t\t\tif (source === 'timeline') {\n\t\t\t\treturn t('nextcloud-vue', 'notes and messages')\n\t\t\t}\n\t\t\tif (source === 'object') {\n\t\t\t\treturn t('nextcloud-vue', 'dates')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'related items')\n\t\t},\n\n\t\t/**\n\t\t * The label of an audit event, from its action and who did it.\n\t\t *\n\t\t * @param {string} action The audit action (create, update, delete).\n\t\t * @param {string} actor Who did it.\n\t\t * @return {string}\n\t\t */\n\t\tdescribeAudit(action, actor) {\n\t\t\tconst known = {\n\t\t\t\tcreate: t('nextcloud-vue', 'Created'),\n\t\t\t\tupdate: t('nextcloud-vue', 'Updated'),\n\t\t\t\tdelete: t('nextcloud-vue', 'Deleted'),\n\t\t\t}\n\t\t\tconst what = known[action] || action || t('nextcloud-vue', 'Changed')\n\t\t\treturn actor ? t('nextcloud-vue', '{action} by {actor}', { action: what, actor }) : what\n\t\t},\n\n\t\t/**\n\t\t * Show a moment in the reader's language: a date for a calendar day,\n\t\t * date and time otherwise.\n\t\t *\n\t\t * @param {object} event The event.\n\t\t * @return {string}\n\t\t */\n\t\tformatMoment(event) {\n\t\t\tconst locale = (typeof getLanguage === 'function' && getLanguage()) || undefined\n\t\t\tconst options = event.dateOnly\n\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale, options).format(event.at)\n\t\t\t} catch {\n\t\t\t\treturn event.at.toLocaleString()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch every configured source. Each one fails on its own, so one\n\t\t * unreachable source never hides the others.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n\t\t */\n\t\tasync load() {\n\t\t\tconst id = this.resolvedObjectId\n\t\t\tconst register = this.resolvedRegister\n\t\t\tconst schema = this.resolvedSchema\n\t\t\tconst seq = ++this.loadSeq\n\t\t\tif (!id || !register || !schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\timport('@nextcloud/router'),\n\t\t\t])\n\t\t\tconst base = `${this.apiBase}/objects/${register}/${schema}/${id}`\n\t\t\tconst failed = []\n\t\t\tconst jobs = []\n\n\t\t\tif (this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData)) {\n\t\t\t\tjobs.push(axios.get(generateUrl(base))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tthis.fetchedObject = (r && r.data) || null\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => failed.push('object')))\n\t\t\t}\n\n\t\t\tconst rows = {}\n\t\t\tthis.relatedConfig.forEach((cfg, i) => {\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${cfg.register || register}/${cfg.schema}`)\n\t\t\t\tjobs.push(axios.get(url, { params: { [cfg.field]: id, _limit: cfg.limit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\trows[i] = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\trows[i] = []\n\t\t\t\t\t\tif (!failed.includes('related')) {\n\t\t\t\t\t\t\tfailed.push('related')\n\t\t\t\t\t\t}\n\t\t\t\t\t}))\n\t\t\t})\n\n\t\t\tif (this.content.auditTrail === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/audit-trails`), { params: { limit: this.content.auditLimit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.auditEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.auditEntries = []\n\t\t\t\t\t\tfailed.push('audit')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (this.content.timeline === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/timeline`))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.timelineEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.timelineEntries = []\n\t\t\t\t\t\tfailed.push('timeline')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (jobs.length === 0) {\n\t\t\t\tthis.failedSources = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tawait Promise.all(jobs)\n\t\t\tif (seq !== this.loadSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.relatedRows = rows\n\t\t\tthis.failedSources = failed\n\t\t\tthis.loading = false\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-timeline-widget__title {\n\tmargin: 0;\n\tfont-size: var(--font-size-large, 1.1em);\n}\n\n.cn-timeline-widget__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__list {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-timeline-widget__event {\n\tposition: relative;\n\tdisplay: flex;\n\tgap: 12px;\n\tpadding-block-end: 12px;\n}\n\n/* The line between dots: drawn from each dot down to the next event. */\n.cn-timeline-widget__event:not(:last-child)::before {\n\tcontent: '';\n\tposition: absolute;\n\tinset-block: 14px 0;\n\tinset-inline-start: 5px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n}\n\n.cn-timeline-widget__dot {\n\tflex: 0 0 auto;\n\twidth: 12px;\n\theight: 12px;\n\tmargin-block-start: 4px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-primary-element);\n}\n\n/* Upcoming: a hollow dot, plus the word \"Upcoming\" beside the date. */\n.cn-timeline-widget__event--upcoming .cn-timeline-widget__dot {\n\tbox-sizing: border-box;\n\tborder: 2px solid var(--color-primary-element);\n\tbackground-color: var(--color-main-background);\n}\n\n.cn-timeline-widget__body {\n\tmin-width: 0;\n}\n\n.cn-timeline-widget__when {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__badge {\n\tmargin-inline-start: 8px;\n\tfont-size: var(--font-size-small, 13px);\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-widget__label {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-timeline-widget__detail {\n\tmargin: 0;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnTimelineWidget.vue2.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineWidget.vue"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<section class=\"cn-timeline-widget\" data-testid=\"cn-timeline-widget\" :aria-busy=\"loading ? 'true' : 'false'\">\n\t\t<h3 v-if=\"resolvedTitle\" class=\"cn-timeline-widget__title\">\n\t\t\t{{ resolvedTitle }}\n\t\t</h3>\n\n\t\t<div v-if=\"loading && events.length === 0\" class=\"cn-timeline-widget__loading\">\n\t\t\t<NcLoadingIcon :size=\"24\" aria-hidden=\"true\" />\n\t\t\t<span>{{ loadingLabel }}</span>\n\t\t</div>\n\n\t\t<template v-else>\n\t\t\t<!-- A failed read is not an empty history: say which part is missing. -->\n\t\t\t<NcNoteCard v-if=\"failedSources.length > 0\" type=\"warning\" data-testid=\"cn-timeline-widget-error\">\n\t\t\t\t{{ failedText }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"events.length === 0\" class=\"cn-timeline-widget__empty\" data-testid=\"cn-timeline-widget-empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\n\t\t\t<ol v-else class=\"cn-timeline-widget__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"event in events\"\n\t\t\t\t\t:key=\"event.id\"\n\t\t\t\t\tclass=\"cn-timeline-widget__event\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-widget__event--upcoming': event.upcoming }\"\n\t\t\t\t\t:data-source=\"event.source\"\n\t\t\t\t\tdata-testid=\"cn-timeline-widget-event\">\n\t\t\t\t\t<span class=\"cn-timeline-widget__dot\" aria-hidden=\"true\" />\n\t\t\t\t\t<div class=\"cn-timeline-widget__body\">\n\t\t\t\t\t\t<time class=\"cn-timeline-widget__when\" :datetime=\"event.at.toISOString()\">\n\t\t\t\t\t\t\t{{ formatMoment(event) }}\n\t\t\t\t\t\t</time>\n\t\t\t\t\t\t<span v-if=\"event.upcoming\" class=\"cn-timeline-widget__badge\">\n\t\t\t\t\t\t\t{{ upcomingLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<p class=\"cn-timeline-widget__label\">\n\t\t\t\t\t\t\t{{ translate(event.label) }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"event.detail\" class=\"cn-timeline-widget__detail\">\n\t\t\t\t\t\t\t{{ event.detail }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</template>\n\t</section>\n</template>\n\n<script>\nimport { getLanguage, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { auditEvents, fieldEvents, listEvents, relatedEvents, sortEvents, timelineEntryEvents } from '../../utils/timelineEvents.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnTimelineWidget — an object's dated events in time order (`timeline`\n * widget type for detail pages).\n *\n * Generalises dossiq's case timeline. It merges up to four sources, all\n * optional, into one list:\n *\n * - `fields`: the object's own date properties, `[{ field, label }]`. A\n * dotted path reaches metadata, such as `@self.created`.\n * - `related`: related objects, `[{ register?, schema, field, dateField?,\n * label, titleField? }]`. Rows of `schema` whose `field` holds this object's\n * id become events at their `dateField` (default `@self.created`).\n * - `auditTrail: true`: the object's audit trail, one event per change.\n * - `timeline: true`: OpenRegister's timeline of notes, calls and messages.\n *\n * Oldest first by default (`order: 'desc'` flips it). A moment after now is\n * marked upcoming, in words as well as style.\n *\n * ```json\n * { \"type\": \"timeline\", \"content\": {\n * \"title\": \"Timeline\",\n * \"fields\": [\n * { \"field\": \"@self.created\", \"label\": \"Booking created\" },\n * { \"field\": \"depositClearedAt\", \"label\": \"Deposit cleared\" },\n * { \"field\": \"confirmationSentAt\", \"label\": \"Confirmation mail sent\" },\n * { \"field\": \"startsAt\", \"label\": \"Starts\" },\n * { \"field\": \"endsAt\", \"label\": \"Ends\" }\n * ] } }\n * ```\n *\n * The object comes from the detail page's context, like `audit-trail`:\n * explicit props win, then the injects, then `content`.\n *\n * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n */\nexport default {\n\tname: 'CnTimelineWidget',\n\n\tcomponents: {\n\t\tNcLoadingIcon,\n\t\tNcNoteCard,\n\t},\n\n\tinject: {\n\t\t/** Detail-page object context from CnDetailPage (a ref or a raw bag). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Detail object context holder from CnPageRenderer (`{ value: { objectData, ... } }`). */\n\t\tcnDetailObjectContext: { default: null },\n\t\t/** Consumer translation function; labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Register slug; object context spread as props by CnWidgetGrid. */\n\t\tregister: { type: String, default: '' },\n\t\t/**\n\t\t * Schema slug, or the schema object the detail context supplies.\n\t\t *\n\t\t * @type {string|object}\n\t\t */\n\t\tschema: { type: [String, Object], default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** The object itself, when the host already has it. */\n\t\tobject: { type: Object, default: null },\n\t\t/** Card title override. */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Stored widget content: `{ title, fields, related, auditTrail, timeline, order }`. */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: false,\n\t\t\trelatedRows: {},\n\t\t\tauditEntries: [],\n\t\t\ttimelineEntries: [],\n\t\t\tfailedSources: [],\n\t\t\tfetchedObject: null,\n\t\t\tloadSeq: 0,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tctx() {\n\t\t\tconst raw = this.cnObjectContext\n\t\t\tconst inj = raw && (raw.value !== undefined ? raw.value : raw)\n\t\t\tconst holder = this.cnDetailObjectContext && this.cnDetailObjectContext.value\n\t\t\treturn inj || holder || {}\n\t\t},\n\n\t\tresolvedObjectId() {\n\t\t\treturn this.objectId || this.ctx.objectId || this.content.objectId || ''\n\t\t},\n\n\t\tresolvedRegister() {\n\t\t\treturn this.register || this.ctx.register || this.content.register || ''\n\t\t},\n\n\t\tresolvedSchema() {\n\t\t\tconst s = this.schema || this.ctx.schema || this.content.schema || ''\n\t\t\treturn typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''\n\t\t},\n\n\t\t/**\n\t\t * The object: explicit prop, then the page context, then a fetch of\n\t\t * our own when only the id is known.\n\t\t *\n\t\t * @return {object|null}\n\t\t */\n\t\tresolvedObject() {\n\t\t\treturn this.object || this.ctx.object || this.ctx.objectData || this.fetchedObject || null\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\tconst raw = this.title || this.content.title || ''\n\t\t\treturn raw ? this.translate(raw) : ''\n\t\t},\n\n\t\tfieldsConfig() {\n\t\t\treturn Array.isArray(this.content.fields) ? this.content.fields : []\n\t\t},\n\n\t\trelatedConfig() {\n\t\t\treturn Array.isArray(this.content.related) ? this.content.related.filter((r) => r && r.schema && r.field) : []\n\t\t},\n\n\t\t/**\n\t\t * Every event from every source, in time order.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tevents() {\n\t\t\tconst now = new Date()\n\t\t\tconst all = [\n\t\t\t\t...fieldEvents(this.resolvedObject || {}, this.fieldsConfig, now),\n\t\t\t\t...listEvents(this.resolvedObject || {}, this.content.lists, now),\n\t\t\t\t...this.relatedConfig.flatMap((cfg, i) => relatedEvents(this.relatedRows[i] || [], cfg, now)),\n\t\t\t\t...auditEvents(this.auditEntries, this.describeAudit, now),\n\t\t\t\t...timelineEntryEvents(this.timelineEntries, t('nextcloud-vue', 'Note'), now),\n\t\t\t]\n\t\t\treturn sortEvents(all, this.content.order === 'desc' ? 'desc' : 'asc')\n\t\t},\n\n\t\t/**\n\t\t * A signature of what to fetch, so a change refetches once.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tloadKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\tid: this.resolvedObjectId,\n\t\t\t\tregister: this.resolvedRegister,\n\t\t\t\tschema: this.resolvedSchema,\n\t\t\t\trelated: this.relatedConfig,\n\t\t\t\taudit: this.content.auditTrail === true,\n\t\t\t\ttimeline: this.content.timeline === true,\n\t\t\t\tneedObject: this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData),\n\t\t\t})\n\t\t},\n\n\t\tfailedText() {\n\t\t\treturn t('nextcloud-vue', 'Part of the timeline could not load: {parts}.', {\n\t\t\t\tparts: this.failedSources.map((s) => this.sourceName(s)).join(', '),\n\t\t\t})\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing has happened yet.')\n\t\t},\n\n\t\tupcomingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Upcoming')\n\t\t},\n\t},\n\n\twatch: {\n\t\tloadKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\tsourceName(source) {\n\t\t\tif (source === 'audit') {\n\t\t\t\treturn t('nextcloud-vue', 'changes')\n\t\t\t}\n\t\t\tif (source === 'timeline') {\n\t\t\t\treturn t('nextcloud-vue', 'notes and messages')\n\t\t\t}\n\t\t\tif (source === 'object') {\n\t\t\t\treturn t('nextcloud-vue', 'dates')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'related items')\n\t\t},\n\n\t\t/**\n\t\t * The label of an audit event, from its action and who did it.\n\t\t *\n\t\t * @param {string} action The audit action (create, update, delete).\n\t\t * @param {string} actor Who did it.\n\t\t * @return {string}\n\t\t */\n\t\tdescribeAudit(action, actor) {\n\t\t\tconst known = {\n\t\t\t\tcreate: t('nextcloud-vue', 'Created'),\n\t\t\t\tupdate: t('nextcloud-vue', 'Updated'),\n\t\t\t\tdelete: t('nextcloud-vue', 'Deleted'),\n\t\t\t}\n\t\t\tconst what = known[action] || action || t('nextcloud-vue', 'Changed')\n\t\t\treturn actor ? t('nextcloud-vue', '{action} by {actor}', { action: what, actor }) : what\n\t\t},\n\n\t\t/**\n\t\t * Show a moment in the reader's language: a date for a calendar day,\n\t\t * date and time otherwise.\n\t\t *\n\t\t * @param {object} event The event.\n\t\t * @return {string}\n\t\t */\n\t\tformatMoment(event) {\n\t\t\tconst locale = (typeof getLanguage === 'function' && getLanguage()) || undefined\n\t\t\tconst options = event.dateOnly\n\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale, options).format(event.at)\n\t\t\t} catch {\n\t\t\t\treturn event.at.toLocaleString(userLocale())\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch every configured source. Each one fails on its own, so one\n\t\t * unreachable source never hides the others.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n\t\t */\n\t\tasync load() {\n\t\t\tconst id = this.resolvedObjectId\n\t\t\tconst register = this.resolvedRegister\n\t\t\tconst schema = this.resolvedSchema\n\t\t\tconst seq = ++this.loadSeq\n\t\t\tif (!id || !register || !schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\timport('@nextcloud/router'),\n\t\t\t])\n\t\t\tconst base = `${this.apiBase}/objects/${register}/${schema}/${id}`\n\t\t\tconst failed = []\n\t\t\tconst jobs = []\n\n\t\t\tif (this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData)) {\n\t\t\t\tjobs.push(axios.get(generateUrl(base))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tthis.fetchedObject = (r && r.data) || null\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => failed.push('object')))\n\t\t\t}\n\n\t\t\tconst rows = {}\n\t\t\tthis.relatedConfig.forEach((cfg, i) => {\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${cfg.register || register}/${cfg.schema}`)\n\t\t\t\tjobs.push(axios.get(url, { params: { [cfg.field]: id, _limit: cfg.limit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\trows[i] = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\trows[i] = []\n\t\t\t\t\t\tif (!failed.includes('related')) {\n\t\t\t\t\t\t\tfailed.push('related')\n\t\t\t\t\t\t}\n\t\t\t\t\t}))\n\t\t\t})\n\n\t\t\tif (this.content.auditTrail === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/audit-trails`), { params: { limit: this.content.auditLimit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.auditEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.auditEntries = []\n\t\t\t\t\t\tfailed.push('audit')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (this.content.timeline === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/timeline`))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.timelineEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.timelineEntries = []\n\t\t\t\t\t\tfailed.push('timeline')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (jobs.length === 0) {\n\t\t\t\tthis.failedSources = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tawait Promise.all(jobs)\n\t\t\tif (seq !== this.loadSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.relatedRows = rows\n\t\t\tthis.failedSources = failed\n\t\t\tthis.loading = false\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-timeline-widget__title {\n\tmargin: 0;\n\tfont-size: var(--font-size-large, 1.1em);\n}\n\n.cn-timeline-widget__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__list {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-timeline-widget__event {\n\tposition: relative;\n\tdisplay: flex;\n\tgap: 12px;\n\tpadding-block-end: 12px;\n}\n\n/* The line between dots: drawn from each dot down to the next event. */\n.cn-timeline-widget__event:not(:last-child)::before {\n\tcontent: '';\n\tposition: absolute;\n\tinset-block: 14px 0;\n\tinset-inline-start: 5px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n}\n\n.cn-timeline-widget__dot {\n\tflex: 0 0 auto;\n\twidth: 12px;\n\theight: 12px;\n\tmargin-block-start: 4px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-primary-element);\n}\n\n/* Upcoming: a hollow dot, plus the word \"Upcoming\" beside the date. */\n.cn-timeline-widget__event--upcoming .cn-timeline-widget__dot {\n\tbox-sizing: border-box;\n\tborder: 2px solid var(--color-primary-element);\n\tbackground-color: var(--color-main-background);\n}\n\n.cn-timeline-widget__body {\n\tmin-width: 0;\n}\n\n.cn-timeline-widget__when {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__badge {\n\tmargin-inline-start: 8px;\n\tfont-size: var(--font-size-small, 13px);\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-widget__label {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-timeline-widget__detail {\n\tmargin: 0;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["t"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnTimelineWidget.vue3.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineWidget.vue?vue&type=template&id=60089a65&lang.js"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<section class=\"cn-timeline-widget\" data-testid=\"cn-timeline-widget\" :aria-busy=\"loading ? 'true' : 'false'\">\n\t\t<h3 v-if=\"resolvedTitle\" class=\"cn-timeline-widget__title\">\n\t\t\t{{ resolvedTitle }}\n\t\t</h3>\n\n\t\t<div v-if=\"loading && events.length === 0\" class=\"cn-timeline-widget__loading\">\n\t\t\t<NcLoadingIcon :size=\"24\" aria-hidden=\"true\" />\n\t\t\t<span>{{ loadingLabel }}</span>\n\t\t</div>\n\n\t\t<template v-else>\n\t\t\t<!-- A failed read is not an empty history: say which part is missing. -->\n\t\t\t<NcNoteCard v-if=\"failedSources.length > 0\" type=\"warning\" data-testid=\"cn-timeline-widget-error\">\n\t\t\t\t{{ failedText }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"events.length === 0\" class=\"cn-timeline-widget__empty\" data-testid=\"cn-timeline-widget-empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\n\t\t\t<ol v-else class=\"cn-timeline-widget__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"event in events\"\n\t\t\t\t\t:key=\"event.id\"\n\t\t\t\t\tclass=\"cn-timeline-widget__event\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-widget__event--upcoming': event.upcoming }\"\n\t\t\t\t\t:data-source=\"event.source\"\n\t\t\t\t\tdata-testid=\"cn-timeline-widget-event\">\n\t\t\t\t\t<span class=\"cn-timeline-widget__dot\" aria-hidden=\"true\" />\n\t\t\t\t\t<div class=\"cn-timeline-widget__body\">\n\t\t\t\t\t\t<time class=\"cn-timeline-widget__when\" :datetime=\"event.at.toISOString()\">\n\t\t\t\t\t\t\t{{ formatMoment(event) }}\n\t\t\t\t\t\t</time>\n\t\t\t\t\t\t<span v-if=\"event.upcoming\" class=\"cn-timeline-widget__badge\">\n\t\t\t\t\t\t\t{{ upcomingLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<p class=\"cn-timeline-widget__label\">\n\t\t\t\t\t\t\t{{ translate(event.label) }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"event.detail\" class=\"cn-timeline-widget__detail\">\n\t\t\t\t\t\t\t{{ event.detail }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</template>\n\t</section>\n</template>\n\n<script>\nimport { getLanguage, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { auditEvents, fieldEvents, listEvents, relatedEvents, sortEvents, timelineEntryEvents } from '../../utils/timelineEvents.js'\n\n/**\n * CnTimelineWidget — an object's dated events in time order (`timeline`\n * widget type for detail pages).\n *\n * Generalises dossiq's case timeline. It merges up to four sources, all\n * optional, into one list:\n *\n * - `fields`: the object's own date properties, `[{ field, label }]`. A\n * dotted path reaches metadata, such as `@self.created`.\n * - `related`: related objects, `[{ register?, schema, field, dateField?,\n * label, titleField? }]`. Rows of `schema` whose `field` holds this object's\n * id become events at their `dateField` (default `@self.created`).\n * - `auditTrail: true`: the object's audit trail, one event per change.\n * - `timeline: true`: OpenRegister's timeline of notes, calls and messages.\n *\n * Oldest first by default (`order: 'desc'` flips it). A moment after now is\n * marked upcoming, in words as well as style.\n *\n * ```json\n * { \"type\": \"timeline\", \"content\": {\n * \"title\": \"Timeline\",\n * \"fields\": [\n * { \"field\": \"@self.created\", \"label\": \"Booking created\" },\n * { \"field\": \"depositClearedAt\", \"label\": \"Deposit cleared\" },\n * { \"field\": \"confirmationSentAt\", \"label\": \"Confirmation mail sent\" },\n * { \"field\": \"startsAt\", \"label\": \"Starts\" },\n * { \"field\": \"endsAt\", \"label\": \"Ends\" }\n * ] } }\n * ```\n *\n * The object comes from the detail page's context, like `audit-trail`:\n * explicit props win, then the injects, then `content`.\n *\n * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n */\nexport default {\n\tname: 'CnTimelineWidget',\n\n\tcomponents: {\n\t\tNcLoadingIcon,\n\t\tNcNoteCard,\n\t},\n\n\tinject: {\n\t\t/** Detail-page object context from CnDetailPage (a ref or a raw bag). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Detail object context holder from CnPageRenderer (`{ value: { objectData, ... } }`). */\n\t\tcnDetailObjectContext: { default: null },\n\t\t/** Consumer translation function; labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Register slug; object context spread as props by CnWidgetGrid. */\n\t\tregister: { type: String, default: '' },\n\t\t/**\n\t\t * Schema slug, or the schema object the detail context supplies.\n\t\t *\n\t\t * @type {string|object}\n\t\t */\n\t\tschema: { type: [String, Object], default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** The object itself, when the host already has it. */\n\t\tobject: { type: Object, default: null },\n\t\t/** Card title override. */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Stored widget content: `{ title, fields, related, auditTrail, timeline, order }`. */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: false,\n\t\t\trelatedRows: {},\n\t\t\tauditEntries: [],\n\t\t\ttimelineEntries: [],\n\t\t\tfailedSources: [],\n\t\t\tfetchedObject: null,\n\t\t\tloadSeq: 0,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tctx() {\n\t\t\tconst raw = this.cnObjectContext\n\t\t\tconst inj = raw && (raw.value !== undefined ? raw.value : raw)\n\t\t\tconst holder = this.cnDetailObjectContext && this.cnDetailObjectContext.value\n\t\t\treturn inj || holder || {}\n\t\t},\n\n\t\tresolvedObjectId() {\n\t\t\treturn this.objectId || this.ctx.objectId || this.content.objectId || ''\n\t\t},\n\n\t\tresolvedRegister() {\n\t\t\treturn this.register || this.ctx.register || this.content.register || ''\n\t\t},\n\n\t\tresolvedSchema() {\n\t\t\tconst s = this.schema || this.ctx.schema || this.content.schema || ''\n\t\t\treturn typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''\n\t\t},\n\n\t\t/**\n\t\t * The object: explicit prop, then the page context, then a fetch of\n\t\t * our own when only the id is known.\n\t\t *\n\t\t * @return {object|null}\n\t\t */\n\t\tresolvedObject() {\n\t\t\treturn this.object || this.ctx.object || this.ctx.objectData || this.fetchedObject || null\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\tconst raw = this.title || this.content.title || ''\n\t\t\treturn raw ? this.translate(raw) : ''\n\t\t},\n\n\t\tfieldsConfig() {\n\t\t\treturn Array.isArray(this.content.fields) ? this.content.fields : []\n\t\t},\n\n\t\trelatedConfig() {\n\t\t\treturn Array.isArray(this.content.related) ? this.content.related.filter((r) => r && r.schema && r.field) : []\n\t\t},\n\n\t\t/**\n\t\t * Every event from every source, in time order.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tevents() {\n\t\t\tconst now = new Date()\n\t\t\tconst all = [\n\t\t\t\t...fieldEvents(this.resolvedObject || {}, this.fieldsConfig, now),\n\t\t\t\t...listEvents(this.resolvedObject || {}, this.content.lists, now),\n\t\t\t\t...this.relatedConfig.flatMap((cfg, i) => relatedEvents(this.relatedRows[i] || [], cfg, now)),\n\t\t\t\t...auditEvents(this.auditEntries, this.describeAudit, now),\n\t\t\t\t...timelineEntryEvents(this.timelineEntries, t('nextcloud-vue', 'Note'), now),\n\t\t\t]\n\t\t\treturn sortEvents(all, this.content.order === 'desc' ? 'desc' : 'asc')\n\t\t},\n\n\t\t/**\n\t\t * A signature of what to fetch, so a change refetches once.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tloadKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\tid: this.resolvedObjectId,\n\t\t\t\tregister: this.resolvedRegister,\n\t\t\t\tschema: this.resolvedSchema,\n\t\t\t\trelated: this.relatedConfig,\n\t\t\t\taudit: this.content.auditTrail === true,\n\t\t\t\ttimeline: this.content.timeline === true,\n\t\t\t\tneedObject: this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData),\n\t\t\t})\n\t\t},\n\n\t\tfailedText() {\n\t\t\treturn t('nextcloud-vue', 'Part of the timeline could not load: {parts}.', {\n\t\t\t\tparts: this.failedSources.map((s) => this.sourceName(s)).join(', '),\n\t\t\t})\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing has happened yet.')\n\t\t},\n\n\t\tupcomingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Upcoming')\n\t\t},\n\t},\n\n\twatch: {\n\t\tloadKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\tsourceName(source) {\n\t\t\tif (source === 'audit') {\n\t\t\t\treturn t('nextcloud-vue', 'changes')\n\t\t\t}\n\t\t\tif (source === 'timeline') {\n\t\t\t\treturn t('nextcloud-vue', 'notes and messages')\n\t\t\t}\n\t\t\tif (source === 'object') {\n\t\t\t\treturn t('nextcloud-vue', 'dates')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'related items')\n\t\t},\n\n\t\t/**\n\t\t * The label of an audit event, from its action and who did it.\n\t\t *\n\t\t * @param {string} action The audit action (create, update, delete).\n\t\t * @param {string} actor Who did it.\n\t\t * @return {string}\n\t\t */\n\t\tdescribeAudit(action, actor) {\n\t\t\tconst known = {\n\t\t\t\tcreate: t('nextcloud-vue', 'Created'),\n\t\t\t\tupdate: t('nextcloud-vue', 'Updated'),\n\t\t\t\tdelete: t('nextcloud-vue', 'Deleted'),\n\t\t\t}\n\t\t\tconst what = known[action] || action || t('nextcloud-vue', 'Changed')\n\t\t\treturn actor ? t('nextcloud-vue', '{action} by {actor}', { action: what, actor }) : what\n\t\t},\n\n\t\t/**\n\t\t * Show a moment in the reader's language: a date for a calendar day,\n\t\t * date and time otherwise.\n\t\t *\n\t\t * @param {object} event The event.\n\t\t * @return {string}\n\t\t */\n\t\tformatMoment(event) {\n\t\t\tconst locale = (typeof getLanguage === 'function' && getLanguage()) || undefined\n\t\t\tconst options = event.dateOnly\n\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale, options).format(event.at)\n\t\t\t} catch {\n\t\t\t\treturn event.at.toLocaleString()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch every configured source. Each one fails on its own, so one\n\t\t * unreachable source never hides the others.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n\t\t */\n\t\tasync load() {\n\t\t\tconst id = this.resolvedObjectId\n\t\t\tconst register = this.resolvedRegister\n\t\t\tconst schema = this.resolvedSchema\n\t\t\tconst seq = ++this.loadSeq\n\t\t\tif (!id || !register || !schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\timport('@nextcloud/router'),\n\t\t\t])\n\t\t\tconst base = `${this.apiBase}/objects/${register}/${schema}/${id}`\n\t\t\tconst failed = []\n\t\t\tconst jobs = []\n\n\t\t\tif (this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData)) {\n\t\t\t\tjobs.push(axios.get(generateUrl(base))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tthis.fetchedObject = (r && r.data) || null\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => failed.push('object')))\n\t\t\t}\n\n\t\t\tconst rows = {}\n\t\t\tthis.relatedConfig.forEach((cfg, i) => {\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${cfg.register || register}/${cfg.schema}`)\n\t\t\t\tjobs.push(axios.get(url, { params: { [cfg.field]: id, _limit: cfg.limit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\trows[i] = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\trows[i] = []\n\t\t\t\t\t\tif (!failed.includes('related')) {\n\t\t\t\t\t\t\tfailed.push('related')\n\t\t\t\t\t\t}\n\t\t\t\t\t}))\n\t\t\t})\n\n\t\t\tif (this.content.auditTrail === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/audit-trails`), { params: { limit: this.content.auditLimit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.auditEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.auditEntries = []\n\t\t\t\t\t\tfailed.push('audit')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (this.content.timeline === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/timeline`))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.timelineEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.timelineEntries = []\n\t\t\t\t\t\tfailed.push('timeline')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (jobs.length === 0) {\n\t\t\t\tthis.failedSources = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tawait Promise.all(jobs)\n\t\t\tif (seq !== this.loadSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.relatedRows = rows\n\t\t\tthis.failedSources = failed\n\t\t\tthis.loading = false\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-timeline-widget__title {\n\tmargin: 0;\n\tfont-size: var(--font-size-large, 1.1em);\n}\n\n.cn-timeline-widget__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__list {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-timeline-widget__event {\n\tposition: relative;\n\tdisplay: flex;\n\tgap: 12px;\n\tpadding-block-end: 12px;\n}\n\n/* The line between dots: drawn from each dot down to the next event. */\n.cn-timeline-widget__event:not(:last-child)::before {\n\tcontent: '';\n\tposition: absolute;\n\tinset-block: 14px 0;\n\tinset-inline-start: 5px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n}\n\n.cn-timeline-widget__dot {\n\tflex: 0 0 auto;\n\twidth: 12px;\n\theight: 12px;\n\tmargin-block-start: 4px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-primary-element);\n}\n\n/* Upcoming: a hollow dot, plus the word \"Upcoming\" beside the date. */\n.cn-timeline-widget__event--upcoming .cn-timeline-widget__dot {\n\tbox-sizing: border-box;\n\tborder: 2px solid var(--color-primary-element);\n\tbackground-color: var(--color-main-background);\n}\n\n.cn-timeline-widget__body {\n\tmin-width: 0;\n}\n\n.cn-timeline-widget__when {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__badge {\n\tmargin-inline-start: 8px;\n\tfont-size: var(--font-size-small, 13px);\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-widget__label {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-timeline-widget__detail {\n\tmargin: 0;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["_createElementBlock","_toDisplayString","_createVNode","_createBlock","_openBlock","_Fragment","_renderList","_normalizeClass","_createElementVNode"],"mappings":";;;;;AAMM,EAAA,KAAA,EAAA,2BAAA;;;;AAI2B,EAAA,KAAA,EAAA,6BAAA;;;;AAW3B,EAAA,KAAA,EAAA,2BAAA;AAAA,EAAA,aAAA,EAAA,0BAAA;;;;AAIQ,EAAA,KAAK,EAAE,0BAAM;;;AASjB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,0BAAe,GAAA;;;;AAInB,EAAA,KAAA,EAAA,2BAAA;;AAGH,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,2BAAA,GAAA;;;AAGA,EAAA,KAAA,EAAA,4BAAA;;;;;;;uBAvCNA;AAAO,IAAA,KAAK,EAAC,oBAAK;AAAA,IAAA,aAAA,EAAA,oBAAA;AAAA,IAAA,WAAA,EAAA,KAAA,CAAA,OAAA,GAAA,MAAA,GAAA,OAAA;;KACf,QAAA,CAAA,aAAA;sBAAJA,kBAEK,CAAA,IAAA,EAFL,UAEK,EAAAC,eAAA;;KAEM,KAAO,CAAA,OAAA,IAAK,QAAK,CAAA,MAAA,CAAC,MAAE,KAAA,CAAA;yCAGzB,iBAAA,EAAA;UAFLC,WAAI,CAAA,wBAAA,EAAA;AAAA,YAAA,IAAA,EAAA,EAAA;AAAA,YAAA,aAAA,EAAA,MAAA;;;;sBAIJF;AAEY,UAAA,CAAA,KAAA,CAAA,aAAA,CAAA,MAAA,GAAA,CAAA;4BAAZG,WAEa,CAAA,qBAAA,EAAA;;AAFD,gBAAA,IAAA,EAAA,SAAA;AAAA,gBAAA,aAAA,EAAA,0BAAA;;;;;;;;AAIT,UAAA,CAAA,QAAA,CAAA,MAAA,CAAA,MAAA,KAAA,CAAA;4BAAHH,kBAEI,CAAA,GAAA,EAFJ,UAEI,EAAAC,eAAA;AAEF,eAAAG,SAAA,EAAA,EAAAJ,kBAAA,CAwBG,MAxBH,UAwBG,EAAA;kCAvBHA,kBAsBI,CAAAK,QAAA,EAAA,IAAA,EAAAC,UAAA,CArBY,QAAM,CAAA,MAAA,EAAA,CAAf,KAAK,KAAA;uCADZN,kBAsBI,CAAA,IAAA,EAAA;oBApBH,GAAG,EAAE,KAAK,CAAC,EAAE;AACd,oBAAA,KAAK,EAACO,cAAA,CAAA,CAAA,2BAAoB,EACY,EAAA,qCAAA,EAAA,KAAA,CAAA,QAAA,EAAA,CAAA,CAAA;oBACrC,aAAW,EAAE,KAAK,CAAC,MAAM;AAC1B,oBAAA,aAAW,EAAC,0BAAyB;;8CACpCC,kBAA0D,CAAA,MAAA,EAAA;AAAtD,sBAAA,KAAM,EAAC,yBAAyB;AAAC,sBAAA,aAAW,EAAC,MAAM;;uCActD,iBAAA,EAAA;sBAZDA,kBAEO,CAAA,MAAA,EAAA;AAFD,wBAAA,KAAA,EAAA,0BAAA;AAAA,wBAAA,QAAA,EAAA,KAAA,CAAA,EAAA,CAAA,WAAA,EAAA;AACF,uBAAA,EAAAP,eAAA,CAAA,QAAA,CAAA,YAAY,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;AAEhB,sBAAA,CAAA,KAAA,CAAA,QAAA;wCAAND,kBAEO,CAAA,MAAA,EAFP,UAEO,EAAAC,eAAA,CADH,QAAa,CAAA,aAAA,CAAA,EAAA,CAAA,YAAA;;AAEjB,sBAAAO,kBAAA,CAEI,KAFJ,WAEI,EAAAP,eAAA,CADA,kBAAS,CAAC,KAAK,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,YAAA;AAEtB,sBAAA,CAAA,KAAA,CAAA,MAAA;AAAH,2BAAAG,SAAA,EAAA,EAAAJ,kBAAA,CAEE,GAFF,EAAA,WAEE,EADEC,eAAA,CAAA,KAAA,CAAA,MAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"CnTimelineWidget.vue3.js","sources":["../../../../src/components/CnTimelineWidget/CnTimelineWidget.vue?vue&type=template&id=091aa98d&lang.js"],"sourcesContent":["<!-- SPDX-License-Identifier: EUPL-1.2 -->\n<!-- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl> -->\n<template>\n\t<section class=\"cn-timeline-widget\" data-testid=\"cn-timeline-widget\" :aria-busy=\"loading ? 'true' : 'false'\">\n\t\t<h3 v-if=\"resolvedTitle\" class=\"cn-timeline-widget__title\">\n\t\t\t{{ resolvedTitle }}\n\t\t</h3>\n\n\t\t<div v-if=\"loading && events.length === 0\" class=\"cn-timeline-widget__loading\">\n\t\t\t<NcLoadingIcon :size=\"24\" aria-hidden=\"true\" />\n\t\t\t<span>{{ loadingLabel }}</span>\n\t\t</div>\n\n\t\t<template v-else>\n\t\t\t<!-- A failed read is not an empty history: say which part is missing. -->\n\t\t\t<NcNoteCard v-if=\"failedSources.length > 0\" type=\"warning\" data-testid=\"cn-timeline-widget-error\">\n\t\t\t\t{{ failedText }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"events.length === 0\" class=\"cn-timeline-widget__empty\" data-testid=\"cn-timeline-widget-empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\n\t\t\t<ol v-else class=\"cn-timeline-widget__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"event in events\"\n\t\t\t\t\t:key=\"event.id\"\n\t\t\t\t\tclass=\"cn-timeline-widget__event\"\n\t\t\t\t\t:class=\"{ 'cn-timeline-widget__event--upcoming': event.upcoming }\"\n\t\t\t\t\t:data-source=\"event.source\"\n\t\t\t\t\tdata-testid=\"cn-timeline-widget-event\">\n\t\t\t\t\t<span class=\"cn-timeline-widget__dot\" aria-hidden=\"true\" />\n\t\t\t\t\t<div class=\"cn-timeline-widget__body\">\n\t\t\t\t\t\t<time class=\"cn-timeline-widget__when\" :datetime=\"event.at.toISOString()\">\n\t\t\t\t\t\t\t{{ formatMoment(event) }}\n\t\t\t\t\t\t</time>\n\t\t\t\t\t\t<span v-if=\"event.upcoming\" class=\"cn-timeline-widget__badge\">\n\t\t\t\t\t\t\t{{ upcomingLabel }}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<p class=\"cn-timeline-widget__label\">\n\t\t\t\t\t\t\t{{ translate(event.label) }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"event.detail\" class=\"cn-timeline-widget__detail\">\n\t\t\t\t\t\t\t{{ event.detail }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t</ol>\n\t\t</template>\n\t</section>\n</template>\n\n<script>\nimport { getLanguage, translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon, NcNoteCard } from '@nextcloud/vue'\nimport { auditEvents, fieldEvents, listEvents, relatedEvents, sortEvents, timelineEntryEvents } from '../../utils/timelineEvents.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnTimelineWidget — an object's dated events in time order (`timeline`\n * widget type for detail pages).\n *\n * Generalises dossiq's case timeline. It merges up to four sources, all\n * optional, into one list:\n *\n * - `fields`: the object's own date properties, `[{ field, label }]`. A\n * dotted path reaches metadata, such as `@self.created`.\n * - `related`: related objects, `[{ register?, schema, field, dateField?,\n * label, titleField? }]`. Rows of `schema` whose `field` holds this object's\n * id become events at their `dateField` (default `@self.created`).\n * - `auditTrail: true`: the object's audit trail, one event per change.\n * - `timeline: true`: OpenRegister's timeline of notes, calls and messages.\n *\n * Oldest first by default (`order: 'desc'` flips it). A moment after now is\n * marked upcoming, in words as well as style.\n *\n * ```json\n * { \"type\": \"timeline\", \"content\": {\n * \"title\": \"Timeline\",\n * \"fields\": [\n * { \"field\": \"@self.created\", \"label\": \"Booking created\" },\n * { \"field\": \"depositClearedAt\", \"label\": \"Deposit cleared\" },\n * { \"field\": \"confirmationSentAt\", \"label\": \"Confirmation mail sent\" },\n * { \"field\": \"startsAt\", \"label\": \"Starts\" },\n * { \"field\": \"endsAt\", \"label\": \"Ends\" }\n * ] } }\n * ```\n *\n * The object comes from the detail page's context, like `audit-trail`:\n * explicit props win, then the injects, then `content`.\n *\n * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n */\nexport default {\n\tname: 'CnTimelineWidget',\n\n\tcomponents: {\n\t\tNcLoadingIcon,\n\t\tNcNoteCard,\n\t},\n\n\tinject: {\n\t\t/** Detail-page object context from CnDetailPage (a ref or a raw bag). */\n\t\tcnObjectContext: { default: null },\n\t\t/** Detail object context holder from CnPageRenderer (`{ value: { objectData, ... } }`). */\n\t\tcnDetailObjectContext: { default: null },\n\t\t/** Consumer translation function; labels are authored in English. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** Register slug; object context spread as props by CnWidgetGrid. */\n\t\tregister: { type: String, default: '' },\n\t\t/**\n\t\t * Schema slug, or the schema object the detail context supplies.\n\t\t *\n\t\t * @type {string|object}\n\t\t */\n\t\tschema: { type: [String, Object], default: '' },\n\t\t/** The object's id. */\n\t\tobjectId: { type: String, default: '' },\n\t\t/** The object itself, when the host already has it. */\n\t\tobject: { type: Object, default: null },\n\t\t/** Card title override. */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Stored widget content: `{ title, fields, related, auditTrail, timeline, order }`. */\n\t\tcontent: { type: Object, default: () => ({}) },\n\t\t/** OpenRegister API base. */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tloading: false,\n\t\t\trelatedRows: {},\n\t\t\tauditEntries: [],\n\t\t\ttimelineEntries: [],\n\t\t\tfailedSources: [],\n\t\t\tfetchedObject: null,\n\t\t\tloadSeq: 0,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tctx() {\n\t\t\tconst raw = this.cnObjectContext\n\t\t\tconst inj = raw && (raw.value !== undefined ? raw.value : raw)\n\t\t\tconst holder = this.cnDetailObjectContext && this.cnDetailObjectContext.value\n\t\t\treturn inj || holder || {}\n\t\t},\n\n\t\tresolvedObjectId() {\n\t\t\treturn this.objectId || this.ctx.objectId || this.content.objectId || ''\n\t\t},\n\n\t\tresolvedRegister() {\n\t\t\treturn this.register || this.ctx.register || this.content.register || ''\n\t\t},\n\n\t\tresolvedSchema() {\n\t\t\tconst s = this.schema || this.ctx.schema || this.content.schema || ''\n\t\t\treturn typeof s === 'string' ? s : (s && (s.slug || s.name || s.id)) || ''\n\t\t},\n\n\t\t/**\n\t\t * The object: explicit prop, then the page context, then a fetch of\n\t\t * our own when only the id is known.\n\t\t *\n\t\t * @return {object|null}\n\t\t */\n\t\tresolvedObject() {\n\t\t\treturn this.object || this.ctx.object || this.ctx.objectData || this.fetchedObject || null\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\tconst raw = this.title || this.content.title || ''\n\t\t\treturn raw ? this.translate(raw) : ''\n\t\t},\n\n\t\tfieldsConfig() {\n\t\t\treturn Array.isArray(this.content.fields) ? this.content.fields : []\n\t\t},\n\n\t\trelatedConfig() {\n\t\t\treturn Array.isArray(this.content.related) ? this.content.related.filter((r) => r && r.schema && r.field) : []\n\t\t},\n\n\t\t/**\n\t\t * Every event from every source, in time order.\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tevents() {\n\t\t\tconst now = new Date()\n\t\t\tconst all = [\n\t\t\t\t...fieldEvents(this.resolvedObject || {}, this.fieldsConfig, now),\n\t\t\t\t...listEvents(this.resolvedObject || {}, this.content.lists, now),\n\t\t\t\t...this.relatedConfig.flatMap((cfg, i) => relatedEvents(this.relatedRows[i] || [], cfg, now)),\n\t\t\t\t...auditEvents(this.auditEntries, this.describeAudit, now),\n\t\t\t\t...timelineEntryEvents(this.timelineEntries, t('nextcloud-vue', 'Note'), now),\n\t\t\t]\n\t\t\treturn sortEvents(all, this.content.order === 'desc' ? 'desc' : 'asc')\n\t\t},\n\n\t\t/**\n\t\t * A signature of what to fetch, so a change refetches once.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tloadKey() {\n\t\t\treturn JSON.stringify({\n\t\t\t\tid: this.resolvedObjectId,\n\t\t\t\tregister: this.resolvedRegister,\n\t\t\t\tschema: this.resolvedSchema,\n\t\t\t\trelated: this.relatedConfig,\n\t\t\t\taudit: this.content.auditTrail === true,\n\t\t\t\ttimeline: this.content.timeline === true,\n\t\t\t\tneedObject: this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData),\n\t\t\t})\n\t\t},\n\n\t\tfailedText() {\n\t\t\treturn t('nextcloud-vue', 'Part of the timeline could not load: {parts}.', {\n\t\t\t\tparts: this.failedSources.map((s) => this.sourceName(s)).join(', '),\n\t\t\t})\n\t\t},\n\n\t\tloadingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Loading…')\n\t\t},\n\n\t\temptyLabel() {\n\t\t\treturn t('nextcloud-vue', 'Nothing has happened yet.')\n\t\t},\n\n\t\tupcomingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Upcoming')\n\t\t},\n\t},\n\n\twatch: {\n\t\tloadKey: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.load()\n\t\t\t},\n\t\t},\n\t},\n\n\tmethods: {\n\t\ttranslate(text) {\n\t\t\treturn text ? this.cnTranslate(text) : ''\n\t\t},\n\n\t\tsourceName(source) {\n\t\t\tif (source === 'audit') {\n\t\t\t\treturn t('nextcloud-vue', 'changes')\n\t\t\t}\n\t\t\tif (source === 'timeline') {\n\t\t\t\treturn t('nextcloud-vue', 'notes and messages')\n\t\t\t}\n\t\t\tif (source === 'object') {\n\t\t\t\treturn t('nextcloud-vue', 'dates')\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'related items')\n\t\t},\n\n\t\t/**\n\t\t * The label of an audit event, from its action and who did it.\n\t\t *\n\t\t * @param {string} action The audit action (create, update, delete).\n\t\t * @param {string} actor Who did it.\n\t\t * @return {string}\n\t\t */\n\t\tdescribeAudit(action, actor) {\n\t\t\tconst known = {\n\t\t\t\tcreate: t('nextcloud-vue', 'Created'),\n\t\t\t\tupdate: t('nextcloud-vue', 'Updated'),\n\t\t\t\tdelete: t('nextcloud-vue', 'Deleted'),\n\t\t\t}\n\t\t\tconst what = known[action] || action || t('nextcloud-vue', 'Changed')\n\t\t\treturn actor ? t('nextcloud-vue', '{action} by {actor}', { action: what, actor }) : what\n\t\t},\n\n\t\t/**\n\t\t * Show a moment in the reader's language: a date for a calendar day,\n\t\t * date and time otherwise.\n\t\t *\n\t\t * @param {object} event The event.\n\t\t * @return {string}\n\t\t */\n\t\tformatMoment(event) {\n\t\t\tconst locale = (typeof getLanguage === 'function' && getLanguage()) || undefined\n\t\t\tconst options = event.dateOnly\n\t\t\t\t? { dateStyle: 'medium' }\n\t\t\t\t: { dateStyle: 'medium', timeStyle: 'short' }\n\t\t\ttry {\n\t\t\t\treturn new Intl.DateTimeFormat(locale, options).format(event.at)\n\t\t\t} catch {\n\t\t\t\treturn event.at.toLocaleString(userLocale())\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Fetch every configured source. Each one fails on its own, so one\n\t\t * unreachable source never hides the others.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/timeline-widget/specs/timeline-widget/spec.md#requirement-a-timeline-widget-shows-an-objects-dated-events-in-order\n\t\t */\n\t\tasync load() {\n\t\t\tconst id = this.resolvedObjectId\n\t\t\tconst register = this.resolvedRegister\n\t\t\tconst schema = this.resolvedSchema\n\t\t\tconst seq = ++this.loadSeq\n\t\t\tif (!id || !register || !schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst [{ default: axios }, { generateUrl }] = await Promise.all([\n\t\t\t\timport('@nextcloud/axios'),\n\t\t\t\timport('@nextcloud/router'),\n\t\t\t])\n\t\t\tconst base = `${this.apiBase}/objects/${register}/${schema}/${id}`\n\t\t\tconst failed = []\n\t\t\tconst jobs = []\n\n\t\t\tif (this.fieldsConfig.length > 0 && !(this.object || this.ctx.object || this.ctx.objectData)) {\n\t\t\t\tjobs.push(axios.get(generateUrl(base))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tthis.fetchedObject = (r && r.data) || null\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => failed.push('object')))\n\t\t\t}\n\n\t\t\tconst rows = {}\n\t\t\tthis.relatedConfig.forEach((cfg, i) => {\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${cfg.register || register}/${cfg.schema}`)\n\t\t\t\tjobs.push(axios.get(url, { params: { [cfg.field]: id, _limit: cfg.limit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\trows[i] = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\trows[i] = []\n\t\t\t\t\t\tif (!failed.includes('related')) {\n\t\t\t\t\t\t\tfailed.push('related')\n\t\t\t\t\t\t}\n\t\t\t\t\t}))\n\t\t\t})\n\n\t\t\tif (this.content.auditTrail === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/audit-trails`), { params: { limit: this.content.auditLimit || 50 } })\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.auditEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.auditEntries = []\n\t\t\t\t\t\tfailed.push('audit')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (this.content.timeline === true) {\n\t\t\t\tjobs.push(axios.get(generateUrl(`${base}/timeline`))\n\t\t\t\t\t.then((r) => {\n\t\t\t\t\t\tconst data = r && r.data\n\t\t\t\t\t\tthis.timelineEntries = (data && (data.results || data)) || []\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\tthis.timelineEntries = []\n\t\t\t\t\t\tfailed.push('timeline')\n\t\t\t\t\t}))\n\t\t\t}\n\n\t\t\tif (jobs.length === 0) {\n\t\t\t\tthis.failedSources = []\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = true\n\t\t\tawait Promise.all(jobs)\n\t\t\tif (seq !== this.loadSeq) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.relatedRows = rows\n\t\t\tthis.failedSources = failed\n\t\t\tthis.loading = false\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-timeline-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n}\n\n.cn-timeline-widget__title {\n\tmargin: 0;\n\tfont-size: var(--font-size-large, 1.1em);\n}\n\n.cn-timeline-widget__loading {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__list {\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-timeline-widget__event {\n\tposition: relative;\n\tdisplay: flex;\n\tgap: 12px;\n\tpadding-block-end: 12px;\n}\n\n/* The line between dots: drawn from each dot down to the next event. */\n.cn-timeline-widget__event:not(:last-child)::before {\n\tcontent: '';\n\tposition: absolute;\n\tinset-block: 14px 0;\n\tinset-inline-start: 5px;\n\tborder-inline-start: 2px solid var(--color-border-dark);\n}\n\n.cn-timeline-widget__dot {\n\tflex: 0 0 auto;\n\twidth: 12px;\n\theight: 12px;\n\tmargin-block-start: 4px;\n\tborder-radius: 50%;\n\tbackground-color: var(--color-primary-element);\n}\n\n/* Upcoming: a hollow dot, plus the word \"Upcoming\" beside the date. */\n.cn-timeline-widget__event--upcoming .cn-timeline-widget__dot {\n\tbox-sizing: border-box;\n\tborder: 2px solid var(--color-primary-element);\n\tbackground-color: var(--color-main-background);\n}\n\n.cn-timeline-widget__body {\n\tmin-width: 0;\n}\n\n.cn-timeline-widget__when {\n\tfont-size: var(--font-size-small, 13px);\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-timeline-widget__badge {\n\tmargin-inline-start: 8px;\n\tfont-size: var(--font-size-small, 13px);\n\tfont-weight: bold;\n\tcolor: var(--color-main-text);\n}\n\n.cn-timeline-widget__label {\n\tmargin: 0;\n\tfont-weight: bold;\n}\n\n.cn-timeline-widget__detail {\n\tmargin: 0;\n\toverflow-wrap: anywhere;\n}\n</style>\n"],"names":["_createElementBlock","_toDisplayString","_createVNode","_createBlock","_openBlock","_Fragment","_renderList","_normalizeClass","_createElementVNode"],"mappings":";;;;;AAMM,EAAA,KAAA,EAAA,2BAAA;;;;AAI2B,EAAA,KAAA,EAAA,6BAAA;;;;AAW3B,EAAA,KAAA,EAAA,2BAAA;AAAA,EAAA,aAAA,EAAA,0BAAA;;;;AAIQ,EAAA,KAAK,EAAE,0BAAM;;;AASjB,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,0BAAe,GAAA;;;;AAInB,EAAA,KAAA,EAAA,2BAAA;;AAGH,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,2BAAA,GAAA;;;AAGA,EAAA,KAAA,EAAA,4BAAA;;;;;;;uBAvCNA;AAAO,IAAA,KAAK,EAAC,oBAAK;AAAA,IAAA,aAAA,EAAA,oBAAA;AAAA,IAAA,WAAA,EAAA,KAAA,CAAA,OAAA,GAAA,MAAA,GAAA,OAAA;;KACf,QAAA,CAAA,aAAA;sBAAJA,kBAEK,CAAA,IAAA,EAFL,UAEK,EAAAC,eAAA;;KAEM,KAAO,CAAA,OAAA,IAAK,QAAK,CAAA,MAAA,CAAC,MAAE,KAAA,CAAA;yCAGzB,iBAAA,EAAA;UAFLC,WAAI,CAAA,wBAAA,EAAA;AAAA,YAAA,IAAA,EAAA,EAAA;AAAA,YAAA,aAAA,EAAA,MAAA;;;;sBAIJF;AAEY,UAAA,CAAA,KAAA,CAAA,aAAA,CAAA,MAAA,GAAA,CAAA;4BAAZG,WAEa,CAAA,qBAAA,EAAA;;AAFD,gBAAA,IAAA,EAAA,SAAA;AAAA,gBAAA,aAAA,EAAA,0BAAA;;;;;;;;AAIT,UAAA,CAAA,QAAA,CAAA,MAAA,CAAA,MAAA,KAAA,CAAA;4BAAHH,kBAEI,CAAA,GAAA,EAFJ,UAEI,EAAAC,eAAA;AAEF,eAAAG,SAAA,EAAA,EAAAJ,kBAAA,CAwBG,MAxBH,UAwBG,EAAA;kCAvBHA,kBAsBI,CAAAK,QAAA,EAAA,IAAA,EAAAC,UAAA,CArBY,QAAM,CAAA,MAAA,EAAA,CAAf,KAAK,KAAA;uCADZN,kBAsBI,CAAA,IAAA,EAAA;oBApBH,GAAG,EAAE,KAAK,CAAC,EAAE;AACd,oBAAA,KAAK,EAACO,cAAA,CAAA,CAAA,2BAAoB,EACY,EAAA,qCAAA,EAAA,KAAA,CAAA,QAAA,EAAA,CAAA,CAAA;oBACrC,aAAW,EAAE,KAAK,CAAC,MAAM;AAC1B,oBAAA,aAAW,EAAC,0BAAyB;;8CACpCC,kBAA0D,CAAA,MAAA,EAAA;AAAtD,sBAAA,KAAM,EAAC,yBAAyB;AAAC,sBAAA,aAAW,EAAC,MAAM;;uCActD,iBAAA,EAAA;sBAZDA,kBAEO,CAAA,MAAA,EAAA;AAFD,wBAAA,KAAA,EAAA,0BAAA;AAAA,wBAAA,QAAA,EAAA,KAAA,CAAA,EAAA,CAAA,WAAA,EAAA;AACF,uBAAA,EAAAP,eAAA,CAAA,QAAA,CAAA,YAAY,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;AAEhB,sBAAA,CAAA,KAAA,CAAA,QAAA;wCAAND,kBAEO,CAAA,MAAA,EAFP,UAEO,EAAAC,eAAA,CADH,QAAa,CAAA,aAAA,CAAA,EAAA,CAAA,YAAA;;AAEjB,sBAAAO,kBAAA,CAEI,KAFJ,WAEI,EAAAP,eAAA,CADA,kBAAS,CAAC,KAAK,CAAC,KAAK,CAAA,CAAA,EAAA,CAAA,YAAA;AAEtB,sBAAA,CAAA,KAAA,CAAA,MAAA;AAAH,2BAAAG,SAAA,EAAA,EAAAJ,kBAAA,CAEE,GAFF,EAAA,WAEE,EADEC,eAAA,CAAA,KAAA,CAAA,MAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;;;;"}
|
|
@@ -2,7 +2,7 @@ import script from './CnTranslatedBadge.vue2.js';
|
|
|
2
2
|
import { render } from './CnTranslatedBadge.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-37e3a382";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { translate } from '@nextcloud/l10n';
|
|
2
|
+
import { userLocale } from '../../utils/userLocale.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* CnTranslatedBadge — surfaces OR's `_translationMeta.translatedFrom`
|
|
@@ -144,7 +145,7 @@ var script = {
|
|
|
144
145
|
try {
|
|
145
146
|
const d = new Date(this.translatedAt);
|
|
146
147
|
if (!Number.isNaN(d.getTime())) {
|
|
147
|
-
return translate('nextcloud-vue', 'Translated at {when}', { when: d.toLocaleString() })
|
|
148
|
+
return translate('nextcloud-vue', 'Translated at {when}', { when: d.toLocaleString(userLocale()) })
|
|
148
149
|
}
|
|
149
150
|
} catch {
|
|
150
151
|
// fall through to raw ISO
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnTranslatedBadge.vue2.js","sources":["../../../../src/components/CnTranslatedBadge/CnTranslatedBadge.vue"],"sourcesContent":["<!--\n CnTranslatedBadge — stateless chip that surfaces OR's\n `_translationMeta` block.\n\n The badge auto-hides when the bound object has no `_translationMeta`\n block, or when `_translationMeta.translatedFrom` is null. When the\n field IS set, the badge renders \"(translated from {sourceLanguage})\"\n and exposes the `translatedAt` timestamp via the `title` attribute.\n\n Pairs with the language-negotiation getters on `createObjectStore`\n (see `i18n-language-negotiation-getters`): apps that wire\n `languageGetter` get translated bytes from OR; the badge then\n signals to the user that those bytes are a translation projection,\n not the source row.\n-->\n<template>\n\t<span\n\t\tv-if=\"visible\"\n\t\tclass=\"cn-translated-badge\"\n\t\t:title=\"hoverTitle\"\n\t\tdata-testid=\"cn-translated-badge\">\n\t\t<span class=\"cn-translated-badge__icon\" aria-hidden=\"true\">⇄</span>\n\t\t<span class=\"cn-translated-badge__label\">\n\t\t\t{{ label }}\n\t\t</span>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\n\n/**\n * CnTranslatedBadge — surfaces OR's `_translationMeta.translatedFrom`\n * as a small chip in detail surfaces.\n *\n * Basic:\n * ```vue\n * <CnTranslatedBadge :object=\"object\" />\n * ```\n *\n * With custom locale name formatter:\n * ```vue\n * <CnTranslatedBadge\n * :object=\"object\"\n * :locale-name-formatter=\"(bcp47) => myLanguageLabels[bcp47] || bcp47\" />\n * ```\n */\nexport default {\n\tname: 'CnTranslatedBadge',\n\n\tprops: {\n\t\t/**\n\t\t * The OR object whose `_translationMeta` is surfaced. The\n\t\t * badge auto-hides when `object` is null, when\n\t\t * `object._translationMeta` is missing, or when\n\t\t * `_translationMeta.translatedFrom` is null/empty.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional BCP-47 → display name function. Receives the\n\t\t * BCP-47 string from `_translationMeta.translatedFrom` and\n\t\t * returns a user-facing label (e.g. `'nl' → 'Nederlands'`).\n\t\t * When omitted, falls back to `Intl.DisplayNames` when\n\t\t * available, then to the raw BCP-47 string.\n\t\t *\n\t\t * @type {((locale: string) => string)|null}\n\t\t */\n\t\tlocaleNameFormatter: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The translatedFrom BCP-47 string when present, else null.\n\t\t *\n\t\t * @return {string|null}\n\t\t */\n\t\ttranslatedFrom() {\n\t\t\tconst meta = this.object && this.object._translationMeta\n\t\t\tif (!meta) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst v = meta.translatedFrom\n\t\t\treturn typeof v === 'string' && v.length > 0 ? v : null\n\t\t},\n\n\t\t/**\n\t\t * The translatedAt ISO timestamp when present, else null.\n\t\t *\n\t\t * @return {string|null}\n\t\t */\n\t\ttranslatedAt() {\n\t\t\tconst meta = this.object && this.object._translationMeta\n\t\t\tif (!meta) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst v = meta.translatedAt\n\t\t\treturn typeof v === 'string' && v.length > 0 ? v : null\n\t\t},\n\n\t\t/**\n\t\t * Whether the badge should render at all.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tvisible() {\n\t\t\treturn this.translatedFrom !== null\n\t\t},\n\n\t\t/**\n\t\t * Display name for the source language. Falls back through\n\t\t * `localeNameFormatter` → `Intl.DisplayNames` → raw BCP-47.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsourceDisplayName() {\n\t\t\tconst bcp47 = this.translatedFrom\n\t\t\tif (!bcp47) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (typeof this.localeNameFormatter === 'function') {\n\t\t\t\ttry {\n\t\t\t\t\tconst v = this.localeNameFormatter(bcp47)\n\t\t\t\t\tif (typeof v === 'string' && v.length > 0) {\n\t\t\t\t\t\treturn v\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// fall through to Intl\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof Intl !== 'undefined' && typeof Intl.DisplayNames === 'function') {\n\t\t\t\ttry {\n\t\t\t\t\tconst navLang = (typeof navigator !== 'undefined' && navigator.language) || 'en'\n\t\t\t\t\tconst dn = new Intl.DisplayNames([navLang], { type: 'language' })\n\t\t\t\t\tconst v = dn.of(bcp47)\n\t\t\t\t\tif (typeof v === 'string' && v.length > 0) {\n\t\t\t\t\t\treturn v\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// fall through to raw\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn bcp47\n\t\t},\n\n\t\t/**\n\t\t * The user-facing label, e.g. `(translated from Dutch)`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tlabel() {\n\t\t\treturn t('nextcloud-vue', '(translated from {language})', { language: this.sourceDisplayName })\n\t\t},\n\n\t\t/**\n\t\t * Hover title — exposes `translatedAt` so users can see how\n\t\t * old the projection is.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\thoverTitle() {\n\t\t\tif (!this.translatedAt) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst d = new Date(this.translatedAt)\n\t\t\t\tif (!Number.isNaN(d.getTime())) {\n\t\t\t\t\treturn t('nextcloud-vue', 'Translated at {when}', { when: d.toLocaleString() })\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// fall through to raw ISO\n\t\t\t}\n\t\t\treturn this.translatedAt\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-translated-badge {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: var(--default-grid-baseline, 4px);\n\tpadding: calc(0.5 * var(--default-grid-baseline, 4px)) calc(2 * var(--default-grid-baseline, 4px));\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.75em;\n\tfont-weight: 500;\n\tline-height: 1;\n}\n\n.cn-translated-badge__icon {\n\tfont-size: 0.9em;\n}\n</style>\n"],"names":["t"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CnTranslatedBadge.vue2.js","sources":["../../../../src/components/CnTranslatedBadge/CnTranslatedBadge.vue"],"sourcesContent":["<!--\n CnTranslatedBadge — stateless chip that surfaces OR's\n `_translationMeta` block.\n\n The badge auto-hides when the bound object has no `_translationMeta`\n block, or when `_translationMeta.translatedFrom` is null. When the\n field IS set, the badge renders \"(translated from {sourceLanguage})\"\n and exposes the `translatedAt` timestamp via the `title` attribute.\n\n Pairs with the language-negotiation getters on `createObjectStore`\n (see `i18n-language-negotiation-getters`): apps that wire\n `languageGetter` get translated bytes from OR; the badge then\n signals to the user that those bytes are a translation projection,\n not the source row.\n-->\n<template>\n\t<span\n\t\tv-if=\"visible\"\n\t\tclass=\"cn-translated-badge\"\n\t\t:title=\"hoverTitle\"\n\t\tdata-testid=\"cn-translated-badge\">\n\t\t<span class=\"cn-translated-badge__icon\" aria-hidden=\"true\">⇄</span>\n\t\t<span class=\"cn-translated-badge__label\">\n\t\t\t{{ label }}\n\t\t</span>\n\t</span>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnTranslatedBadge — surfaces OR's `_translationMeta.translatedFrom`\n * as a small chip in detail surfaces.\n *\n * Basic:\n * ```vue\n * <CnTranslatedBadge :object=\"object\" />\n * ```\n *\n * With custom locale name formatter:\n * ```vue\n * <CnTranslatedBadge\n * :object=\"object\"\n * :locale-name-formatter=\"(bcp47) => myLanguageLabels[bcp47] || bcp47\" />\n * ```\n */\nexport default {\n\tname: 'CnTranslatedBadge',\n\n\tprops: {\n\t\t/**\n\t\t * The OR object whose `_translationMeta` is surfaced. The\n\t\t * badge auto-hides when `object` is null, when\n\t\t * `object._translationMeta` is missing, or when\n\t\t * `_translationMeta.translatedFrom` is null/empty.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional BCP-47 → display name function. Receives the\n\t\t * BCP-47 string from `_translationMeta.translatedFrom` and\n\t\t * returns a user-facing label (e.g. `'nl' → 'Nederlands'`).\n\t\t * When omitted, falls back to `Intl.DisplayNames` when\n\t\t * available, then to the raw BCP-47 string.\n\t\t *\n\t\t * @type {((locale: string) => string)|null}\n\t\t */\n\t\tlocaleNameFormatter: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The translatedFrom BCP-47 string when present, else null.\n\t\t *\n\t\t * @return {string|null}\n\t\t */\n\t\ttranslatedFrom() {\n\t\t\tconst meta = this.object && this.object._translationMeta\n\t\t\tif (!meta) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst v = meta.translatedFrom\n\t\t\treturn typeof v === 'string' && v.length > 0 ? v : null\n\t\t},\n\n\t\t/**\n\t\t * The translatedAt ISO timestamp when present, else null.\n\t\t *\n\t\t * @return {string|null}\n\t\t */\n\t\ttranslatedAt() {\n\t\t\tconst meta = this.object && this.object._translationMeta\n\t\t\tif (!meta) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst v = meta.translatedAt\n\t\t\treturn typeof v === 'string' && v.length > 0 ? v : null\n\t\t},\n\n\t\t/**\n\t\t * Whether the badge should render at all.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tvisible() {\n\t\t\treturn this.translatedFrom !== null\n\t\t},\n\n\t\t/**\n\t\t * Display name for the source language. Falls back through\n\t\t * `localeNameFormatter` → `Intl.DisplayNames` → raw BCP-47.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsourceDisplayName() {\n\t\t\tconst bcp47 = this.translatedFrom\n\t\t\tif (!bcp47) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (typeof this.localeNameFormatter === 'function') {\n\t\t\t\ttry {\n\t\t\t\t\tconst v = this.localeNameFormatter(bcp47)\n\t\t\t\t\tif (typeof v === 'string' && v.length > 0) {\n\t\t\t\t\t\treturn v\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// fall through to Intl\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof Intl !== 'undefined' && typeof Intl.DisplayNames === 'function') {\n\t\t\t\ttry {\n\t\t\t\t\tconst navLang = (typeof navigator !== 'undefined' && navigator.language) || 'en'\n\t\t\t\t\tconst dn = new Intl.DisplayNames([navLang], { type: 'language' })\n\t\t\t\t\tconst v = dn.of(bcp47)\n\t\t\t\t\tif (typeof v === 'string' && v.length > 0) {\n\t\t\t\t\t\treturn v\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// fall through to raw\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn bcp47\n\t\t},\n\n\t\t/**\n\t\t * The user-facing label, e.g. `(translated from Dutch)`.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tlabel() {\n\t\t\treturn t('nextcloud-vue', '(translated from {language})', { language: this.sourceDisplayName })\n\t\t},\n\n\t\t/**\n\t\t * Hover title — exposes `translatedAt` so users can see how\n\t\t * old the projection is.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\thoverTitle() {\n\t\t\tif (!this.translatedAt) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst d = new Date(this.translatedAt)\n\t\t\t\tif (!Number.isNaN(d.getTime())) {\n\t\t\t\t\treturn t('nextcloud-vue', 'Translated at {when}', { when: d.toLocaleString(userLocale()) })\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// fall through to raw ISO\n\t\t\t}\n\t\t\treturn this.translatedAt\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-translated-badge {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: var(--default-grid-baseline, 4px);\n\tpadding: calc(0.5 * var(--default-grid-baseline, 4px)) calc(2 * var(--default-grid-baseline, 4px));\n\tborder-radius: var(--border-radius-pill, 999px);\n\tbackground: var(--color-background-hover);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 0.75em;\n\tfont-weight: 500;\n\tline-height: 1;\n}\n\n.cn-translated-badge__icon {\n\tfont-size: 0.9em;\n}\n</style>\n"],"names":["t"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnVersionHistory.vue2.js';
|
|
|
2
2
|
import { render } from './CnVersionHistory.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-0fca5a52";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -7,6 +7,7 @@ import FileCompare from 'vue-material-design-icons/FileCompare.vue';
|
|
|
7
7
|
import __sfc_main from '../CnDetailCard/CnDetailCard.vue.js';
|
|
8
8
|
import { foldAuditTrailEntries } from '../../utils/auditTrailDiff.js';
|
|
9
9
|
import { computeObjectDiff } from '../../utils/computeObjectDiff.js';
|
|
10
|
+
import { userLocale } from '../../utils/userLocale.js';
|
|
10
11
|
import { buildHeaders } from '../../utils/headers.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -348,7 +349,7 @@ var script = {
|
|
|
348
349
|
if (Number.isNaN(d.getTime()) === true) {
|
|
349
350
|
return String(raw)
|
|
350
351
|
}
|
|
351
|
-
return d.toLocaleString()
|
|
352
|
+
return d.toLocaleString(userLocale())
|
|
352
353
|
},
|
|
353
354
|
},
|
|
354
355
|
};
|
|
@@ -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":"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"}
|
|
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":"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"}
|