@conduction/nextcloud-vue 2.85.0 → 2.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue.js +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js +3 -2
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue2.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnMetadataTab.vue3.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue.js +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js +5 -4
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdvancedFormDialog/CnPropertyValueCell.vue3.js.map +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue.js +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js +2 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +2 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
- package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue.js +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js +156 -14
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +105 -74
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js.map +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue.js +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js +2 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnCalendarEventPicker/CnCalendarEventPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue.js +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js +2 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCalendarWidget/CnCalendarWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +6 -5
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue.js +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js +2 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue2.js.map +1 -1
- package/dist/esm/components/CnCollectivePagePicker/CnCollectivePagePicker.vue3.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue.js +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js +2 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue2.js.map +1 -1
- package/dist/esm/components/CnConversationThread/CnConversationThread.vue3.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue.js +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js +2 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnCountdownWidget/CnCountdownWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +2 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue.js +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js +3 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue2.js.map +1 -1
- package/dist/esm/components/CnDataMatrix/CnDataMatrix.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js +2 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailHeaderChips.vue3.js.map +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue.js +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js +2 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue2.js.map +1 -1
- package/dist/esm/components/CnEmailPicker/CnEmailPicker.vue3.js.map +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue.js +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js +3 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue2.js.map +1 -1
- package/dist/esm/components/CnFederationStatus/CnFederationStatus.vue3.js.map +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue.js +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue2.js +3 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue2.js.map +1 -1
- package/dist/esm/components/CnFileManager/CnFileManager.vue3.js.map +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue.js +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js +2 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue2.js.map +1 -1
- package/dist/esm/components/CnFilePreview/CnFilePreview.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +49 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +3 -3
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue.js +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js +2 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue2.js.map +1 -1
- package/dist/esm/components/CnFollowToggle/CnFollowToggle.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -5
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +2 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
- package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue.js +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js +3 -2
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCalendar/CnObjectCalendar.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +28 -0
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +82 -75
- package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue.js +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js +5 -4
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnAuditTrailTab.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFlowTasksPanel.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnNotesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js +2 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnTasksTab.vue3.js.map +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue.js +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js +2 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue2.js.map +1 -1
- package/dist/esm/components/CnPropertySourceField/CnPropertySourceField.vue3.js.map +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue.js +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js +2 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue2.js.map +1 -1
- package/dist/esm/components/CnRoadmapItem/CnRoadmapItem.vue3.js.map +1 -1
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js +2 -0
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js +2 -2
- package/dist/esm/components/CnSchemaFormDialog/CnSchemaFormDialog.vue3.js.map +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue.js +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js +2 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue2.js.map +1 -1
- package/dist/esm/components/CnStatsBlock/CnStatsBlock.vue3.js.map +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue.js +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js +2 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue2.js.map +1 -1
- package/dist/esm/components/CnSummaryAggregates/CnSummaryAggregates.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +36 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +55 -40
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue.js +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js +2 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue2.js.map +1 -1
- package/dist/esm/components/CnTasksCard/CnTasksCard.vue3.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue.js +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js +2 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTimelineWidget/CnTimelineWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue.js +1 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js +2 -1
- package/dist/esm/components/CnTranslatedBadge/CnTranslatedBadge.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue.js +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js +2 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionHistory/CnVersionHistory.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +3 -26
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue.js +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js +2 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue2.js.map +1 -1
- package/dist/esm/dialogs/CnNoteHistoryDialog.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js +3 -2
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js +4 -3
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/activity/CnActivityTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js +3 -2
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/analytics/CnAnalyticsTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js +6 -5
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/calendar/CnCalendarTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/contactmoment/CnContactmomentCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/cospend/CnCospendTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/deck/CnDeckTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/email/CnEmailCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue.js +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js +2 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionCard.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/field-inspection/CnFieldInspectionTab.vue3.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue.js +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js +2 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue2.js.map +1 -1
- package/dist/esm/integrations/builtin/photos/CnPhotosTab.vue3.js.map +1 -1
- package/dist/esm/l10n/en.json.js +35 -2
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +38 -2
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +1068 -962
- package/dist/esm/store/useObjectStore.js +7 -2
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/boardColumns.js +50 -1
- package/dist/esm/utils/boardColumns.js.map +1 -1
- package/dist/esm/utils/boardReferenceColumns.js +115 -4
- package/dist/esm/utils/boardReferenceColumns.js.map +1 -1
- package/dist/esm/utils/contentHeaderLink.js +48 -1
- package/dist/esm/utils/contentHeaderLink.js.map +1 -1
- package/dist/esm/utils/schema.js +5 -4
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/utils/userLocale.js +30 -0
- package/dist/esm/utils/userLocale.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +1088 -476
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1068 -962
- package/l10n/en.json +35 -2
- package/l10n/nl.json +38 -2
- package/package.json +1 -1
- package/src/components/CnAdvancedFormDialog/CnMetadataTab.vue +3 -2
- package/src/components/CnAdvancedFormDialog/CnPropertyValueCell.vue +5 -4
- package/src/components/CnAnalyticsReportPicker/CnAnalyticsReportPicker.vue +2 -1
- package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +2 -1
- package/src/components/CnBoardView/CnBoardView.vue +189 -24
- package/src/components/CnCalendarEventPicker/CnCalendarEventPicker.vue +2 -1
- package/src/components/CnCalendarWidget/CnCalendarWidget.vue +2 -1
- package/src/components/CnChartWidget/CnChartWidget.vue +6 -5
- package/src/components/CnCollectivePagePicker/CnCollectivePagePicker.vue +2 -1
- package/src/components/CnConversationThread/CnConversationThread.vue +2 -1
- package/src/components/CnCountdownWidget/CnCountdownWidget.vue +2 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +2 -1
- package/src/components/CnDataMatrix/CnDataMatrix.vue +2 -1
- package/src/components/CnDetailPage/CnDetailHeaderChips.vue +2 -1
- package/src/components/CnEmailPicker/CnEmailPicker.vue +2 -1
- package/src/components/CnFederationStatus/CnFederationStatus.vue +3 -1
- package/src/components/CnFileManager/CnFileManager.vue +2 -1
- package/src/components/CnFilePreview/CnFilePreview.vue +2 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +54 -6
- package/src/components/CnFollowToggle/CnFollowToggle.vue +2 -1
- package/src/components/CnIndexPage/CnIndexPage.vue +30 -4
- package/src/components/CnNotesCard/CnNotesCard.vue +2 -1
- package/src/components/CnObjectCalendar/CnObjectCalendar.vue +3 -2
- package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +36 -0
- package/src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue +5 -4
- package/src/components/CnObjectSidebar/CnAuditTrailTab.vue +2 -1
- package/src/components/CnObjectSidebar/CnFlowTasksPanel.vue +2 -1
- package/src/components/CnObjectSidebar/CnNotesTab.vue +2 -1
- package/src/components/CnObjectSidebar/CnTasksTab.vue +2 -1
- package/src/components/CnPropertySourceField/CnPropertySourceField.vue +2 -1
- package/src/components/CnRoadmapItem/CnRoadmapItem.vue +2 -1
- package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +4 -2
- package/src/components/CnStatsBlock/CnStatsBlock.vue +2 -1
- package/src/components/CnSummaryAggregates/CnSummaryAggregates.vue +2 -1
- package/src/components/CnTabsWidget/CnTabsWidget.vue +71 -0
- package/src/components/CnTasksCard/CnTasksCard.vue +2 -1
- package/src/components/CnTimelineWidget/CnTimelineWidget.vue +2 -1
- package/src/components/CnTranslatedBadge/CnTranslatedBadge.vue +2 -1
- package/src/components/CnVersionHistory/CnVersionHistory.vue +2 -1
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +3 -26
- package/src/css/board.css +40 -0
- package/src/dialogs/CnNoteHistoryDialog.vue +2 -1
- package/src/integrations/builtin/activity/CnActivityCard.vue +3 -2
- package/src/integrations/builtin/activity/CnActivityTab.vue +4 -3
- package/src/integrations/builtin/analytics/CnAnalyticsTab.vue +3 -2
- package/src/integrations/builtin/calendar/CnCalendarCard.vue +2 -1
- package/src/integrations/builtin/calendar/CnCalendarTab.vue +6 -5
- package/src/integrations/builtin/contactmoment/CnContactmomentCard.vue +2 -1
- package/src/integrations/builtin/cospend/CnCospendTab.vue +2 -1
- package/src/integrations/builtin/deck/CnDeckTab.vue +2 -1
- package/src/integrations/builtin/email/CnEmailCard.vue +2 -1
- package/src/integrations/builtin/field-inspection/CnFieldInspectionCard.vue +2 -1
- package/src/integrations/builtin/field-inspection/CnFieldInspectionTab.vue +2 -1
- package/src/integrations/builtin/photos/CnPhotosTab.vue +2 -1
- package/src/schemas/app-manifest-v2.schema.json +4 -1
- package/src/store/useObjectStore.js +7 -2
- package/src/utils/boardColumns.js +49 -0
- package/src/utils/boardReferenceColumns.js +114 -3
- package/src/utils/contentHeaderLink.js +47 -0
- package/src/utils/schema.js +5 -4
- package/src/utils/userLocale.js +26 -0
- package/src/utils/validateManifestV2.compiled.js +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnObjectMetadataWidget.vue2.js","sources":["../../../../src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue"],"sourcesContent":["<!--\n CnObjectMetadataWidget — Read-only metadata display widget.\n\n Shows system/internal metadata for an OpenRegister object in a horizontal\n label-value grid. Automatically extracts known metadata fields from the object\n (id, uuid, uri, register, schema, created, updated, owner, etc.).\n\n Not editable — purely informational. Wraps CnDetailCard + CnDetailGrid.\n-->\n<template>\n\t<CnDetailCard :title=\"title\"\n\t\t:icon=\"iconComponent\"\n\t\t:collapsible=\"collapsible\"\n\t\t:collapsed=\"collapsed\">\n\t\t<template #actions>\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Grouped: one grid per category, each under its own heading. A flat\n\t\t list of twenty rows is a wall; Identity / Location / Ownership /\n\t\t Lifecycle / Archiving is how a reader actually looks for one fact.\n\t\t `grouped: false` restores the single flat grid for hosts that want\n\t\t the old shape. -->\n\t\t<template v-if=\"grouped && groupedItems.length > 0\">\n\t\t\t<div\n\t\t\t\tv-for=\"group in groupedItems\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-object-metadata__group\">\n\t\t\t\t<h4 class=\"cn-object-metadata__group-title\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</h4>\n\t\t\t\t<CnDetailGrid\n\t\t\t\t\t:items=\"group.items\"\n\t\t\t\t\t:layout=\"layout\"\n\t\t\t\t\t:columns=\"columns\"\n\t\t\t\t\t:labelWidth=\"labelWidth\"\n\t\t\t\t\t:accent=\"false\"\n\t\t\t\t\t:emptyLabel=\"emptyLabel\" />\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- One flat grid: either because grouping is off, or because there is\n\t\t nothing to group and CnDetailGrid already owns the empty state. -->\n\t\t<CnDetailGrid\n\t\t\tv-else\n\t\t\t:items=\"metadataItems\"\n\t\t\t:layout=\"layout\"\n\t\t\t:columns=\"columns\"\n\t\t\t:labelWidth=\"labelWidth\"\n\t\t\t:accent=\"false\"\n\t\t\t:emptyLabel=\"emptyLabel\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { CnDetailCard } from '../CnDetailCard/index.js'\nimport { CnDetailGrid } from '../CnDetailGrid/index.js'\n\n/**\n * Known metadata fields and their labels.\n * These are the standard fields from OpenRegister's `@self` / system fields.\n */\nconst METADATA_FIELDS = [\n\t{ key: 'id', label: 'ID', group: 'identity' },\n\t{ key: 'uuid', label: 'UUID', group: 'identity' },\n\t{ key: 'uri', label: 'URI', group: 'identity' },\n\t{ key: 'version', label: 'Version', group: 'identity' },\n\t{ key: 'register', label: 'Register', group: 'location' },\n\t{ key: 'schema', label: 'Schema', group: 'location' },\n\t{ key: 'schemaVersion', label: 'Schema version', group: 'location' },\n\t{ key: 'folder', label: 'Folder', group: 'location', format: 'folder' },\n\t{ key: 'owner', label: 'Owner', group: 'ownership' },\n\t{ key: 'organisation', label: 'Organisation', group: 'ownership' },\n\t{ key: 'organization', label: 'Organization', group: 'ownership' },\n\t{ key: 'status', label: 'Status', group: 'lifecycle' },\n\t{ key: 'created', label: 'Created', group: 'lifecycle', format: 'date-time' },\n\t{ key: 'updated', label: 'Updated', group: 'lifecycle', format: 'date-time' },\n\t{ key: 'locked', label: 'Locked', group: 'lifecycle', format: 'lock' },\n\t{ key: 'textRepresentation', label: 'Text Representation', group: 'identity' },\n]\n\n/**\n * The archival constraints, read from the resolved `@self._retention` decision.\n *\n * 🔴 THESE KEYS ARE MDTO CONCEPTS IN ENGLISH, and they changed with\n * openregister#3584: `nomination` became `appraisal`, `period` became\n * `retentionPeriod`, `actionDate` became `disposalDate`, `classification`\n * became `disposalCategory`, and the Archiefwet lifecycle arrived as\n * `recordState` with a derived `immutable`. MDTO supersedes TMLO, so\n * `archiefnominatie` is the superseded spelling of MDTO's `waardering`.\n *\n * They live one level down, under `_retention`, and `include` / `exclude`\n * address them by these same names.\n *\n * Two of the resolver's keys are deliberately not rows here. `immutable` is\n * derived from `recordState` and would only repeat what \"Transferred to\n * archive\" already says, and `annotation` is the raw rule-evaluation object\n * kept for debugging, which would land in the panel as JSON.\n *\n * Empty on an object whose schema declares no archival obligation, and that is\n * a real answer rather than a gap — see `emptyLabel`.\n */\nconst ARCHIVAL_FIELDS = [\n\t{ key: 'appraisal', label: 'Appraisal', group: 'archiving', format: 'appraisal', core: true },\n\t{ key: 'retentionPeriod', label: 'Retention period', group: 'archiving', format: 'duration', core: true },\n\t{ key: 'disposalDate', label: 'Disposal date', group: 'archiving', format: 'date', core: true },\n\t{ key: 'recordState', label: 'Record state', group: 'archiving', format: 'record-state', core: true },\n\t{ key: 'disposalCategory', label: 'Selection list category', group: 'archiving' },\n\t{ key: 'basis', label: 'Basis', group: 'archiving', format: 'basis' },\n\t{ key: 'source', label: 'Source', group: 'archiving' },\n\t// Which revision of the list, and when it was read (openregister#3588).\n\t// The same category carries different retention periods across revisions,\n\t// so a decision that names only the list cannot be defended once it moves.\n\t{ key: 'sourceVersion', label: 'Selection list version', group: 'archiving' },\n\t{ key: 'sourceConsultedAt', label: 'Consulted on', group: 'archiving', format: 'date' },\n\t{ key: 'legalHold', label: 'Legal hold', group: 'archiving', format: 'legal-hold' },\n]\n\n/**\n * The groups, in the order a reader works down them.\n *\n * Identity first (which record is this), then where it lives, who owns it, what\n * state it is in, and finally what happens to it. Archiving last because it is\n * the answer you go looking for rather than the one you scan past.\n */\nconst GROUPS = [\n\t{ key: 'identity', label: 'Identity' },\n\t{ key: 'location', label: 'Location' },\n\t{ key: 'ownership', label: 'Ownership' },\n\t{ key: 'lifecycle', label: 'Lifecycle' },\n\t{ key: 'archiving', label: 'Archiving' },\n]\n\n/**\n * CnObjectMetadataWidget — Read-only metadata display widget.\n *\n * Automatically extracts and formats metadata from an OpenRegister object.\n * Understands both flat objects (where metadata is at the top level) and\n * objects with a `@self` metadata block.\n *\n * Basic usage\n * ```vue\n * <CnObjectMetadataWidget :object-data=\"publication\" />\n * ```\n *\n * With extra items\n * ```vue\n * <CnObjectMetadataWidget\n * title=\"System Info\"\n * :object-data=\"entity\"\n * :extra-items=\"[\n * { label: 'Source', value: entity.source },\n * { label: 'Catalog', value: entity.catalog },\n * ]\" />\n * ```\n *\n * Selective display\n * ```vue\n * <CnObjectMetadataWidget\n * :object-data=\"entity\"\n * :include=\"['id', 'uuid', 'created', 'updated', 'owner']\" />\n * ```\n */\nexport default {\n\tname: 'CnObjectMetadataWidget',\n\n\tcomponents: {\n\t\tCnDetailCard,\n\t\tCnDetailGrid,\n\t},\n\n\tprops: {\n\t\t/** Widget title shown in the card header */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Metadata'),\n\t\t},\n\n\t\t/** Optional MDI icon component for the header */\n\t\ticon: {\n\t\t\ttype: [Object, Function],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The object data containing metadata.\n\t\t * Supports flat objects and objects with `@self` metadata block.\n\t\t * Optional: null renders the empty state (and avoids a required-prop\n\t\t * warning on surfaces that mount before the object loads, e.g. a\n\t\t * `metadata` tab in CnObjectSidebar). Handled internally via\n\t\t * `this.objectData || {}`.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Layout mode for the grid: 'grid' or 'horizontal'.\n\t\t */\n\t\tlayout: {\n\t\t\ttype: String,\n\t\t\tdefault: 'horizontal',\n\t\t},\n\n\t\t/**\n\t\t * Number of grid columns (only for layout='grid').\n\t\t */\n\t\tcolumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\n\t\t/**\n\t\t * Min width for labels in horizontal layout.\n\t\t */\n\t\tlabelWidth: {\n\t\t\ttype: Number,\n\t\t\tdefault: 150,\n\t\t},\n\n\t\t/**\n\t\t * Additional metadata items to display.\n\t\t *\n\t\t * @type {Array<{ label: string, value: string|number }>}\n\t\t */\n\t\textraItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Metadata fields to include (whitelist). If null, all available are shown.\n\t\t *\n\t\t * @type {string[]|null}\n\t\t */\n\t\tinclude: {\n\t\t\ttype: Array,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Metadata fields to exclude.\n\t\t *\n\t\t * @type {string[]}\n\t\t */\n\t\texclude: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the card can be collapsed */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Initial collapsed state */\n\t\tcollapsed: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Group the rows under category headings (Identity, Location,\n\t\t * Ownership, Lifecycle, Archiving) instead of rendering one flat list.\n\t\t *\n\t\t * On by default: a flat list of twenty rows is a wall to read. Pass\n\t\t * `false` for the previous single-grid shape.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tgrouped: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Heading for the items a host supplied through `extraItems`, which\n\t\t * carry no group of their own.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\totherLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Other'),\n\t\t},\n\n\t\t/** Label shown when no metadata available */\n\t\temptyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No metadata available'),\n\t\t},\n\t},\n\n\tcomputed: {\n\t\ticonComponent() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\t/**\n\t\t * Merged metadata source: combines the `@self` block with top-level fields.\n\t\t *\n\t\t * @self fields take priority over top-level for shared keys.\n\t\t */\n\t\tmetadataSource() {\n\t\t\t// objectData is optional (and momentarily null during async loads or\n\t\t\t// when a parent binds a not-yet-resolved object), so guard before\n\t\t\t// reading `@self` to avoid a render-time TypeError.\n\t\t\tconst data = this.objectData || {}\n\t\t\tconst selfBlock = data['@self']\n\n\t\t\t// 🔴 WHEN THERE IS A `@self` BLOCK, IT IS THE ONLY METADATA SOURCE.\n\t\t\t//\n\t\t\t// This used to merge `{ ...data, ...selfBlock }`, which meant any\n\t\t\t// BUSINESS property sharing a name with a metadata field leaked into\n\t\t\t// the metadata list. Measured on a dossiq case: the panel reported\n\t\t\t// `STATUS active` — the case's own workflow status, a schema\n\t\t\t// property — while the page header beside it read `Unknown`, because\n\t\t\t// the two were reading different things and only one of them was\n\t\t\t// metadata. `version`, `owner`, `folder` and `locked` are all\n\t\t\t// perfectly ordinary property names and had the same exposure.\n\t\t\t//\n\t\t\t// A record WITHOUT a `@self` block is a different case: several\n\t\t\t// widget props pass a pre-flattened metadata object, and for those\n\t\t\t// the top level genuinely is the metadata. `id` is carried over\n\t\t\t// either way because the API mirrors it to the top level.\n\t\t\tif (selfBlock && typeof selfBlock === 'object') {\n\t\t\t\tconst carried = {}\n\t\t\t\tif (data.id !== undefined && selfBlock.id === undefined) {\n\t\t\t\t\tcarried.id = data.id\n\t\t\t\t}\n\t\t\t\treturn { ...carried, ...selfBlock }\n\t\t\t}\n\n\t\t\treturn { ...data }\n\t\t},\n\n\t\t/**\n\t\t * The resolved archival decision, or an empty object.\n\t\t *\n\t\t * Read from `@self._retention`, which OpenRegister's render layer fills\n\t\t * by merging the object's stored retention block, its schema's\n\t\t * `x-openregister-archival` evaluation and any legal hold. It is absent\n\t\t * entirely — not empty — on an object with no archival obligation, and\n\t\t * that distinction is deliberate on the server side, so it is preserved\n\t\t * here rather than defaulted into a row of dashes.\n\t\t */\n\t\tarchivalSource() {\n\t\t\tconst block = this.metadataSource._retention\n\t\t\tif (!block || typeof block !== 'object') {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\treturn block\n\t\t},\n\n\t\t/**\n\t\t * The same items, bucketed into the categories a reader scans.\n\t\t *\n\t\t * A group with nothing in it is dropped rather than rendered as an\n\t\t * empty heading — an object with no archival obligation should not\n\t\t * carry an \"Archiving\" heading over a void. `extraItems` carry no\n\t\t * group, so they collect under the host's own heading at the end.\n\t\t */\n\t\tgroupedItems() {\n\t\t\tconst byKey = new Map(GROUPS.map((g) => [g.key, { ...g, label: t('nextcloud-vue', g.label), items: [] }]))\n\t\t\tconst ungrouped = []\n\n\t\t\tfor (const item of this.metadataItems) {\n\t\t\t\tconst bucket = item.group ? byKey.get(item.group) : null\n\t\t\t\tif (bucket) {\n\t\t\t\t\tbucket.items.push(item)\n\t\t\t\t} else {\n\t\t\t\t\tungrouped.push(item)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst groups = [...byKey.values()].filter((g) => g.items.length > 0)\n\t\t\tif (ungrouped.length > 0) {\n\t\t\t\tgroups.push({ key: 'other', label: this.otherLabel, items: ungrouped })\n\t\t\t}\n\n\t\t\treturn groups\n\t\t},\n\n\t\t/**\n\t\t * Build the items array for CnDetailGrid from known metadata fields.\n\t\t */\n\t\tmetadataItems() {\n\t\t\tconst source = this.metadataSource\n\t\t\tconst items = []\n\n\t\t\tfor (const def of METADATA_FIELDS) {\n\t\t\t\t// Filter by include/exclude\n\t\t\t\tif (this.include && !this.include.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.exclude.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst raw = source[def.key]\n\t\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\titems.push({\n\t\t\t\t\t// Translated at use, not at import: the bundles register\n\t\t\t\t\t// after this module loads, and a label resolved at import\n\t\t\t\t\t// time would stay English for every reader.\n\t\t\t\t\tlabel: t('nextcloud-vue', def.label),\n\t\t\t\t\tvalue: this.formatMetadataValue(raw, def),\n\t\t\t\t\tgroup: def.group,\n\t\t\t\t\thref: this.hrefFor(raw, def),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// The archival group, read one level down from `@self._retention`.\n\t\t\t// Appended after the identity fields rather than interleaved: what\n\t\t\t// happens to a record and when is a question of its own, and a\n\t\t\t// records officer reads the group, not one line of it.\n\t\t\t// nextcloud-vue#1062. When the object HAS an archival decision, an\n\t\t\t// absent core fact is itself the answer: a records officer reading\n\t\t\t// \"Disposal date: -\" learns there is no date yet, while a missing row\n\t\t\t// reads as a panel that never looked. So the four MDTO core rows\n\t\t\t// stay, blank, and so does any key a host named in `include`, which\n\t\t\t// is already the host saying \"this row matters to me\". Optional\n\t\t\t// provenance rows still only appear when they carry something.\n\t\t\t//\n\t\t\t// An object with NO decision keeps an empty Archiving group, which\n\t\t\t// the grouping drops entirely: \"no archival obligation\" and \"an\n\t\t\t// obligation with a gap\" are different answers and must look it.\n\t\t\tconst archival = this.archivalSource\n\t\t\tconst hasDecision = Object.keys(archival).length > 0\n\t\t\tfor (const def of ARCHIVAL_FIELDS) {\n\t\t\t\tif (this.include && !this.include.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.exclude.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst raw = archival[def.key]\n\t\t\t\tconst absent = raw === undefined || raw === null\n\t\t\t\tif (absent && !(hasDecision && (def.core || this.include))) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\titems.push({\n\t\t\t\t\tlabel: t('nextcloud-vue', def.label),\n\t\t\t\t\tvalue: this.formatMetadataValue(raw, def),\n\t\t\t\t\tgroup: def.group,\n\t\t\t\t\tempty: absent,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Append extra items\n\t\t\tfor (const item of this.extraItems) {\n\t\t\t\titems.push(item)\n\t\t\t}\n\n\t\t\treturn items\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Format a metadata value for display.\n\t\t *\n\t\t * @param {unknown} value - The raw metadata value.\n\t\t * @param {object} def - The metadata field definition (format, label, etc.).\n\t\t */\n\t\tformatMetadataValue(value, def) {\n\t\t\tif (value === null || value === undefined) {\n\t\t\t\treturn '-'\n\t\t\t}\n\n\t\t\t// The lock is an object (`{ user, displayName, expiresAt }`) and used\n\t\t\t// to reach the panel as raw JSON, which reads as debug output rather\n\t\t\t// than as the one fact that matters: who is holding this, and until\n\t\t\t// when.\n\t\t\tif (def.format === 'lock') {\n\t\t\t\treturn this.formatLock(value)\n\t\t\t}\n\n\t\t\t// Archival formats. Each turns a stored code into the phrase an\n\t\t\t// archivist would say, and each falls back to the raw value rather\n\t\t\t// than hiding a code it has not been taught — an unrecognised\n\t\t\t// appraisal is still a records obligation.\n\t\t\tif (def.format === 'appraisal') {\n\t\t\t\treturn this.formatAppraisal(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'record-state') {\n\t\t\t\treturn this.formatRecordState(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'duration') {\n\t\t\t\treturn this.formatDuration(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'basis') {\n\t\t\t\treturn this.formatBasis(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'legal-hold') {\n\t\t\t\treturn this.formatLegalHold(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'date') {\n\t\t\t\tconst date = new Date(value)\n\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t\treturn date.toLocaleDateString(undefined, {\n\t\t\t\t\tday: '2-digit',\n\t\t\t\t\tmonth: '2-digit',\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Date-time formatting\n\t\t\tif (def.format === 'date-time') {\n\t\t\t\ttry {\n\t\t\t\t\tconst date = new Date(value)\n\t\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\t\treturn String(value)\n\t\t\t\t\t}\n\t\t\t\t\treturn date.toLocaleDateString(undefined, {\n\t\t\t\t\t\tday: '2-digit',\n\t\t\t\t\t\tmonth: '2-digit',\n\t\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\t}) + ', ' + date.toLocaleTimeString(undefined, {\n\t\t\t\t\t\thour: '2-digit',\n\t\t\t\t\t\tminute: '2-digit',\n\t\t\t\t\t\tsecond: '2-digit',\n\t\t\t\t\t})\n\t\t\t\t} catch {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Booleans\n\t\t\tif (typeof value === 'boolean') {\n\t\t\t\treturn value ? 'Yes' : 'No'\n\t\t\t}\n\n\t\t\t// Arrays\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.length > 0 ? value.join(', ') : '-'\n\t\t\t}\n\n\t\t\t// Objects — show as JSON snippet\n\t\t\tif (typeof value === 'object') {\n\t\t\t\treturn JSON.stringify(value)\n\t\t\t}\n\n\t\t\treturn String(value)\n\t\t},\n\n\t\t/**\n\t\t * Render a lock as a sentence rather than as its JSON.\n\t\t *\n\t\t * @param {object} lock - The `@self.locked` payload.\n\t\t * @return {string} Who holds it, and until when.\n\t\t */\n\t\tformatLock(lock) {\n\t\t\tif (typeof lock !== 'object') {\n\t\t\t\treturn String(lock)\n\t\t\t}\n\t\t\tconst holder = lock.displayName || lock.user\n\t\t\tconst until = lock.expiresAt ? new Date(lock.expiresAt) : null\n\t\t\tconst hasUntil = until && !Number.isNaN(until.getTime())\n\n\t\t\tif (holder && hasUntil) {\n\t\t\t\treturn t('nextcloud-vue', 'Locked by {user} until {date}', {\n\t\t\t\t\tuser: holder,\n\t\t\t\t\tdate: until.toLocaleString(),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif (holder) {\n\t\t\t\treturn t('nextcloud-vue', 'Locked by {user}', { user: holder })\n\t\t\t}\n\n\t\t\treturn t('nextcloud-vue', 'Locked')\n\t\t},\n\n\t\t/**\n\t\t * Name what is going to happen to the record.\n\t\t *\n\t\t * @param {string} value - The stored appraisal.\n\t\t * @return {string} The phrase, or the raw code when unrecognised.\n\t\t */\n\t\tformatAppraisal(value) {\n\t\t\tconst known = {\n\t\t\t\tretain_permanently: t('nextcloud-vue', 'Keep permanently'),\n\t\t\t\tdestroy: t('nextcloud-vue', 'Destroy'),\n\t\t\t\tnot_yet_determined: t('nextcloud-vue', 'Not yet determined'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * Name the record's place in the Archiefwet lifecycle.\n\t\t *\n\t\t * @param {string} value - The record state.\n\t\t * @return {string} The phrase, or the raw value.\n\t\t */\n\t\tformatRecordState(value) {\n\t\t\tconst known = {\n\t\t\t\tactive: t('nextcloud-vue', 'Active'),\n\t\t\t\tsemi_static: t('nextcloud-vue', 'Semi-static'),\n\t\t\t\ttransferred: t('nextcloud-vue', 'Transferred to archive'),\n\t\t\t\tdestroyed: t('nextcloud-vue', 'Destroyed'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * A Files deep-link for a folder held as a numeric node id.\n\t\t *\n\t\t * `@self.folder` is a string that is USUALLY a node id and sometimes a\n\t\t * legacy path, so only the digit form gets a link — a path would produce\n\t\t * a URL that 404s, which is worse than plain text.\n\t\t *\n\t\t * @param {unknown} raw - The raw metadata value.\n\t\t * @param {object} def - The field definition.\n\t\t * @return {string|null} The href, or null when it is not linkable.\n\t\t */\n\t\threfFor(raw, def) {\n\t\t\tif (def.format !== 'folder') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst id = String(raw).trim()\n\t\t\tif (!/^\\d+$/.test(id)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn generateUrl('/apps/files/?fileid={id}&opendetails=true', { id })\n\t\t},\n\n\t\t/**\n\t\t * Turn an ISO-8601 duration into something readable.\n\t\t *\n\t\t * Deliberately handles only the whole-year / whole-month / whole-day\n\t\t * forms a retention period is actually written in (`P10Y`, `P6M`,\n\t\t * `P30D`). Anything else is returned as-is rather than parsed\n\t\t * half-correctly, because a retention period rendered wrong is worse\n\t\t * than one rendered raw.\n\t\t *\n\t\t * @param {string} value - The ISO-8601 duration.\n\t\t * @return {string} The readable period, or the raw duration.\n\t\t */\n\t\tformatDuration(value) {\n\t\t\tconst match = /^P(\\d+)([YMD])$/.exec(String(value))\n\t\t\tif (!match) {\n\t\t\t\treturn String(value)\n\t\t\t}\n\n\t\t\tconst amount = Number(match[1])\n\t\t\tif (match[2] === 'Y') {\n\t\t\t\treturn n('nextcloud-vue', '%n year', '%n years', amount)\n\t\t\t}\n\t\t\tif (match[2] === 'M') {\n\t\t\t\treturn n('nextcloud-vue', '%n month', '%n months', amount)\n\t\t\t}\n\t\t\treturn n('nextcloud-vue', '%n day', '%n days', amount)\n\t\t},\n\n\t\t/**\n\t\t * Say on whose authority the retention period rests.\n\t\t *\n\t\t * @param {string} value - The basis code.\n\t\t * @return {string} The phrase, or the raw code.\n\t\t */\n\t\tformatBasis(value) {\n\t\t\tconst known = {\n\t\t\t\tselection_list: t('nextcloud-vue', 'Selection list'),\n\t\t\t\t// Its own answer, not a variant of \"schema\": the schema expected\n\t\t\t\t// a selection list and none was consulted, which an operator who\n\t\t\t\t// believes one is configured needs to be told.\n\t\t\t\tselection_list_not_consulted: t('nextcloud-vue', 'Selection list not consulted'),\n\t\t\t\tschema: t('nextcloud-vue', 'Schema archive settings'),\n\t\t\t\tschema_annotation: t('nextcloud-vue', 'Schema archival annotation'),\n\t\t\t\ttmlo: t('nextcloud-vue', 'Record archival metadata'),\n\t\t\t\trecord: t('nextcloud-vue', 'Recorded on the object'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * Render the legal-hold state.\n\t\t *\n\t\t * A released hold still reports itself: \"held once and released\" is a\n\t\t * different fact from \"never held\", and an archivist reads the\n\t\t * difference.\n\t\t *\n\t\t * @param {object} hold - The resolved hold state.\n\t\t * @return {string} The hold sentence.\n\t\t */\n\t\tformatLegalHold(hold) {\n\t\t\tif (typeof hold !== 'object') {\n\t\t\t\treturn String(hold)\n\t\t\t}\n\n\t\t\tif (hold.active) {\n\t\t\t\tif (hold.reason) {\n\t\t\t\t\treturn t('nextcloud-vue', 'On hold: {reason}', { reason: hold.reason })\n\t\t\t\t}\n\t\t\t\treturn t('nextcloud-vue', 'On hold')\n\t\t\t}\n\n\t\t\tif (hold.releasedCount) {\n\t\t\t\treturn n('nextcloud-vue', 'Released, %n earlier hold', 'Released, %n earlier holds', hold.releasedCount)\n\t\t\t}\n\n\t\t\treturn t('nextcloud-vue', 'No hold')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* Group headings. Quiet enough that they organise without competing with the\n values they sit over — a category label is a signpost, not content. */\n.cn-object-metadata__group + .cn-object-metadata__group {\n\tmargin-top: calc(3 * var(--default-grid-baseline, 4px));\n}\n\n.cn-object-metadata__group-title {\n\tmargin: 0 0 calc(0.5 * var(--default-grid-baseline, 4px));\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* Override CnDetailGrid item styling for a compact table-like appearance */\n:deep(.cn-detail-grid__item) {\n\tbackground: none;\n\tborder-radius: 0;\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding: calc(1.5 * var(--default-grid-baseline, 4px)) 0;\n}\n\n:deep(.cn-detail-grid__item:last-child) {\n\tborder-bottom: none;\n}\n\n:deep(.cn-detail-grid--horizontal) {\n\tgap: 0;\n}\n\n:deep(.cn-detail-grid__label) {\n\tfont-size: 0.8em;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.02em;\n}\n\n:deep(.cn-detail-grid__value) {\n\tfont-size: 0.9em;\n\tword-break: break-all;\n\tmargin: 0;\n}\n</style>\n"],"names":["CnDetailCard","CnDetailGrid","t","n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnObjectMetadataWidget.vue2.js","sources":["../../../../src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue"],"sourcesContent":["<!--\n CnObjectMetadataWidget — Read-only metadata display widget.\n\n Shows system/internal metadata for an OpenRegister object in a horizontal\n label-value grid. Automatically extracts known metadata fields from the object\n (id, uuid, uri, register, schema, created, updated, owner, etc.).\n\n Not editable — purely informational. Wraps CnDetailCard + CnDetailGrid.\n-->\n<template>\n\t<CnDetailCard :title=\"title\"\n\t\t:icon=\"iconComponent\"\n\t\t:collapsible=\"collapsible\"\n\t\t:collapsed=\"collapsed\">\n\t\t<template #actions>\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Grouped: one grid per category, each under its own heading. A flat\n\t\t list of twenty rows is a wall; Identity / Location / Ownership /\n\t\t Lifecycle / Archiving is how a reader actually looks for one fact.\n\t\t `grouped: false` restores the single flat grid for hosts that want\n\t\t the old shape. -->\n\t\t<template v-if=\"grouped && groupedItems.length > 0\">\n\t\t\t<div\n\t\t\t\tv-for=\"group in groupedItems\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-object-metadata__group\">\n\t\t\t\t<h4 class=\"cn-object-metadata__group-title\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</h4>\n\t\t\t\t<CnDetailGrid\n\t\t\t\t\t:items=\"group.items\"\n\t\t\t\t\t:layout=\"layout\"\n\t\t\t\t\t:columns=\"columns\"\n\t\t\t\t\t:labelWidth=\"labelWidth\"\n\t\t\t\t\t:accent=\"false\"\n\t\t\t\t\t:emptyLabel=\"emptyLabel\" />\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- One flat grid: either because grouping is off, or because there is\n\t\t nothing to group and CnDetailGrid already owns the empty state. -->\n\t\t<CnDetailGrid\n\t\t\tv-else\n\t\t\t:items=\"metadataItems\"\n\t\t\t:layout=\"layout\"\n\t\t\t:columns=\"columns\"\n\t\t\t:labelWidth=\"labelWidth\"\n\t\t\t:accent=\"false\"\n\t\t\t:emptyLabel=\"emptyLabel\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { userLocale } from '../../utils/userLocale.js'\nimport { CnDetailCard } from '../CnDetailCard/index.js'\nimport { CnDetailGrid } from '../CnDetailGrid/index.js'\n\n/**\n * Known metadata fields and their labels.\n * These are the standard fields from OpenRegister's `@self` / system fields.\n */\nconst METADATA_FIELDS = [\n\t{ key: 'id', label: 'ID', group: 'identity' },\n\t{ key: 'uuid', label: 'UUID', group: 'identity' },\n\t{ key: 'uri', label: 'URI', group: 'identity' },\n\t{ key: 'version', label: 'Version', group: 'identity' },\n\t{ key: 'register', label: 'Register', group: 'location' },\n\t{ key: 'schema', label: 'Schema', group: 'location' },\n\t{ key: 'schemaVersion', label: 'Schema version', group: 'location' },\n\t{ key: 'folder', label: 'Folder', group: 'location', format: 'folder' },\n\t{ key: 'owner', label: 'Owner', group: 'ownership' },\n\t{ key: 'organisation', label: 'Organisation', group: 'ownership' },\n\t{ key: 'organization', label: 'Organization', group: 'ownership' },\n\t{ key: 'status', label: 'Status', group: 'lifecycle' },\n\t{ key: 'created', label: 'Created', group: 'lifecycle', format: 'date-time' },\n\t{ key: 'updated', label: 'Updated', group: 'lifecycle', format: 'date-time' },\n\t{ key: 'locked', label: 'Locked', group: 'lifecycle', format: 'lock' },\n\t{ key: 'textRepresentation', label: 'Text Representation', group: 'identity' },\n]\n\n/**\n * The archival constraints, read from the resolved `@self._retention` decision.\n *\n * 🔴 THESE KEYS ARE MDTO CONCEPTS IN ENGLISH, and they changed with\n * openregister#3584: `nomination` became `appraisal`, `period` became\n * `retentionPeriod`, `actionDate` became `disposalDate`, `classification`\n * became `disposalCategory`, and the Archiefwet lifecycle arrived as\n * `recordState` with a derived `immutable`. MDTO supersedes TMLO, so\n * `archiefnominatie` is the superseded spelling of MDTO's `waardering`.\n *\n * They live one level down, under `_retention`, and `include` / `exclude`\n * address them by these same names.\n *\n * Two of the resolver's keys are deliberately not rows here. `immutable` is\n * derived from `recordState` and would only repeat what \"Transferred to\n * archive\" already says, and `annotation` is the raw rule-evaluation object\n * kept for debugging, which would land in the panel as JSON.\n *\n * Empty on an object whose schema declares no archival obligation, and that is\n * a real answer rather than a gap — see `emptyLabel`.\n */\nconst ARCHIVAL_FIELDS = [\n\t{ key: 'appraisal', label: 'Appraisal', group: 'archiving', format: 'appraisal', core: true },\n\t{ key: 'retentionPeriod', label: 'Retention period', group: 'archiving', format: 'duration', core: true },\n\t{ key: 'disposalDate', label: 'Disposal date', group: 'archiving', format: 'date', core: true },\n\t{ key: 'recordState', label: 'Record state', group: 'archiving', format: 'record-state', core: true },\n\t{ key: 'disposalCategory', label: 'Selection list category', group: 'archiving' },\n\t{ key: 'basis', label: 'Basis', group: 'archiving', format: 'basis' },\n\t{ key: 'source', label: 'Source', group: 'archiving' },\n\t// Which revision of the list, and when it was read (openregister#3588).\n\t// The same category carries different retention periods across revisions,\n\t// so a decision that names only the list cannot be defended once it moves.\n\t{ key: 'sourceVersion', label: 'Selection list version', group: 'archiving' },\n\t{ key: 'sourceConsultedAt', label: 'Consulted on', group: 'archiving', format: 'date' },\n\t{ key: 'legalHold', label: 'Legal hold', group: 'archiving', format: 'legal-hold' },\n]\n\n/**\n * The groups, in the order a reader works down them.\n *\n * Identity first (which record is this), then where it lives, who owns it, what\n * state it is in, and finally what happens to it. Archiving last because it is\n * the answer you go looking for rather than the one you scan past.\n */\nconst GROUPS = [\n\t{ key: 'identity', label: 'Identity' },\n\t{ key: 'location', label: 'Location' },\n\t{ key: 'ownership', label: 'Ownership' },\n\t{ key: 'lifecycle', label: 'Lifecycle' },\n\t{ key: 'archiving', label: 'Archiving' },\n]\n\n/**\n * CnObjectMetadataWidget — Read-only metadata display widget.\n *\n * Automatically extracts and formats metadata from an OpenRegister object.\n * Understands both flat objects (where metadata is at the top level) and\n * objects with a `@self` metadata block.\n *\n * Basic usage\n * ```vue\n * <CnObjectMetadataWidget :object-data=\"publication\" />\n * ```\n *\n * With extra items\n * ```vue\n * <CnObjectMetadataWidget\n * title=\"System Info\"\n * :object-data=\"entity\"\n * :extra-items=\"[\n * { label: 'Source', value: entity.source },\n * { label: 'Catalog', value: entity.catalog },\n * ]\" />\n * ```\n *\n * Selective display\n * ```vue\n * <CnObjectMetadataWidget\n * :object-data=\"entity\"\n * :include=\"['id', 'uuid', 'created', 'updated', 'owner']\" />\n * ```\n */\nexport default {\n\tname: 'CnObjectMetadataWidget',\n\n\tcomponents: {\n\t\tCnDetailCard,\n\t\tCnDetailGrid,\n\t},\n\n\tprops: {\n\t\t/** Widget title shown in the card header */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Metadata'),\n\t\t},\n\n\t\t/** Optional MDI icon component for the header */\n\t\ticon: {\n\t\t\ttype: [Object, Function],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The object data containing metadata.\n\t\t * Supports flat objects and objects with `@self` metadata block.\n\t\t * Optional: null renders the empty state (and avoids a required-prop\n\t\t * warning on surfaces that mount before the object loads, e.g. a\n\t\t * `metadata` tab in CnObjectSidebar). Handled internally via\n\t\t * `this.objectData || {}`.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Layout mode for the grid: 'grid' or 'horizontal'.\n\t\t */\n\t\tlayout: {\n\t\t\ttype: String,\n\t\t\tdefault: 'horizontal',\n\t\t},\n\n\t\t/**\n\t\t * Number of grid columns (only for layout='grid').\n\t\t */\n\t\tcolumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\n\t\t/**\n\t\t * Min width for labels in horizontal layout.\n\t\t */\n\t\tlabelWidth: {\n\t\t\ttype: Number,\n\t\t\tdefault: 150,\n\t\t},\n\n\t\t/**\n\t\t * Additional metadata items to display.\n\t\t *\n\t\t * @type {Array<{ label: string, value: string|number }>}\n\t\t */\n\t\textraItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Metadata fields to include (whitelist). If null, all available are shown.\n\t\t *\n\t\t * @type {string[]|null}\n\t\t */\n\t\tinclude: {\n\t\t\ttype: Array,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Metadata fields to exclude.\n\t\t *\n\t\t * @type {string[]}\n\t\t */\n\t\texclude: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the card can be collapsed */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Initial collapsed state */\n\t\tcollapsed: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Group the rows under category headings (Identity, Location,\n\t\t * Ownership, Lifecycle, Archiving) instead of rendering one flat list.\n\t\t *\n\t\t * On by default: a flat list of twenty rows is a wall to read. Pass\n\t\t * `false` for the previous single-grid shape.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tgrouped: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Heading for the items a host supplied through `extraItems`, which\n\t\t * carry no group of their own.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\totherLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Other'),\n\t\t},\n\n\t\t/** Label shown when no metadata available */\n\t\temptyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No metadata available'),\n\t\t},\n\t},\n\n\tcomputed: {\n\t\ticonComponent() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\t/**\n\t\t * Merged metadata source: combines the `@self` block with top-level fields.\n\t\t *\n\t\t * @self fields take priority over top-level for shared keys.\n\t\t */\n\t\tmetadataSource() {\n\t\t\t// objectData is optional (and momentarily null during async loads or\n\t\t\t// when a parent binds a not-yet-resolved object), so guard before\n\t\t\t// reading `@self` to avoid a render-time TypeError.\n\t\t\tconst data = this.objectData || {}\n\t\t\tconst selfBlock = data['@self']\n\n\t\t\t// 🔴 WHEN THERE IS A `@self` BLOCK, IT IS THE ONLY METADATA SOURCE.\n\t\t\t//\n\t\t\t// This used to merge `{ ...data, ...selfBlock }`, which meant any\n\t\t\t// BUSINESS property sharing a name with a metadata field leaked into\n\t\t\t// the metadata list. Measured on a dossiq case: the panel reported\n\t\t\t// `STATUS active` — the case's own workflow status, a schema\n\t\t\t// property — while the page header beside it read `Unknown`, because\n\t\t\t// the two were reading different things and only one of them was\n\t\t\t// metadata. `version`, `owner`, `folder` and `locked` are all\n\t\t\t// perfectly ordinary property names and had the same exposure.\n\t\t\t//\n\t\t\t// A record WITHOUT a `@self` block is a different case: several\n\t\t\t// widget props pass a pre-flattened metadata object, and for those\n\t\t\t// the top level genuinely is the metadata. `id` is carried over\n\t\t\t// either way because the API mirrors it to the top level.\n\t\t\tif (selfBlock && typeof selfBlock === 'object') {\n\t\t\t\tconst carried = {}\n\t\t\t\tif (data.id !== undefined && selfBlock.id === undefined) {\n\t\t\t\t\tcarried.id = data.id\n\t\t\t\t}\n\t\t\t\treturn { ...carried, ...selfBlock }\n\t\t\t}\n\n\t\t\treturn { ...data }\n\t\t},\n\n\t\t/**\n\t\t * The resolved archival decision, or an empty object.\n\t\t *\n\t\t * Read from `@self._retention`, which OpenRegister's render layer fills\n\t\t * by merging the object's stored retention block, its schema's\n\t\t * `x-openregister-archival` evaluation and any legal hold. It is absent\n\t\t * entirely — not empty — on an object with no archival obligation, and\n\t\t * that distinction is deliberate on the server side, so it is preserved\n\t\t * here rather than defaulted into a row of dashes.\n\t\t */\n\t\tarchivalSource() {\n\t\t\tconst block = this.metadataSource._retention\n\t\t\tif (!block || typeof block !== 'object') {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\treturn block\n\t\t},\n\n\t\t/**\n\t\t * The same items, bucketed into the categories a reader scans.\n\t\t *\n\t\t * A group with nothing in it is dropped rather than rendered as an\n\t\t * empty heading — an object with no archival obligation should not\n\t\t * carry an \"Archiving\" heading over a void. `extraItems` carry no\n\t\t * group, so they collect under the host's own heading at the end.\n\t\t */\n\t\tgroupedItems() {\n\t\t\tconst byKey = new Map(GROUPS.map((g) => [g.key, { ...g, label: t('nextcloud-vue', g.label), items: [] }]))\n\t\t\tconst ungrouped = []\n\n\t\t\tfor (const item of this.metadataItems) {\n\t\t\t\tconst bucket = item.group ? byKey.get(item.group) : null\n\t\t\t\tif (bucket) {\n\t\t\t\t\tbucket.items.push(item)\n\t\t\t\t} else {\n\t\t\t\t\tungrouped.push(item)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst groups = [...byKey.values()].filter((g) => g.items.length > 0)\n\t\t\tif (ungrouped.length > 0) {\n\t\t\t\tgroups.push({ key: 'other', label: this.otherLabel, items: ungrouped })\n\t\t\t}\n\n\t\t\treturn groups\n\t\t},\n\n\t\t/**\n\t\t * Build the items array for CnDetailGrid from known metadata fields.\n\t\t */\n\t\tmetadataItems() {\n\t\t\tconst source = this.metadataSource\n\t\t\tconst items = []\n\n\t\t\tfor (const def of METADATA_FIELDS) {\n\t\t\t\t// Filter by include/exclude\n\t\t\t\tif (this.include && !this.include.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.exclude.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst raw = source[def.key]\n\t\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\titems.push({\n\t\t\t\t\t// Translated at use, not at import: the bundles register\n\t\t\t\t\t// after this module loads, and a label resolved at import\n\t\t\t\t\t// time would stay English for every reader.\n\t\t\t\t\tlabel: t('nextcloud-vue', def.label),\n\t\t\t\t\tvalue: this.formatMetadataValue(raw, def),\n\t\t\t\t\tgroup: def.group,\n\t\t\t\t\thref: this.hrefFor(raw, def),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// The archival group, read one level down from `@self._retention`.\n\t\t\t// Appended after the identity fields rather than interleaved: what\n\t\t\t// happens to a record and when is a question of its own, and a\n\t\t\t// records officer reads the group, not one line of it.\n\t\t\t// nextcloud-vue#1062. When the object HAS an archival decision, an\n\t\t\t// absent core fact is itself the answer: a records officer reading\n\t\t\t// \"Disposal date: -\" learns there is no date yet, while a missing row\n\t\t\t// reads as a panel that never looked. So the four MDTO core rows\n\t\t\t// stay, blank, and so does any key a host named in `include`, which\n\t\t\t// is already the host saying \"this row matters to me\". Optional\n\t\t\t// provenance rows still only appear when they carry something.\n\t\t\t//\n\t\t\t// An object with NO decision keeps an empty Archiving group, which\n\t\t\t// the grouping drops entirely: \"no archival obligation\" and \"an\n\t\t\t// obligation with a gap\" are different answers and must look it.\n\t\t\tconst archival = this.archivalSource\n\t\t\tconst hasDecision = Object.keys(archival).length > 0\n\t\t\tfor (const def of ARCHIVAL_FIELDS) {\n\t\t\t\tif (this.include && !this.include.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.exclude.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst raw = archival[def.key]\n\t\t\t\tconst absent = raw === undefined || raw === null\n\t\t\t\tif (absent && !(hasDecision && (def.core || this.include))) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\titems.push({\n\t\t\t\t\tlabel: t('nextcloud-vue', def.label),\n\t\t\t\t\tvalue: this.formatMetadataValue(raw, def),\n\t\t\t\t\tgroup: def.group,\n\t\t\t\t\tempty: absent,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Append extra items\n\t\t\tfor (const item of this.extraItems) {\n\t\t\t\titems.push(item)\n\t\t\t}\n\n\t\t\treturn items\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Format a metadata value for display.\n\t\t *\n\t\t * @param {unknown} value - The raw metadata value.\n\t\t * @param {object} def - The metadata field definition (format, label, etc.).\n\t\t */\n\t\tformatMetadataValue(value, def) {\n\t\t\tif (value === null || value === undefined) {\n\t\t\t\treturn '-'\n\t\t\t}\n\n\t\t\t// The lock is an object (`{ user, displayName, expiresAt }`) and used\n\t\t\t// to reach the panel as raw JSON, which reads as debug output rather\n\t\t\t// than as the one fact that matters: who is holding this, and until\n\t\t\t// when.\n\t\t\tif (def.format === 'lock') {\n\t\t\t\treturn this.formatLock(value)\n\t\t\t}\n\n\t\t\t// Archival formats. Each turns a stored code into the phrase an\n\t\t\t// archivist would say, and each falls back to the raw value rather\n\t\t\t// than hiding a code it has not been taught — an unrecognised\n\t\t\t// appraisal is still a records obligation.\n\t\t\tif (def.format === 'appraisal') {\n\t\t\t\treturn this.formatAppraisal(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'record-state') {\n\t\t\t\treturn this.formatRecordState(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'duration') {\n\t\t\t\treturn this.formatDuration(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'basis') {\n\t\t\t\treturn this.formatBasis(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'legal-hold') {\n\t\t\t\treturn this.formatLegalHold(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'date') {\n\t\t\t\tconst date = new Date(value)\n\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t\treturn date.toLocaleDateString(userLocale(), {\n\t\t\t\t\tday: '2-digit',\n\t\t\t\t\tmonth: '2-digit',\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Date-time formatting\n\t\t\tif (def.format === 'date-time') {\n\t\t\t\ttry {\n\t\t\t\t\tconst date = new Date(value)\n\t\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\t\treturn String(value)\n\t\t\t\t\t}\n\t\t\t\t\treturn date.toLocaleDateString(userLocale(), {\n\t\t\t\t\t\tday: '2-digit',\n\t\t\t\t\t\tmonth: '2-digit',\n\t\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\t}) + ', ' + date.toLocaleTimeString(userLocale(), {\n\t\t\t\t\t\thour: '2-digit',\n\t\t\t\t\t\tminute: '2-digit',\n\t\t\t\t\t\tsecond: '2-digit',\n\t\t\t\t\t})\n\t\t\t\t} catch {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Booleans\n\t\t\tif (typeof value === 'boolean') {\n\t\t\t\treturn value ? 'Yes' : 'No'\n\t\t\t}\n\n\t\t\t// Arrays\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.length > 0 ? value.join(', ') : '-'\n\t\t\t}\n\n\t\t\t// Objects — show as JSON snippet\n\t\t\tif (typeof value === 'object') {\n\t\t\t\treturn JSON.stringify(value)\n\t\t\t}\n\n\t\t\treturn String(value)\n\t\t},\n\n\t\t/**\n\t\t * Render a lock as a sentence rather than as its JSON.\n\t\t *\n\t\t * @param {object} lock - The `@self.locked` payload.\n\t\t * @return {string} Who holds it, and until when.\n\t\t */\n\t\tformatLock(lock) {\n\t\t\tif (typeof lock !== 'object') {\n\t\t\t\treturn String(lock)\n\t\t\t}\n\t\t\tconst holder = lock.displayName || lock.user\n\t\t\tconst until = lock.expiresAt ? new Date(lock.expiresAt) : null\n\t\t\tconst hasUntil = until && !Number.isNaN(until.getTime())\n\n\t\t\tif (holder && hasUntil) {\n\t\t\t\treturn t('nextcloud-vue', 'Locked by {user} until {date}', {\n\t\t\t\t\tuser: holder,\n\t\t\t\t\tdate: until.toLocaleString(userLocale()),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif (holder) {\n\t\t\t\treturn t('nextcloud-vue', 'Locked by {user}', { user: holder })\n\t\t\t}\n\n\t\t\treturn t('nextcloud-vue', 'Locked')\n\t\t},\n\n\t\t/**\n\t\t * Name what is going to happen to the record.\n\t\t *\n\t\t * @param {string} value - The stored appraisal.\n\t\t * @return {string} The phrase, or the raw code when unrecognised.\n\t\t */\n\t\tformatAppraisal(value) {\n\t\t\tconst known = {\n\t\t\t\tretain_permanently: t('nextcloud-vue', 'Keep permanently'),\n\t\t\t\tdestroy: t('nextcloud-vue', 'Destroy'),\n\t\t\t\tnot_yet_determined: t('nextcloud-vue', 'Not yet determined'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * Name the record's place in the Archiefwet lifecycle.\n\t\t *\n\t\t * @param {string} value - The record state.\n\t\t * @return {string} The phrase, or the raw value.\n\t\t */\n\t\tformatRecordState(value) {\n\t\t\tconst known = {\n\t\t\t\tactive: t('nextcloud-vue', 'Active'),\n\t\t\t\tsemi_static: t('nextcloud-vue', 'Semi-static'),\n\t\t\t\ttransferred: t('nextcloud-vue', 'Transferred to archive'),\n\t\t\t\tdestroyed: t('nextcloud-vue', 'Destroyed'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * A Files deep-link for a folder held as a numeric node id.\n\t\t *\n\t\t * `@self.folder` is a string that is USUALLY a node id and sometimes a\n\t\t * legacy path, so only the digit form gets a link — a path would produce\n\t\t * a URL that 404s, which is worse than plain text.\n\t\t *\n\t\t * @param {unknown} raw - The raw metadata value.\n\t\t * @param {object} def - The field definition.\n\t\t * @return {string|null} The href, or null when it is not linkable.\n\t\t */\n\t\threfFor(raw, def) {\n\t\t\tif (def.format !== 'folder') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst id = String(raw).trim()\n\t\t\tif (!/^\\d+$/.test(id)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn generateUrl('/apps/files/?fileid={id}&opendetails=true', { id })\n\t\t},\n\n\t\t/**\n\t\t * Turn an ISO-8601 duration into something readable.\n\t\t *\n\t\t * Deliberately handles only the whole-year / whole-month / whole-day\n\t\t * forms a retention period is actually written in (`P10Y`, `P6M`,\n\t\t * `P30D`). Anything else is returned as-is rather than parsed\n\t\t * half-correctly, because a retention period rendered wrong is worse\n\t\t * than one rendered raw.\n\t\t *\n\t\t * @param {string} value - The ISO-8601 duration.\n\t\t * @return {string} The readable period, or the raw duration.\n\t\t */\n\t\tformatDuration(value) {\n\t\t\tconst match = /^P(\\d+)([YMD])$/.exec(String(value))\n\t\t\tif (!match) {\n\t\t\t\treturn String(value)\n\t\t\t}\n\n\t\t\tconst amount = Number(match[1])\n\t\t\tif (match[2] === 'Y') {\n\t\t\t\treturn n('nextcloud-vue', '%n year', '%n years', amount)\n\t\t\t}\n\t\t\tif (match[2] === 'M') {\n\t\t\t\treturn n('nextcloud-vue', '%n month', '%n months', amount)\n\t\t\t}\n\t\t\treturn n('nextcloud-vue', '%n day', '%n days', amount)\n\t\t},\n\n\t\t/**\n\t\t * Say on whose authority the retention period rests.\n\t\t *\n\t\t * @param {string} value - The basis code.\n\t\t * @return {string} The phrase, or the raw code.\n\t\t */\n\t\tformatBasis(value) {\n\t\t\tconst known = {\n\t\t\t\tselection_list: t('nextcloud-vue', 'Selection list'),\n\t\t\t\t// Its own answer, not a variant of \"schema\": the schema expected\n\t\t\t\t// a selection list and none was consulted, which an operator who\n\t\t\t\t// believes one is configured needs to be told.\n\t\t\t\tselection_list_not_consulted: t('nextcloud-vue', 'Selection list not consulted'),\n\t\t\t\tschema: t('nextcloud-vue', 'Schema archive settings'),\n\t\t\t\tschema_annotation: t('nextcloud-vue', 'Schema archival annotation'),\n\t\t\t\ttmlo: t('nextcloud-vue', 'Record archival metadata'),\n\t\t\t\trecord: t('nextcloud-vue', 'Recorded on the object'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * Render the legal-hold state.\n\t\t *\n\t\t * A released hold still reports itself: \"held once and released\" is a\n\t\t * different fact from \"never held\", and an archivist reads the\n\t\t * difference.\n\t\t *\n\t\t * @param {object} hold - The resolved hold state.\n\t\t * @return {string} The hold sentence.\n\t\t */\n\t\tformatLegalHold(hold) {\n\t\t\tif (typeof hold !== 'object') {\n\t\t\t\treturn String(hold)\n\t\t\t}\n\n\t\t\tif (hold.active) {\n\t\t\t\tif (hold.reason) {\n\t\t\t\t\treturn t('nextcloud-vue', 'On hold: {reason}', { reason: hold.reason })\n\t\t\t\t}\n\t\t\t\treturn t('nextcloud-vue', 'On hold')\n\t\t\t}\n\n\t\t\tif (hold.releasedCount) {\n\t\t\t\treturn n('nextcloud-vue', 'Released, %n earlier hold', 'Released, %n earlier holds', hold.releasedCount)\n\t\t\t}\n\n\t\t\treturn t('nextcloud-vue', 'No hold')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* Group headings. Quiet enough that they organise without competing with the\n values they sit over — a category label is a signpost, not content. */\n.cn-object-metadata__group + .cn-object-metadata__group {\n\tmargin-top: calc(3 * var(--default-grid-baseline, 4px));\n}\n\n.cn-object-metadata__group-title {\n\tmargin: 0 0 calc(0.5 * var(--default-grid-baseline, 4px));\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* Override CnDetailGrid item styling for a compact table-like appearance */\n:deep(.cn-detail-grid__item) {\n\tbackground: none;\n\tborder-radius: 0;\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding: calc(1.5 * var(--default-grid-baseline, 4px)) 0;\n}\n\n:deep(.cn-detail-grid__item:last-child) {\n\tborder-bottom: none;\n}\n\n:deep(.cn-detail-grid--horizontal) {\n\tgap: 0;\n}\n\n:deep(.cn-detail-grid__label) {\n\tfont-size: 0.8em;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.02em;\n}\n\n:deep(.cn-detail-grid__value) {\n\tfont-size: 0.9em;\n\tword-break: break-all;\n\tmargin: 0;\n}\n</style>\n"],"names":["CnDetailCard","CnDetailGrid","t","n"],"mappings":";;;;;;AA6DA;AACC;AACA;;AAED,MAAM,kBAAkB;AACvB,CAAA,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY;AAC7C,CAAA,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY;AACjD,CAAA,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY;CAC/C,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAS,EAAG;CACvD,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAS,EAAG;CACzD,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY;CACrD,EAAE,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAS,EAAG;AACpE,CAAA,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,QAAO,EAAG;AACvE,CAAA,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa;CACpD,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,WAAU,EAAG;CAClE,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,WAAU,EAAG;CAClE,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAU,EAAG;AACtD,CAAA,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa;AAC7E,CAAA,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa;CAC7E,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAK,EAAG;AACtE,CAAA,EAAE,GAAG,EAAE,oBAAoB,EAAE,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,YAAY;AAC/E,EAAA;;AAEA;AACC;AACA;;AAEA;AACA;;;AAGA;AACA;;;AAGA;AACA;;AAEA;;AAEA;AACA;AACA;;AAED,MAAM,kBAAkB;AACvB,CAAA,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM;AAC7F,CAAA,EAAE,GAAG,EAAE,iBAAiB,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM;AACzG,CAAA,EAAE,GAAG,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;AAC/F,CAAA,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM;AACrG,CAAA,EAAE,GAAG,EAAE,kBAAkB,EAAE,KAAK,EAAE,yBAAyB,EAAE,KAAK,EAAE,aAAa;CACjF,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,OAAM,EAAG;CACrE,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAU,EAAG;;AAEtD;;AAEA,CAAA,EAAE,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,wBAAwB,EAAE,KAAK,EAAE,aAAa;AAC7E,CAAA,EAAE,GAAG,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ;AACvF,CAAA,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,cAAc;AACpF,EAAA;;AAEA;AACC;AACA;AACA;AACA;;;AAGD,MAAM,MAAK,GAAI;AACd,CAAA,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY;AACtC,CAAA,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY;AACtC,CAAA,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa;AACxC,CAAA,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa;AACxC,CAAA,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa;AACzC,EAAA;;AAEA;;AAEC;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAED,aAAe;CACd,IAAI,EAAE,wBAAwB;;CAE9B,UAAU,EAAE;gBACXA,UAAY;gBACZC,YAAY;EACZ;;AAED,CAAA,KAAK,EAAE;AACN;AACA,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,UAAU,CAAC;GAC7C;;AAED;EACA,IAAI,EAAE;GACL,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;GACxB,OAAO,EAAE,IAAI;GACb;;AAED;AACC;;;;;;AAMA;AACA;;EAED,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,IAAI;GACb;;AAED;AACC;;AAED,EAAA,MAAM,EAAE;GACP,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,YAAY;GACrB;;AAED;AACC;;AAED,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,CAAC;GACV;;AAED;AACC;;EAED,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,GAAG;GACZ;;AAED;AACC;AACA;;;EAGD,UAAU,EAAE;GACX,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;AACC;AACA;AACA;;AAED,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,KAAK;GACX,OAAO,EAAE,IAAI;GACb;;AAED;;AAEC;AACA;;AAED,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;EACA,WAAW,EAAE;GACZ,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;;EAGD,SAAS,EAAE;GACV,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;AAED;;;AAGC;;AAEA;AACA;AACA;;AAED,EAAA,OAAO,EAAE;GACR,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,IAAI;GACb;;AAED;;;AAGC;;;EAGD,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,OAAO,CAAC;GAC1C;;AAED;EACA,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,uBAAuB,CAAC;GAC1D;EACD;;AAED,CAAA,QAAQ,EAAE;AACT,EAAA,aAAa,GAAG;AACf,GAAA,OAAO,IAAI,CAAC,IAAG;GACf;;AAED;AACC;AACA;;;AAGD,EAAA,cAAc,GAAG;;;AAGhB;GACA,MAAM,IAAK,GAAE,IAAI,CAAC,UAAS,IAAK,GAAC;GACjC,MAAM,YAAY,IAAI,CAAC,OAAO,EAAA;;;;;;;;;;;;;;;;;AAiB9B,GAAA,IAAI,aAAa,OAAO,cAAc,QAAQ,EAAE;AAC/C,IAAA,MAAM,OAAQ,GAAE,GAAC;IACjB,IAAI,IAAI,CAAC,EAAG,KAAI,SAAQ,IAAK,SAAS,CAAC,EAAG,KAAI,SAAS,EAAE;AACxD,KAAA,OAAO,CAAC,EAAC,GAAI,IAAI,CAAC,GAAC;AACpB,KAAA;AACA,IAAA,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,SAAU,EAAA;AACnC,IAAA;;AAEA,GAAA,OAAO,EAAE,GAAG,IAAK,EAAA;GACjB;;AAED;AACC;AACA;AACA;;;;;AAKA;;AAED,EAAA,cAAc,GAAG;AAChB,GAAA,MAAM,KAAM,GAAE,IAAI,CAAC,cAAc,CAAC,WAAS;AAC3C,GAAA,IAAI,CAAC,KAAM,IAAG,OAAO,KAAM,KAAI,QAAQ,EAAE;AACxC,IAAA,OAAO,EAAC;AACT,IAAA;GACA,OAAO,KAAI;GACX;;AAED;;AAEC;;;;;;AAMD,EAAA,YAAY,GAAG;AACd,GAAA,MAAM,KAAI,GAAI,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAG,EAAC,CAAC,CAAC,EAAA;AACzG,GAAA,MAAM,SAAQ,GAAI,GAAC;;AAEnB,GAAA,KAAK,MAAM,IAAK,IAAG,IAAI,CAAC,aAAa,EAAE;IACtC,MAAM,MAAK,GAAI,IAAI,CAAC,KAAI,GAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAE,GAAE,KAAG;IACvD,IAAI,MAAM,EAAE;KACX,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAA;KACrB,MAAK;AACN,KAAA,SAAS,CAAC,IAAI,CAAC,IAAI,EAAA;AACpB,KAAA;AACD,IAAA;;GAEA,MAAM,MAAO,GAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAO,GAAE,CAAC,EAAA;GACnE,IAAI,SAAS,CAAC,MAAO,GAAE,CAAC,EAAE;AACzB,IAAA,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,WAAW,EAAA;AACvE,IAAA;;GAEA,OAAO,MAAK;GACZ;;AAED;;;AAGA,EAAA,aAAa,GAAG;AACf,GAAA,MAAM,MAAK,GAAI,IAAI,CAAC,eAAa;GACjC,MAAM,KAAM,GAAE,GAAC;;AAEf,GAAA,KAAK,MAAM,GAAI,IAAG,eAAe,EAAE;;IAElC,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACpD,KAAA,QAAO;AACR,KAAA;AACA,IAAA,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACnC,KAAA,QAAO;AACR,KAAA;;IAEA,MAAM,GAAE,GAAI,MAAM,CAAC,GAAG,CAAC,GAAG,EAAA;AAC1B,IAAA,IAAI,GAAI,KAAI,SAAU,IAAG,GAAE,KAAM,IAAI,EAAE;AACtC,KAAA,QAAO;AACR,KAAA;;IAEA,KAAK,CAAC,IAAI,CAAC;;;AAGV;AACA,KAAA,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,GAAG,CAAC,KAAK,CAAC;AACpC,KAAA,KAAK,EAAE,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC;AACzC,KAAA,KAAK,EAAE,GAAG,CAAC,KAAK;KAChB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC;KAC5B,EAAA;AACF,IAAA;;;;;AAKA;;;;;;;;;;;;AAYA,GAAA,MAAM,QAAO,GAAI,IAAI,CAAC,eAAa;GACnC,MAAM,WAAY,GAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAA;AACnD,GAAA,KAAK,MAAM,GAAI,IAAG,eAAe,EAAE;IAClC,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACpD,KAAA,QAAO;AACR,KAAA;AACA,IAAA,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACnC,KAAA,QAAO;AACR,KAAA;;IAEA,MAAM,GAAE,GAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAA;AAC5B,IAAA,MAAM,MAAK,GAAI,GAAI,KAAI,aAAa,QAAQ,KAAG;IAC/C,IAAI,MAAO,IAAG,EAAE,WAAU,KAAM,GAAG,CAAC,IAAG,IAAK,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE;AAC3D,KAAA,QAAO;AACR,KAAA;;IAEA,KAAK,CAAC,IAAI,CAAC;AACV,KAAA,KAAK,EAAEA,SAAC,CAAC,eAAe,EAAE,GAAG,CAAC,KAAK,CAAC;AACpC,KAAA,KAAK,EAAE,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC;AACzC,KAAA,KAAK,EAAE,GAAG,CAAC,KAAK;KAChB,KAAK,EAAE,MAAM;KACb,EAAA;AACF,IAAA;;AAEA;AACA,GAAA,KAAK,MAAM,IAAG,IAAK,IAAI,CAAC,UAAU,EAAE;AACnC,IAAA,KAAK,CAAC,IAAI,CAAC,IAAI,EAAA;AAChB,IAAA;;GAEA,OAAO,KAAI;GACX;EACD;;AAED,CAAA,OAAO,EAAE;AACR;AACC;AACA;AACA;AACA;;AAED,EAAA,mBAAmB,CAAC,KAAK,EAAE,GAAG,EAAE;AAC/B,GAAA,IAAI,KAAI,KAAM,QAAQ,KAAM,KAAI,SAAS,EAAE;AAC1C,IAAA,OAAO,GAAE;AACV,IAAA;;;;;AAKA;GACA,IAAI,GAAG,CAAC,MAAO,KAAI,MAAM,EAAE;IAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAA;AAC7B,IAAA;;;;;AAKA;GACA,IAAI,GAAG,CAAC,MAAO,KAAI,WAAW,EAAE;AAC/B,IAAA,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAA;AAClC,IAAA;;AAEA,GAAA,IAAI,GAAG,CAAC,MAAK,KAAM,cAAc,EAAE;AAClC,IAAA,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAA;AACpC,IAAA;;GAEA,IAAI,GAAG,CAAC,MAAK,KAAM,UAAU,EAAE;AAC9B,IAAA,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAA;AACjC,IAAA;;GAEA,IAAI,GAAG,CAAC,WAAW,OAAO,EAAE;IAC3B,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAA;AAC9B,IAAA;;GAEA,IAAI,GAAG,CAAC,MAAO,KAAI,YAAY,EAAE;AAChC,IAAA,OAAO,IAAI,CAAC,eAAe,CAAC,KAAK,CAAA;AAClC,IAAA;;GAEA,IAAI,GAAG,CAAC,MAAO,KAAI,MAAM,EAAE;IAC1B,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,EAAA;AAC3B,IAAA,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACjC,KAAA,OAAO,MAAM,CAAC,KAAK,CAAA;AACpB,KAAA;AACA,IAAA,OAAO,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE,EAAE;KAC5C,GAAG,EAAE,SAAS;AACd,KAAA,KAAK,EAAE,SAAS;AAChB,KAAA,IAAI,EAAE,SAAS;KACf,CAAA;AACF,IAAA;;AAEA;GACA,IAAI,GAAG,CAAC,MAAO,KAAI,WAAW,EAAE;AAC/B,IAAA,IAAI;KACH,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,EAAA;AAC3B,KAAA,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACjC,MAAA,OAAO,MAAM,CAAC,KAAK,CAAA;AACpB,MAAA;AACA,KAAA,OAAO,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE,EAAE;MAC5C,GAAG,EAAE,SAAS;AACd,MAAA,KAAK,EAAE,SAAS;AAChB,MAAA,IAAI,EAAE,SAAS;AAChB,MAAC,IAAI,IAAK,GAAE,IAAI,CAAC,kBAAkB,CAAC,UAAU,EAAE,EAAE;AACjD,MAAA,IAAI,EAAE,SAAS;AACf,MAAA,MAAM,EAAE,SAAS;AACjB,MAAA,MAAM,EAAE,SAAS;MACjB,CAAA;AACF,KAAA,CAAE,MAAM;AACP,KAAA,OAAO,MAAM,CAAC,KAAK,CAAA;AACpB,KAAA;AACD,IAAA;;AAEA;GACA,IAAI,OAAO,UAAU,SAAS,EAAE;AAC/B,IAAA,OAAO,QAAQ,QAAQ,IAAG;AAC3B,IAAA;;AAEA;GACA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AACzB,IAAA,OAAO,KAAK,CAAC,MAAO,GAAE,CAAE,GAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAE,GAAE,GAAE;AAChD,IAAA;;;GAGA,IAAI,OAAO,UAAU,QAAQ,EAAE;IAC9B,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;AAC5B,IAAA;;AAEA,GAAA,OAAO,MAAM,CAAC,KAAK,CAAA;GACnB;;AAED;AACC;AACA;AACA;AACA;;AAED,EAAA,UAAU,CAAC,IAAI,EAAE;GAChB,IAAI,OAAO,SAAS,QAAQ,EAAE;AAC7B,IAAA,OAAO,MAAM,CAAC,IAAI,CAAA;AACnB,IAAA;AACA,GAAA,MAAM,MAAK,GAAI,IAAI,CAAC,WAAY,IAAG,IAAI,CAAC,KAAG;GAC3C,MAAM,KAAI,GAAI,IAAI,CAAC,SAAU,GAAE,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAE,GAAE,KAAG;GAC7D,MAAM,WAAW,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,EAAA;;AAEvD,GAAA,IAAI,MAAO,IAAG,QAAQ,EAAE;IACvB,OAAOA,SAAC,CAAC,eAAe,EAAE,+BAA+B,EAAE;KAC1D,IAAI,EAAE,MAAM;AACZ,KAAA,IAAI,EAAE,KAAK,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;KACxC,CAAA;AACF,IAAA;;GAEA,IAAI,MAAM,EAAE;IACX,OAAOA,SAAC,CAAC,eAAe,EAAE,kBAAkB,EAAE,EAAE,IAAI,EAAE,MAAK,EAAG,CAAA;AAC/D,IAAA;;AAEA,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,QAAQ,CAAA;GAClC;;AAED;AACC;AACA;AACA;;;EAGD,eAAe,CAAC,KAAK,EAAE;GACtB,MAAM,KAAI,GAAI;IACb,kBAAkB,EAAEA,SAAC,CAAC,eAAe,EAAE,kBAAkB,CAAC;AAC1D,IAAA,OAAO,EAAEA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAC;IACtC,kBAAkB,EAAEA,SAAC,CAAC,eAAe,EAAE,oBAAoB,CAAC;AAC7D,KAAA;AACA,GAAA,OAAO,KAAK,CAAC,KAAK,CAAA,IAAK,MAAM,CAAC,KAAK,CAAA;GACnC;;AAED;AACC;AACA;AACA;AACA;;EAED,iBAAiB,CAAC,KAAK,EAAE;GACxB,MAAM,KAAI,GAAI;AACb,IAAA,MAAM,EAAEA,SAAC,CAAC,eAAe,EAAE,QAAQ,CAAC;AACpC,IAAA,WAAW,EAAEA,SAAC,CAAC,eAAe,EAAE,aAAa,CAAC;IAC9C,WAAW,EAAEA,SAAC,CAAC,eAAe,EAAE,wBAAwB,CAAC;AACzD,IAAA,SAAS,EAAEA,SAAC,CAAC,eAAe,EAAE,WAAW,CAAC;AAC3C,KAAA;AACA,GAAA,OAAO,KAAK,CAAC,KAAK,CAAA,IAAK,MAAM,CAAC,KAAK,CAAA;GACnC;;AAED;;AAEC;;;AAGA;AACA;AACA;AACA;;;AAGD,EAAA,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE;GACjB,IAAI,GAAG,CAAC,WAAW,QAAQ,EAAE;AAC5B,IAAA,OAAO,IAAG;AACX,IAAA;GACA,MAAM,EAAG,GAAE,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,GAAC;AAC5B,GAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;AACtB,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,OAAO,WAAW,CAAC,2CAA2C,EAAE,EAAE,IAAI,CAAA;GACtE;;AAED;AACC;AACA;;;;;AAKA;AACA;AACA;;;AAGD,EAAA,cAAc,CAAC,KAAK,EAAE;GACrB,MAAM,KAAM,GAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAA;GAClD,IAAI,CAAC,KAAK,EAAE;AACX,IAAA,OAAO,MAAM,CAAC,KAAK,CAAA;AACpB,IAAA;;GAEA,MAAM,MAAK,GAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAA;AAC9B,GAAA,IAAI,KAAK,CAAC,CAAC,CAAA,KAAM,GAAG,EAAE;IACrB,OAAOC,eAAC,CAAC,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,CAAA;AACxD,IAAA;AACA,GAAA,IAAI,KAAK,CAAC,CAAC,CAAA,KAAM,GAAG,EAAE;IACrB,OAAOA,eAAC,CAAC,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,CAAA;AAC1D,IAAA;GACA,OAAOA,eAAC,CAAC,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAA;GACrD;;AAED;AACC;AACA;AACA;AACA;;AAED,EAAA,WAAW,CAAC,KAAK,EAAE;GAClB,MAAM,KAAI,GAAI;IACb,cAAc,EAAED,SAAC,CAAC,eAAe,EAAE,gBAAgB,CAAC;;;AAGpD;AACA,IAAA,4BAA4B,EAAEA,SAAC,CAAC,eAAe,EAAE,8BAA8B,CAAC;IAChF,MAAM,EAAEA,SAAC,CAAC,eAAe,EAAE,yBAAyB,CAAC;AACrD,IAAA,iBAAiB,EAAEA,SAAC,CAAC,eAAe,EAAE,4BAA4B,CAAC;IACnE,IAAI,EAAEA,SAAC,CAAC,eAAe,EAAE,0BAA0B,CAAC;IACpD,MAAM,EAAEA,SAAC,CAAC,eAAe,EAAE,wBAAwB,CAAC;AACrD,KAAA;AACA,GAAA,OAAO,KAAK,CAAC,KAAK,CAAA,IAAK,MAAM,CAAC,KAAK,CAAA;GACnC;;AAED;;AAEC;;;;AAIA;AACA;AACA;;AAED,EAAA,eAAe,CAAC,IAAI,EAAE;GACrB,IAAI,OAAO,SAAS,QAAQ,EAAE;AAC7B,IAAA,OAAO,MAAM,CAAC,IAAI,CAAA;AACnB,IAAA;;AAEA,GAAA,IAAI,IAAI,CAAC,MAAM,EAAE;AAChB,IAAA,IAAI,IAAI,CAAC,MAAM,EAAE;AAChB,KAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,mBAAmB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAK,EAAG,CAAA;AACvE,KAAA;AACA,IAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAA;AACpC,IAAA;;GAEA,IAAI,IAAI,CAAC,aAAa,EAAE;AACvB,IAAA,OAAOC,eAAC,CAAC,eAAe,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,IAAI,CAAC,aAAa,CAAA;AACxG,IAAA;;AAEA,GAAA,OAAOD,SAAC,CAAC,eAAe,EAAE,SAAS,CAAA;GACnC;EACD;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnObjectMetadataWidget.vue3.js","sources":["../../../../src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue?vue&type=template&id=6eb886ea&lang.js"],"sourcesContent":["<!--\n CnObjectMetadataWidget — Read-only metadata display widget.\n\n Shows system/internal metadata for an OpenRegister object in a horizontal\n label-value grid. Automatically extracts known metadata fields from the object\n (id, uuid, uri, register, schema, created, updated, owner, etc.).\n\n Not editable — purely informational. Wraps CnDetailCard + CnDetailGrid.\n-->\n<template>\n\t<CnDetailCard :title=\"title\"\n\t\t:icon=\"iconComponent\"\n\t\t:collapsible=\"collapsible\"\n\t\t:collapsed=\"collapsed\">\n\t\t<template #actions>\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Grouped: one grid per category, each under its own heading. A flat\n\t\t list of twenty rows is a wall; Identity / Location / Ownership /\n\t\t Lifecycle / Archiving is how a reader actually looks for one fact.\n\t\t `grouped: false` restores the single flat grid for hosts that want\n\t\t the old shape. -->\n\t\t<template v-if=\"grouped && groupedItems.length > 0\">\n\t\t\t<div\n\t\t\t\tv-for=\"group in groupedItems\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-object-metadata__group\">\n\t\t\t\t<h4 class=\"cn-object-metadata__group-title\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</h4>\n\t\t\t\t<CnDetailGrid\n\t\t\t\t\t:items=\"group.items\"\n\t\t\t\t\t:layout=\"layout\"\n\t\t\t\t\t:columns=\"columns\"\n\t\t\t\t\t:labelWidth=\"labelWidth\"\n\t\t\t\t\t:accent=\"false\"\n\t\t\t\t\t:emptyLabel=\"emptyLabel\" />\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- One flat grid: either because grouping is off, or because there is\n\t\t nothing to group and CnDetailGrid already owns the empty state. -->\n\t\t<CnDetailGrid\n\t\t\tv-else\n\t\t\t:items=\"metadataItems\"\n\t\t\t:layout=\"layout\"\n\t\t\t:columns=\"columns\"\n\t\t\t:labelWidth=\"labelWidth\"\n\t\t\t:accent=\"false\"\n\t\t\t:emptyLabel=\"emptyLabel\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { CnDetailCard } from '../CnDetailCard/index.js'\nimport { CnDetailGrid } from '../CnDetailGrid/index.js'\n\n/**\n * Known metadata fields and their labels.\n * These are the standard fields from OpenRegister's `@self` / system fields.\n */\nconst METADATA_FIELDS = [\n\t{ key: 'id', label: 'ID', group: 'identity' },\n\t{ key: 'uuid', label: 'UUID', group: 'identity' },\n\t{ key: 'uri', label: 'URI', group: 'identity' },\n\t{ key: 'version', label: 'Version', group: 'identity' },\n\t{ key: 'register', label: 'Register', group: 'location' },\n\t{ key: 'schema', label: 'Schema', group: 'location' },\n\t{ key: 'schemaVersion', label: 'Schema version', group: 'location' },\n\t{ key: 'folder', label: 'Folder', group: 'location', format: 'folder' },\n\t{ key: 'owner', label: 'Owner', group: 'ownership' },\n\t{ key: 'organisation', label: 'Organisation', group: 'ownership' },\n\t{ key: 'organization', label: 'Organization', group: 'ownership' },\n\t{ key: 'status', label: 'Status', group: 'lifecycle' },\n\t{ key: 'created', label: 'Created', group: 'lifecycle', format: 'date-time' },\n\t{ key: 'updated', label: 'Updated', group: 'lifecycle', format: 'date-time' },\n\t{ key: 'locked', label: 'Locked', group: 'lifecycle', format: 'lock' },\n\t{ key: 'textRepresentation', label: 'Text Representation', group: 'identity' },\n]\n\n/**\n * The archival constraints, read from the resolved `@self._retention` decision.\n *\n * 🔴 THESE KEYS ARE MDTO CONCEPTS IN ENGLISH, and they changed with\n * openregister#3584: `nomination` became `appraisal`, `period` became\n * `retentionPeriod`, `actionDate` became `disposalDate`, `classification`\n * became `disposalCategory`, and the Archiefwet lifecycle arrived as\n * `recordState` with a derived `immutable`. MDTO supersedes TMLO, so\n * `archiefnominatie` is the superseded spelling of MDTO's `waardering`.\n *\n * They live one level down, under `_retention`, and `include` / `exclude`\n * address them by these same names.\n *\n * Two of the resolver's keys are deliberately not rows here. `immutable` is\n * derived from `recordState` and would only repeat what \"Transferred to\n * archive\" already says, and `annotation` is the raw rule-evaluation object\n * kept for debugging, which would land in the panel as JSON.\n *\n * Empty on an object whose schema declares no archival obligation, and that is\n * a real answer rather than a gap — see `emptyLabel`.\n */\nconst ARCHIVAL_FIELDS = [\n\t{ key: 'appraisal', label: 'Appraisal', group: 'archiving', format: 'appraisal', core: true },\n\t{ key: 'retentionPeriod', label: 'Retention period', group: 'archiving', format: 'duration', core: true },\n\t{ key: 'disposalDate', label: 'Disposal date', group: 'archiving', format: 'date', core: true },\n\t{ key: 'recordState', label: 'Record state', group: 'archiving', format: 'record-state', core: true },\n\t{ key: 'disposalCategory', label: 'Selection list category', group: 'archiving' },\n\t{ key: 'basis', label: 'Basis', group: 'archiving', format: 'basis' },\n\t{ key: 'source', label: 'Source', group: 'archiving' },\n\t// Which revision of the list, and when it was read (openregister#3588).\n\t// The same category carries different retention periods across revisions,\n\t// so a decision that names only the list cannot be defended once it moves.\n\t{ key: 'sourceVersion', label: 'Selection list version', group: 'archiving' },\n\t{ key: 'sourceConsultedAt', label: 'Consulted on', group: 'archiving', format: 'date' },\n\t{ key: 'legalHold', label: 'Legal hold', group: 'archiving', format: 'legal-hold' },\n]\n\n/**\n * The groups, in the order a reader works down them.\n *\n * Identity first (which record is this), then where it lives, who owns it, what\n * state it is in, and finally what happens to it. Archiving last because it is\n * the answer you go looking for rather than the one you scan past.\n */\nconst GROUPS = [\n\t{ key: 'identity', label: 'Identity' },\n\t{ key: 'location', label: 'Location' },\n\t{ key: 'ownership', label: 'Ownership' },\n\t{ key: 'lifecycle', label: 'Lifecycle' },\n\t{ key: 'archiving', label: 'Archiving' },\n]\n\n/**\n * CnObjectMetadataWidget — Read-only metadata display widget.\n *\n * Automatically extracts and formats metadata from an OpenRegister object.\n * Understands both flat objects (where metadata is at the top level) and\n * objects with a `@self` metadata block.\n *\n * Basic usage\n * ```vue\n * <CnObjectMetadataWidget :object-data=\"publication\" />\n * ```\n *\n * With extra items\n * ```vue\n * <CnObjectMetadataWidget\n * title=\"System Info\"\n * :object-data=\"entity\"\n * :extra-items=\"[\n * { label: 'Source', value: entity.source },\n * { label: 'Catalog', value: entity.catalog },\n * ]\" />\n * ```\n *\n * Selective display\n * ```vue\n * <CnObjectMetadataWidget\n * :object-data=\"entity\"\n * :include=\"['id', 'uuid', 'created', 'updated', 'owner']\" />\n * ```\n */\nexport default {\n\tname: 'CnObjectMetadataWidget',\n\n\tcomponents: {\n\t\tCnDetailCard,\n\t\tCnDetailGrid,\n\t},\n\n\tprops: {\n\t\t/** Widget title shown in the card header */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Metadata'),\n\t\t},\n\n\t\t/** Optional MDI icon component for the header */\n\t\ticon: {\n\t\t\ttype: [Object, Function],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The object data containing metadata.\n\t\t * Supports flat objects and objects with `@self` metadata block.\n\t\t * Optional: null renders the empty state (and avoids a required-prop\n\t\t * warning on surfaces that mount before the object loads, e.g. a\n\t\t * `metadata` tab in CnObjectSidebar). Handled internally via\n\t\t * `this.objectData || {}`.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Layout mode for the grid: 'grid' or 'horizontal'.\n\t\t */\n\t\tlayout: {\n\t\t\ttype: String,\n\t\t\tdefault: 'horizontal',\n\t\t},\n\n\t\t/**\n\t\t * Number of grid columns (only for layout='grid').\n\t\t */\n\t\tcolumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\n\t\t/**\n\t\t * Min width for labels in horizontal layout.\n\t\t */\n\t\tlabelWidth: {\n\t\t\ttype: Number,\n\t\t\tdefault: 150,\n\t\t},\n\n\t\t/**\n\t\t * Additional metadata items to display.\n\t\t *\n\t\t * @type {Array<{ label: string, value: string|number }>}\n\t\t */\n\t\textraItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Metadata fields to include (whitelist). If null, all available are shown.\n\t\t *\n\t\t * @type {string[]|null}\n\t\t */\n\t\tinclude: {\n\t\t\ttype: Array,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Metadata fields to exclude.\n\t\t *\n\t\t * @type {string[]}\n\t\t */\n\t\texclude: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the card can be collapsed */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Initial collapsed state */\n\t\tcollapsed: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Group the rows under category headings (Identity, Location,\n\t\t * Ownership, Lifecycle, Archiving) instead of rendering one flat list.\n\t\t *\n\t\t * On by default: a flat list of twenty rows is a wall to read. Pass\n\t\t * `false` for the previous single-grid shape.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tgrouped: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Heading for the items a host supplied through `extraItems`, which\n\t\t * carry no group of their own.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\totherLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Other'),\n\t\t},\n\n\t\t/** Label shown when no metadata available */\n\t\temptyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No metadata available'),\n\t\t},\n\t},\n\n\tcomputed: {\n\t\ticonComponent() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\t/**\n\t\t * Merged metadata source: combines the `@self` block with top-level fields.\n\t\t *\n\t\t * @self fields take priority over top-level for shared keys.\n\t\t */\n\t\tmetadataSource() {\n\t\t\t// objectData is optional (and momentarily null during async loads or\n\t\t\t// when a parent binds a not-yet-resolved object), so guard before\n\t\t\t// reading `@self` to avoid a render-time TypeError.\n\t\t\tconst data = this.objectData || {}\n\t\t\tconst selfBlock = data['@self']\n\n\t\t\t// 🔴 WHEN THERE IS A `@self` BLOCK, IT IS THE ONLY METADATA SOURCE.\n\t\t\t//\n\t\t\t// This used to merge `{ ...data, ...selfBlock }`, which meant any\n\t\t\t// BUSINESS property sharing a name with a metadata field leaked into\n\t\t\t// the metadata list. Measured on a dossiq case: the panel reported\n\t\t\t// `STATUS active` — the case's own workflow status, a schema\n\t\t\t// property — while the page header beside it read `Unknown`, because\n\t\t\t// the two were reading different things and only one of them was\n\t\t\t// metadata. `version`, `owner`, `folder` and `locked` are all\n\t\t\t// perfectly ordinary property names and had the same exposure.\n\t\t\t//\n\t\t\t// A record WITHOUT a `@self` block is a different case: several\n\t\t\t// widget props pass a pre-flattened metadata object, and for those\n\t\t\t// the top level genuinely is the metadata. `id` is carried over\n\t\t\t// either way because the API mirrors it to the top level.\n\t\t\tif (selfBlock && typeof selfBlock === 'object') {\n\t\t\t\tconst carried = {}\n\t\t\t\tif (data.id !== undefined && selfBlock.id === undefined) {\n\t\t\t\t\tcarried.id = data.id\n\t\t\t\t}\n\t\t\t\treturn { ...carried, ...selfBlock }\n\t\t\t}\n\n\t\t\treturn { ...data }\n\t\t},\n\n\t\t/**\n\t\t * The resolved archival decision, or an empty object.\n\t\t *\n\t\t * Read from `@self._retention`, which OpenRegister's render layer fills\n\t\t * by merging the object's stored retention block, its schema's\n\t\t * `x-openregister-archival` evaluation and any legal hold. It is absent\n\t\t * entirely — not empty — on an object with no archival obligation, and\n\t\t * that distinction is deliberate on the server side, so it is preserved\n\t\t * here rather than defaulted into a row of dashes.\n\t\t */\n\t\tarchivalSource() {\n\t\t\tconst block = this.metadataSource._retention\n\t\t\tif (!block || typeof block !== 'object') {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\treturn block\n\t\t},\n\n\t\t/**\n\t\t * The same items, bucketed into the categories a reader scans.\n\t\t *\n\t\t * A group with nothing in it is dropped rather than rendered as an\n\t\t * empty heading — an object with no archival obligation should not\n\t\t * carry an \"Archiving\" heading over a void. `extraItems` carry no\n\t\t * group, so they collect under the host's own heading at the end.\n\t\t */\n\t\tgroupedItems() {\n\t\t\tconst byKey = new Map(GROUPS.map((g) => [g.key, { ...g, label: t('nextcloud-vue', g.label), items: [] }]))\n\t\t\tconst ungrouped = []\n\n\t\t\tfor (const item of this.metadataItems) {\n\t\t\t\tconst bucket = item.group ? byKey.get(item.group) : null\n\t\t\t\tif (bucket) {\n\t\t\t\t\tbucket.items.push(item)\n\t\t\t\t} else {\n\t\t\t\t\tungrouped.push(item)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst groups = [...byKey.values()].filter((g) => g.items.length > 0)\n\t\t\tif (ungrouped.length > 0) {\n\t\t\t\tgroups.push({ key: 'other', label: this.otherLabel, items: ungrouped })\n\t\t\t}\n\n\t\t\treturn groups\n\t\t},\n\n\t\t/**\n\t\t * Build the items array for CnDetailGrid from known metadata fields.\n\t\t */\n\t\tmetadataItems() {\n\t\t\tconst source = this.metadataSource\n\t\t\tconst items = []\n\n\t\t\tfor (const def of METADATA_FIELDS) {\n\t\t\t\t// Filter by include/exclude\n\t\t\t\tif (this.include && !this.include.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.exclude.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst raw = source[def.key]\n\t\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\titems.push({\n\t\t\t\t\t// Translated at use, not at import: the bundles register\n\t\t\t\t\t// after this module loads, and a label resolved at import\n\t\t\t\t\t// time would stay English for every reader.\n\t\t\t\t\tlabel: t('nextcloud-vue', def.label),\n\t\t\t\t\tvalue: this.formatMetadataValue(raw, def),\n\t\t\t\t\tgroup: def.group,\n\t\t\t\t\thref: this.hrefFor(raw, def),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// The archival group, read one level down from `@self._retention`.\n\t\t\t// Appended after the identity fields rather than interleaved: what\n\t\t\t// happens to a record and when is a question of its own, and a\n\t\t\t// records officer reads the group, not one line of it.\n\t\t\t// nextcloud-vue#1062. When the object HAS an archival decision, an\n\t\t\t// absent core fact is itself the answer: a records officer reading\n\t\t\t// \"Disposal date: -\" learns there is no date yet, while a missing row\n\t\t\t// reads as a panel that never looked. So the four MDTO core rows\n\t\t\t// stay, blank, and so does any key a host named in `include`, which\n\t\t\t// is already the host saying \"this row matters to me\". Optional\n\t\t\t// provenance rows still only appear when they carry something.\n\t\t\t//\n\t\t\t// An object with NO decision keeps an empty Archiving group, which\n\t\t\t// the grouping drops entirely: \"no archival obligation\" and \"an\n\t\t\t// obligation with a gap\" are different answers and must look it.\n\t\t\tconst archival = this.archivalSource\n\t\t\tconst hasDecision = Object.keys(archival).length > 0\n\t\t\tfor (const def of ARCHIVAL_FIELDS) {\n\t\t\t\tif (this.include && !this.include.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.exclude.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst raw = archival[def.key]\n\t\t\t\tconst absent = raw === undefined || raw === null\n\t\t\t\tif (absent && !(hasDecision && (def.core || this.include))) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\titems.push({\n\t\t\t\t\tlabel: t('nextcloud-vue', def.label),\n\t\t\t\t\tvalue: this.formatMetadataValue(raw, def),\n\t\t\t\t\tgroup: def.group,\n\t\t\t\t\tempty: absent,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Append extra items\n\t\t\tfor (const item of this.extraItems) {\n\t\t\t\titems.push(item)\n\t\t\t}\n\n\t\t\treturn items\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Format a metadata value for display.\n\t\t *\n\t\t * @param {unknown} value - The raw metadata value.\n\t\t * @param {object} def - The metadata field definition (format, label, etc.).\n\t\t */\n\t\tformatMetadataValue(value, def) {\n\t\t\tif (value === null || value === undefined) {\n\t\t\t\treturn '-'\n\t\t\t}\n\n\t\t\t// The lock is an object (`{ user, displayName, expiresAt }`) and used\n\t\t\t// to reach the panel as raw JSON, which reads as debug output rather\n\t\t\t// than as the one fact that matters: who is holding this, and until\n\t\t\t// when.\n\t\t\tif (def.format === 'lock') {\n\t\t\t\treturn this.formatLock(value)\n\t\t\t}\n\n\t\t\t// Archival formats. Each turns a stored code into the phrase an\n\t\t\t// archivist would say, and each falls back to the raw value rather\n\t\t\t// than hiding a code it has not been taught — an unrecognised\n\t\t\t// appraisal is still a records obligation.\n\t\t\tif (def.format === 'appraisal') {\n\t\t\t\treturn this.formatAppraisal(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'record-state') {\n\t\t\t\treturn this.formatRecordState(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'duration') {\n\t\t\t\treturn this.formatDuration(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'basis') {\n\t\t\t\treturn this.formatBasis(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'legal-hold') {\n\t\t\t\treturn this.formatLegalHold(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'date') {\n\t\t\t\tconst date = new Date(value)\n\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t\treturn date.toLocaleDateString(undefined, {\n\t\t\t\t\tday: '2-digit',\n\t\t\t\t\tmonth: '2-digit',\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Date-time formatting\n\t\t\tif (def.format === 'date-time') {\n\t\t\t\ttry {\n\t\t\t\t\tconst date = new Date(value)\n\t\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\t\treturn String(value)\n\t\t\t\t\t}\n\t\t\t\t\treturn date.toLocaleDateString(undefined, {\n\t\t\t\t\t\tday: '2-digit',\n\t\t\t\t\t\tmonth: '2-digit',\n\t\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\t}) + ', ' + date.toLocaleTimeString(undefined, {\n\t\t\t\t\t\thour: '2-digit',\n\t\t\t\t\t\tminute: '2-digit',\n\t\t\t\t\t\tsecond: '2-digit',\n\t\t\t\t\t})\n\t\t\t\t} catch {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Booleans\n\t\t\tif (typeof value === 'boolean') {\n\t\t\t\treturn value ? 'Yes' : 'No'\n\t\t\t}\n\n\t\t\t// Arrays\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.length > 0 ? value.join(', ') : '-'\n\t\t\t}\n\n\t\t\t// Objects — show as JSON snippet\n\t\t\tif (typeof value === 'object') {\n\t\t\t\treturn JSON.stringify(value)\n\t\t\t}\n\n\t\t\treturn String(value)\n\t\t},\n\n\t\t/**\n\t\t * Render a lock as a sentence rather than as its JSON.\n\t\t *\n\t\t * @param {object} lock - The `@self.locked` payload.\n\t\t * @return {string} Who holds it, and until when.\n\t\t */\n\t\tformatLock(lock) {\n\t\t\tif (typeof lock !== 'object') {\n\t\t\t\treturn String(lock)\n\t\t\t}\n\t\t\tconst holder = lock.displayName || lock.user\n\t\t\tconst until = lock.expiresAt ? new Date(lock.expiresAt) : null\n\t\t\tconst hasUntil = until && !Number.isNaN(until.getTime())\n\n\t\t\tif (holder && hasUntil) {\n\t\t\t\treturn t('nextcloud-vue', 'Locked by {user} until {date}', {\n\t\t\t\t\tuser: holder,\n\t\t\t\t\tdate: until.toLocaleString(),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif (holder) {\n\t\t\t\treturn t('nextcloud-vue', 'Locked by {user}', { user: holder })\n\t\t\t}\n\n\t\t\treturn t('nextcloud-vue', 'Locked')\n\t\t},\n\n\t\t/**\n\t\t * Name what is going to happen to the record.\n\t\t *\n\t\t * @param {string} value - The stored appraisal.\n\t\t * @return {string} The phrase, or the raw code when unrecognised.\n\t\t */\n\t\tformatAppraisal(value) {\n\t\t\tconst known = {\n\t\t\t\tretain_permanently: t('nextcloud-vue', 'Keep permanently'),\n\t\t\t\tdestroy: t('nextcloud-vue', 'Destroy'),\n\t\t\t\tnot_yet_determined: t('nextcloud-vue', 'Not yet determined'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * Name the record's place in the Archiefwet lifecycle.\n\t\t *\n\t\t * @param {string} value - The record state.\n\t\t * @return {string} The phrase, or the raw value.\n\t\t */\n\t\tformatRecordState(value) {\n\t\t\tconst known = {\n\t\t\t\tactive: t('nextcloud-vue', 'Active'),\n\t\t\t\tsemi_static: t('nextcloud-vue', 'Semi-static'),\n\t\t\t\ttransferred: t('nextcloud-vue', 'Transferred to archive'),\n\t\t\t\tdestroyed: t('nextcloud-vue', 'Destroyed'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * A Files deep-link for a folder held as a numeric node id.\n\t\t *\n\t\t * `@self.folder` is a string that is USUALLY a node id and sometimes a\n\t\t * legacy path, so only the digit form gets a link — a path would produce\n\t\t * a URL that 404s, which is worse than plain text.\n\t\t *\n\t\t * @param {unknown} raw - The raw metadata value.\n\t\t * @param {object} def - The field definition.\n\t\t * @return {string|null} The href, or null when it is not linkable.\n\t\t */\n\t\threfFor(raw, def) {\n\t\t\tif (def.format !== 'folder') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst id = String(raw).trim()\n\t\t\tif (!/^\\d+$/.test(id)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn generateUrl('/apps/files/?fileid={id}&opendetails=true', { id })\n\t\t},\n\n\t\t/**\n\t\t * Turn an ISO-8601 duration into something readable.\n\t\t *\n\t\t * Deliberately handles only the whole-year / whole-month / whole-day\n\t\t * forms a retention period is actually written in (`P10Y`, `P6M`,\n\t\t * `P30D`). Anything else is returned as-is rather than parsed\n\t\t * half-correctly, because a retention period rendered wrong is worse\n\t\t * than one rendered raw.\n\t\t *\n\t\t * @param {string} value - The ISO-8601 duration.\n\t\t * @return {string} The readable period, or the raw duration.\n\t\t */\n\t\tformatDuration(value) {\n\t\t\tconst match = /^P(\\d+)([YMD])$/.exec(String(value))\n\t\t\tif (!match) {\n\t\t\t\treturn String(value)\n\t\t\t}\n\n\t\t\tconst amount = Number(match[1])\n\t\t\tif (match[2] === 'Y') {\n\t\t\t\treturn n('nextcloud-vue', '%n year', '%n years', amount)\n\t\t\t}\n\t\t\tif (match[2] === 'M') {\n\t\t\t\treturn n('nextcloud-vue', '%n month', '%n months', amount)\n\t\t\t}\n\t\t\treturn n('nextcloud-vue', '%n day', '%n days', amount)\n\t\t},\n\n\t\t/**\n\t\t * Say on whose authority the retention period rests.\n\t\t *\n\t\t * @param {string} value - The basis code.\n\t\t * @return {string} The phrase, or the raw code.\n\t\t */\n\t\tformatBasis(value) {\n\t\t\tconst known = {\n\t\t\t\tselection_list: t('nextcloud-vue', 'Selection list'),\n\t\t\t\t// Its own answer, not a variant of \"schema\": the schema expected\n\t\t\t\t// a selection list and none was consulted, which an operator who\n\t\t\t\t// believes one is configured needs to be told.\n\t\t\t\tselection_list_not_consulted: t('nextcloud-vue', 'Selection list not consulted'),\n\t\t\t\tschema: t('nextcloud-vue', 'Schema archive settings'),\n\t\t\t\tschema_annotation: t('nextcloud-vue', 'Schema archival annotation'),\n\t\t\t\ttmlo: t('nextcloud-vue', 'Record archival metadata'),\n\t\t\t\trecord: t('nextcloud-vue', 'Recorded on the object'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * Render the legal-hold state.\n\t\t *\n\t\t * A released hold still reports itself: \"held once and released\" is a\n\t\t * different fact from \"never held\", and an archivist reads the\n\t\t * difference.\n\t\t *\n\t\t * @param {object} hold - The resolved hold state.\n\t\t * @return {string} The hold sentence.\n\t\t */\n\t\tformatLegalHold(hold) {\n\t\t\tif (typeof hold !== 'object') {\n\t\t\t\treturn String(hold)\n\t\t\t}\n\n\t\t\tif (hold.active) {\n\t\t\t\tif (hold.reason) {\n\t\t\t\t\treturn t('nextcloud-vue', 'On hold: {reason}', { reason: hold.reason })\n\t\t\t\t}\n\t\t\t\treturn t('nextcloud-vue', 'On hold')\n\t\t\t}\n\n\t\t\tif (hold.releasedCount) {\n\t\t\t\treturn n('nextcloud-vue', 'Released, %n earlier hold', 'Released, %n earlier holds', hold.releasedCount)\n\t\t\t}\n\n\t\t\treturn t('nextcloud-vue', 'No hold')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* Group headings. Quiet enough that they organise without competing with the\n values they sit over — a category label is a signpost, not content. */\n.cn-object-metadata__group + .cn-object-metadata__group {\n\tmargin-top: calc(3 * var(--default-grid-baseline, 4px));\n}\n\n.cn-object-metadata__group-title {\n\tmargin: 0 0 calc(0.5 * var(--default-grid-baseline, 4px));\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* Override CnDetailGrid item styling for a compact table-like appearance */\n:deep(.cn-detail-grid__item) {\n\tbackground: none;\n\tborder-radius: 0;\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding: calc(1.5 * var(--default-grid-baseline, 4px)) 0;\n}\n\n:deep(.cn-detail-grid__item:last-child) {\n\tborder-bottom: none;\n}\n\n:deep(.cn-detail-grid--horizontal) {\n\tgap: 0;\n}\n\n:deep(.cn-detail-grid__label) {\n\tfont-size: 0.8em;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.02em;\n}\n\n:deep(.cn-detail-grid__value) {\n\tfont-size: 0.9em;\n\tword-break: break-all;\n\tmargin: 0;\n}\n</style>\n"],"names":["_renderSlot","_createElementBlock","_Fragment","_renderList","_toDisplayString"],"mappings":";;AAqCQ,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,iCAAiB,GAAA;;;;;;;AAlBf,IAAA,KAAI,EAAG,MAAK,CAAA,KAAA;QACrB,EAAE,QAAa,CAAA,aAAA;eACR,EAAC,MAAY,CAAA,WAAA;AACpB,IAAA,SAAK,EAAG,MAAQ,CAAA,SAAA;;AACV,IAAA,OAAO,UACjB,MAAG;MAAHA,UAAG,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;;qBAQD,MAgBQ;OAhBK,MAAM,CAAA,OAAA,IAAA,QAAA,CAAA,YAAA,CAAA,MAAA,GAAA,CAAA;4BACnBC,kBAcI,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAAC,UAAA,CAbW,QAAE,CAAA,YAAA,EAAA,CAAX,KAAK,KAAA;iCADXF,kBAcI,CAAA,KAAA,EAAA;cAZJ,GAAG,EAAE,KAAK,CAAC,GAAG;AACd,cAAA,KAAI,EAAC,2BAAS;;iCAGV,gBAAA,EADDG,eAAA,CAAA,KAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;yBAQU,CAAA,uBAAA,EAAA;gBALb,KAAM,EAAE,KAAK,CAAC,KAAK;sBACZ,QAAQ,CAAA,MAAA;AACd,gBAAA,OAAO,EAAC,MAAA,CAAA,OAAA;AACR,gBAAA,UAAE,EAAA,MAAA,CAAA,UAAA;AACF,gBAAA,MAAM,EAAE,KAAK;AACb,gBAAA,UAAU,EAAE,MAAA,CAAA,UAAA;;;;;;;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"CnObjectMetadataWidget.vue3.js","sources":["../../../../src/components/CnObjectMetadataWidget/CnObjectMetadataWidget.vue?vue&type=template&id=b0578290&lang.js"],"sourcesContent":["<!--\n CnObjectMetadataWidget — Read-only metadata display widget.\n\n Shows system/internal metadata for an OpenRegister object in a horizontal\n label-value grid. Automatically extracts known metadata fields from the object\n (id, uuid, uri, register, schema, created, updated, owner, etc.).\n\n Not editable — purely informational. Wraps CnDetailCard + CnDetailGrid.\n-->\n<template>\n\t<CnDetailCard :title=\"title\"\n\t\t:icon=\"iconComponent\"\n\t\t:collapsible=\"collapsible\"\n\t\t:collapsed=\"collapsed\">\n\t\t<template #actions>\n\t\t\t<slot name=\"actions\" />\n\t\t</template>\n\n\t\t<!-- Grouped: one grid per category, each under its own heading. A flat\n\t\t list of twenty rows is a wall; Identity / Location / Ownership /\n\t\t Lifecycle / Archiving is how a reader actually looks for one fact.\n\t\t `grouped: false` restores the single flat grid for hosts that want\n\t\t the old shape. -->\n\t\t<template v-if=\"grouped && groupedItems.length > 0\">\n\t\t\t<div\n\t\t\t\tv-for=\"group in groupedItems\"\n\t\t\t\t:key=\"group.key\"\n\t\t\t\tclass=\"cn-object-metadata__group\">\n\t\t\t\t<h4 class=\"cn-object-metadata__group-title\">\n\t\t\t\t\t{{ group.label }}\n\t\t\t\t</h4>\n\t\t\t\t<CnDetailGrid\n\t\t\t\t\t:items=\"group.items\"\n\t\t\t\t\t:layout=\"layout\"\n\t\t\t\t\t:columns=\"columns\"\n\t\t\t\t\t:labelWidth=\"labelWidth\"\n\t\t\t\t\t:accent=\"false\"\n\t\t\t\t\t:emptyLabel=\"emptyLabel\" />\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- One flat grid: either because grouping is off, or because there is\n\t\t nothing to group and CnDetailGrid already owns the empty state. -->\n\t\t<CnDetailGrid\n\t\t\tv-else\n\t\t\t:items=\"metadataItems\"\n\t\t\t:layout=\"layout\"\n\t\t\t:columns=\"columns\"\n\t\t\t:labelWidth=\"labelWidth\"\n\t\t\t:accent=\"false\"\n\t\t\t:emptyLabel=\"emptyLabel\" />\n\t</CnDetailCard>\n</template>\n\n<script>\nimport { translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { userLocale } from '../../utils/userLocale.js'\nimport { CnDetailCard } from '../CnDetailCard/index.js'\nimport { CnDetailGrid } from '../CnDetailGrid/index.js'\n\n/**\n * Known metadata fields and their labels.\n * These are the standard fields from OpenRegister's `@self` / system fields.\n */\nconst METADATA_FIELDS = [\n\t{ key: 'id', label: 'ID', group: 'identity' },\n\t{ key: 'uuid', label: 'UUID', group: 'identity' },\n\t{ key: 'uri', label: 'URI', group: 'identity' },\n\t{ key: 'version', label: 'Version', group: 'identity' },\n\t{ key: 'register', label: 'Register', group: 'location' },\n\t{ key: 'schema', label: 'Schema', group: 'location' },\n\t{ key: 'schemaVersion', label: 'Schema version', group: 'location' },\n\t{ key: 'folder', label: 'Folder', group: 'location', format: 'folder' },\n\t{ key: 'owner', label: 'Owner', group: 'ownership' },\n\t{ key: 'organisation', label: 'Organisation', group: 'ownership' },\n\t{ key: 'organization', label: 'Organization', group: 'ownership' },\n\t{ key: 'status', label: 'Status', group: 'lifecycle' },\n\t{ key: 'created', label: 'Created', group: 'lifecycle', format: 'date-time' },\n\t{ key: 'updated', label: 'Updated', group: 'lifecycle', format: 'date-time' },\n\t{ key: 'locked', label: 'Locked', group: 'lifecycle', format: 'lock' },\n\t{ key: 'textRepresentation', label: 'Text Representation', group: 'identity' },\n]\n\n/**\n * The archival constraints, read from the resolved `@self._retention` decision.\n *\n * 🔴 THESE KEYS ARE MDTO CONCEPTS IN ENGLISH, and they changed with\n * openregister#3584: `nomination` became `appraisal`, `period` became\n * `retentionPeriod`, `actionDate` became `disposalDate`, `classification`\n * became `disposalCategory`, and the Archiefwet lifecycle arrived as\n * `recordState` with a derived `immutable`. MDTO supersedes TMLO, so\n * `archiefnominatie` is the superseded spelling of MDTO's `waardering`.\n *\n * They live one level down, under `_retention`, and `include` / `exclude`\n * address them by these same names.\n *\n * Two of the resolver's keys are deliberately not rows here. `immutable` is\n * derived from `recordState` and would only repeat what \"Transferred to\n * archive\" already says, and `annotation` is the raw rule-evaluation object\n * kept for debugging, which would land in the panel as JSON.\n *\n * Empty on an object whose schema declares no archival obligation, and that is\n * a real answer rather than a gap — see `emptyLabel`.\n */\nconst ARCHIVAL_FIELDS = [\n\t{ key: 'appraisal', label: 'Appraisal', group: 'archiving', format: 'appraisal', core: true },\n\t{ key: 'retentionPeriod', label: 'Retention period', group: 'archiving', format: 'duration', core: true },\n\t{ key: 'disposalDate', label: 'Disposal date', group: 'archiving', format: 'date', core: true },\n\t{ key: 'recordState', label: 'Record state', group: 'archiving', format: 'record-state', core: true },\n\t{ key: 'disposalCategory', label: 'Selection list category', group: 'archiving' },\n\t{ key: 'basis', label: 'Basis', group: 'archiving', format: 'basis' },\n\t{ key: 'source', label: 'Source', group: 'archiving' },\n\t// Which revision of the list, and when it was read (openregister#3588).\n\t// The same category carries different retention periods across revisions,\n\t// so a decision that names only the list cannot be defended once it moves.\n\t{ key: 'sourceVersion', label: 'Selection list version', group: 'archiving' },\n\t{ key: 'sourceConsultedAt', label: 'Consulted on', group: 'archiving', format: 'date' },\n\t{ key: 'legalHold', label: 'Legal hold', group: 'archiving', format: 'legal-hold' },\n]\n\n/**\n * The groups, in the order a reader works down them.\n *\n * Identity first (which record is this), then where it lives, who owns it, what\n * state it is in, and finally what happens to it. Archiving last because it is\n * the answer you go looking for rather than the one you scan past.\n */\nconst GROUPS = [\n\t{ key: 'identity', label: 'Identity' },\n\t{ key: 'location', label: 'Location' },\n\t{ key: 'ownership', label: 'Ownership' },\n\t{ key: 'lifecycle', label: 'Lifecycle' },\n\t{ key: 'archiving', label: 'Archiving' },\n]\n\n/**\n * CnObjectMetadataWidget — Read-only metadata display widget.\n *\n * Automatically extracts and formats metadata from an OpenRegister object.\n * Understands both flat objects (where metadata is at the top level) and\n * objects with a `@self` metadata block.\n *\n * Basic usage\n * ```vue\n * <CnObjectMetadataWidget :object-data=\"publication\" />\n * ```\n *\n * With extra items\n * ```vue\n * <CnObjectMetadataWidget\n * title=\"System Info\"\n * :object-data=\"entity\"\n * :extra-items=\"[\n * { label: 'Source', value: entity.source },\n * { label: 'Catalog', value: entity.catalog },\n * ]\" />\n * ```\n *\n * Selective display\n * ```vue\n * <CnObjectMetadataWidget\n * :object-data=\"entity\"\n * :include=\"['id', 'uuid', 'created', 'updated', 'owner']\" />\n * ```\n */\nexport default {\n\tname: 'CnObjectMetadataWidget',\n\n\tcomponents: {\n\t\tCnDetailCard,\n\t\tCnDetailGrid,\n\t},\n\n\tprops: {\n\t\t/** Widget title shown in the card header */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Metadata'),\n\t\t},\n\n\t\t/** Optional MDI icon component for the header */\n\t\ticon: {\n\t\t\ttype: [Object, Function],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * The object data containing metadata.\n\t\t * Supports flat objects and objects with `@self` metadata block.\n\t\t * Optional: null renders the empty state (and avoids a required-prop\n\t\t * warning on surfaces that mount before the object loads, e.g. a\n\t\t * `metadata` tab in CnObjectSidebar). Handled internally via\n\t\t * `this.objectData || {}`.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Layout mode for the grid: 'grid' or 'horizontal'.\n\t\t */\n\t\tlayout: {\n\t\t\ttype: String,\n\t\t\tdefault: 'horizontal',\n\t\t},\n\n\t\t/**\n\t\t * Number of grid columns (only for layout='grid').\n\t\t */\n\t\tcolumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\n\t\t/**\n\t\t * Min width for labels in horizontal layout.\n\t\t */\n\t\tlabelWidth: {\n\t\t\ttype: Number,\n\t\t\tdefault: 150,\n\t\t},\n\n\t\t/**\n\t\t * Additional metadata items to display.\n\t\t *\n\t\t * @type {Array<{ label: string, value: string|number }>}\n\t\t */\n\t\textraItems: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Metadata fields to include (whitelist). If null, all available are shown.\n\t\t *\n\t\t * @type {string[]|null}\n\t\t */\n\t\tinclude: {\n\t\t\ttype: Array,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Metadata fields to exclude.\n\t\t *\n\t\t * @type {string[]}\n\t\t */\n\t\texclude: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Whether the card can be collapsed */\n\t\tcollapsible: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Initial collapsed state */\n\t\tcollapsed: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Group the rows under category headings (Identity, Location,\n\t\t * Ownership, Lifecycle, Archiving) instead of rendering one flat list.\n\t\t *\n\t\t * On by default: a flat list of twenty rows is a wall to read. Pass\n\t\t * `false` for the previous single-grid shape.\n\t\t *\n\t\t * @type {boolean}\n\t\t */\n\t\tgrouped: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Heading for the items a host supplied through `extraItems`, which\n\t\t * carry no group of their own.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\totherLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Other'),\n\t\t},\n\n\t\t/** Label shown when no metadata available */\n\t\temptyLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'No metadata available'),\n\t\t},\n\t},\n\n\tcomputed: {\n\t\ticonComponent() {\n\t\t\treturn this.icon\n\t\t},\n\n\t\t/**\n\t\t * Merged metadata source: combines the `@self` block with top-level fields.\n\t\t *\n\t\t * @self fields take priority over top-level for shared keys.\n\t\t */\n\t\tmetadataSource() {\n\t\t\t// objectData is optional (and momentarily null during async loads or\n\t\t\t// when a parent binds a not-yet-resolved object), so guard before\n\t\t\t// reading `@self` to avoid a render-time TypeError.\n\t\t\tconst data = this.objectData || {}\n\t\t\tconst selfBlock = data['@self']\n\n\t\t\t// 🔴 WHEN THERE IS A `@self` BLOCK, IT IS THE ONLY METADATA SOURCE.\n\t\t\t//\n\t\t\t// This used to merge `{ ...data, ...selfBlock }`, which meant any\n\t\t\t// BUSINESS property sharing a name with a metadata field leaked into\n\t\t\t// the metadata list. Measured on a dossiq case: the panel reported\n\t\t\t// `STATUS active` — the case's own workflow status, a schema\n\t\t\t// property — while the page header beside it read `Unknown`, because\n\t\t\t// the two were reading different things and only one of them was\n\t\t\t// metadata. `version`, `owner`, `folder` and `locked` are all\n\t\t\t// perfectly ordinary property names and had the same exposure.\n\t\t\t//\n\t\t\t// A record WITHOUT a `@self` block is a different case: several\n\t\t\t// widget props pass a pre-flattened metadata object, and for those\n\t\t\t// the top level genuinely is the metadata. `id` is carried over\n\t\t\t// either way because the API mirrors it to the top level.\n\t\t\tif (selfBlock && typeof selfBlock === 'object') {\n\t\t\t\tconst carried = {}\n\t\t\t\tif (data.id !== undefined && selfBlock.id === undefined) {\n\t\t\t\t\tcarried.id = data.id\n\t\t\t\t}\n\t\t\t\treturn { ...carried, ...selfBlock }\n\t\t\t}\n\n\t\t\treturn { ...data }\n\t\t},\n\n\t\t/**\n\t\t * The resolved archival decision, or an empty object.\n\t\t *\n\t\t * Read from `@self._retention`, which OpenRegister's render layer fills\n\t\t * by merging the object's stored retention block, its schema's\n\t\t * `x-openregister-archival` evaluation and any legal hold. It is absent\n\t\t * entirely — not empty — on an object with no archival obligation, and\n\t\t * that distinction is deliberate on the server side, so it is preserved\n\t\t * here rather than defaulted into a row of dashes.\n\t\t */\n\t\tarchivalSource() {\n\t\t\tconst block = this.metadataSource._retention\n\t\t\tif (!block || typeof block !== 'object') {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\treturn block\n\t\t},\n\n\t\t/**\n\t\t * The same items, bucketed into the categories a reader scans.\n\t\t *\n\t\t * A group with nothing in it is dropped rather than rendered as an\n\t\t * empty heading — an object with no archival obligation should not\n\t\t * carry an \"Archiving\" heading over a void. `extraItems` carry no\n\t\t * group, so they collect under the host's own heading at the end.\n\t\t */\n\t\tgroupedItems() {\n\t\t\tconst byKey = new Map(GROUPS.map((g) => [g.key, { ...g, label: t('nextcloud-vue', g.label), items: [] }]))\n\t\t\tconst ungrouped = []\n\n\t\t\tfor (const item of this.metadataItems) {\n\t\t\t\tconst bucket = item.group ? byKey.get(item.group) : null\n\t\t\t\tif (bucket) {\n\t\t\t\t\tbucket.items.push(item)\n\t\t\t\t} else {\n\t\t\t\t\tungrouped.push(item)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst groups = [...byKey.values()].filter((g) => g.items.length > 0)\n\t\t\tif (ungrouped.length > 0) {\n\t\t\t\tgroups.push({ key: 'other', label: this.otherLabel, items: ungrouped })\n\t\t\t}\n\n\t\t\treturn groups\n\t\t},\n\n\t\t/**\n\t\t * Build the items array for CnDetailGrid from known metadata fields.\n\t\t */\n\t\tmetadataItems() {\n\t\t\tconst source = this.metadataSource\n\t\t\tconst items = []\n\n\t\t\tfor (const def of METADATA_FIELDS) {\n\t\t\t\t// Filter by include/exclude\n\t\t\t\tif (this.include && !this.include.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.exclude.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst raw = source[def.key]\n\t\t\t\tif (raw === undefined || raw === null) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\titems.push({\n\t\t\t\t\t// Translated at use, not at import: the bundles register\n\t\t\t\t\t// after this module loads, and a label resolved at import\n\t\t\t\t\t// time would stay English for every reader.\n\t\t\t\t\tlabel: t('nextcloud-vue', def.label),\n\t\t\t\t\tvalue: this.formatMetadataValue(raw, def),\n\t\t\t\t\tgroup: def.group,\n\t\t\t\t\thref: this.hrefFor(raw, def),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// The archival group, read one level down from `@self._retention`.\n\t\t\t// Appended after the identity fields rather than interleaved: what\n\t\t\t// happens to a record and when is a question of its own, and a\n\t\t\t// records officer reads the group, not one line of it.\n\t\t\t// nextcloud-vue#1062. When the object HAS an archival decision, an\n\t\t\t// absent core fact is itself the answer: a records officer reading\n\t\t\t// \"Disposal date: -\" learns there is no date yet, while a missing row\n\t\t\t// reads as a panel that never looked. So the four MDTO core rows\n\t\t\t// stay, blank, and so does any key a host named in `include`, which\n\t\t\t// is already the host saying \"this row matters to me\". Optional\n\t\t\t// provenance rows still only appear when they carry something.\n\t\t\t//\n\t\t\t// An object with NO decision keeps an empty Archiving group, which\n\t\t\t// the grouping drops entirely: \"no archival obligation\" and \"an\n\t\t\t// obligation with a gap\" are different answers and must look it.\n\t\t\tconst archival = this.archivalSource\n\t\t\tconst hasDecision = Object.keys(archival).length > 0\n\t\t\tfor (const def of ARCHIVAL_FIELDS) {\n\t\t\t\tif (this.include && !this.include.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (this.exclude.includes(def.key)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tconst raw = archival[def.key]\n\t\t\t\tconst absent = raw === undefined || raw === null\n\t\t\t\tif (absent && !(hasDecision && (def.core || this.include))) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\titems.push({\n\t\t\t\t\tlabel: t('nextcloud-vue', def.label),\n\t\t\t\t\tvalue: this.formatMetadataValue(raw, def),\n\t\t\t\t\tgroup: def.group,\n\t\t\t\t\tempty: absent,\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Append extra items\n\t\t\tfor (const item of this.extraItems) {\n\t\t\t\titems.push(item)\n\t\t\t}\n\n\t\t\treturn items\n\t\t},\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Format a metadata value for display.\n\t\t *\n\t\t * @param {unknown} value - The raw metadata value.\n\t\t * @param {object} def - The metadata field definition (format, label, etc.).\n\t\t */\n\t\tformatMetadataValue(value, def) {\n\t\t\tif (value === null || value === undefined) {\n\t\t\t\treturn '-'\n\t\t\t}\n\n\t\t\t// The lock is an object (`{ user, displayName, expiresAt }`) and used\n\t\t\t// to reach the panel as raw JSON, which reads as debug output rather\n\t\t\t// than as the one fact that matters: who is holding this, and until\n\t\t\t// when.\n\t\t\tif (def.format === 'lock') {\n\t\t\t\treturn this.formatLock(value)\n\t\t\t}\n\n\t\t\t// Archival formats. Each turns a stored code into the phrase an\n\t\t\t// archivist would say, and each falls back to the raw value rather\n\t\t\t// than hiding a code it has not been taught — an unrecognised\n\t\t\t// appraisal is still a records obligation.\n\t\t\tif (def.format === 'appraisal') {\n\t\t\t\treturn this.formatAppraisal(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'record-state') {\n\t\t\t\treturn this.formatRecordState(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'duration') {\n\t\t\t\treturn this.formatDuration(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'basis') {\n\t\t\t\treturn this.formatBasis(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'legal-hold') {\n\t\t\t\treturn this.formatLegalHold(value)\n\t\t\t}\n\n\t\t\tif (def.format === 'date') {\n\t\t\t\tconst date = new Date(value)\n\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t\treturn date.toLocaleDateString(userLocale(), {\n\t\t\t\t\tday: '2-digit',\n\t\t\t\t\tmonth: '2-digit',\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t})\n\t\t\t}\n\n\t\t\t// Date-time formatting\n\t\t\tif (def.format === 'date-time') {\n\t\t\t\ttry {\n\t\t\t\t\tconst date = new Date(value)\n\t\t\t\t\tif (Number.isNaN(date.getTime())) {\n\t\t\t\t\t\treturn String(value)\n\t\t\t\t\t}\n\t\t\t\t\treturn date.toLocaleDateString(userLocale(), {\n\t\t\t\t\t\tday: '2-digit',\n\t\t\t\t\t\tmonth: '2-digit',\n\t\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\t}) + ', ' + date.toLocaleTimeString(userLocale(), {\n\t\t\t\t\t\thour: '2-digit',\n\t\t\t\t\t\tminute: '2-digit',\n\t\t\t\t\t\tsecond: '2-digit',\n\t\t\t\t\t})\n\t\t\t\t} catch {\n\t\t\t\t\treturn String(value)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Booleans\n\t\t\tif (typeof value === 'boolean') {\n\t\t\t\treturn value ? 'Yes' : 'No'\n\t\t\t}\n\n\t\t\t// Arrays\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn value.length > 0 ? value.join(', ') : '-'\n\t\t\t}\n\n\t\t\t// Objects — show as JSON snippet\n\t\t\tif (typeof value === 'object') {\n\t\t\t\treturn JSON.stringify(value)\n\t\t\t}\n\n\t\t\treturn String(value)\n\t\t},\n\n\t\t/**\n\t\t * Render a lock as a sentence rather than as its JSON.\n\t\t *\n\t\t * @param {object} lock - The `@self.locked` payload.\n\t\t * @return {string} Who holds it, and until when.\n\t\t */\n\t\tformatLock(lock) {\n\t\t\tif (typeof lock !== 'object') {\n\t\t\t\treturn String(lock)\n\t\t\t}\n\t\t\tconst holder = lock.displayName || lock.user\n\t\t\tconst until = lock.expiresAt ? new Date(lock.expiresAt) : null\n\t\t\tconst hasUntil = until && !Number.isNaN(until.getTime())\n\n\t\t\tif (holder && hasUntil) {\n\t\t\t\treturn t('nextcloud-vue', 'Locked by {user} until {date}', {\n\t\t\t\t\tuser: holder,\n\t\t\t\t\tdate: until.toLocaleString(userLocale()),\n\t\t\t\t})\n\t\t\t}\n\n\t\t\tif (holder) {\n\t\t\t\treturn t('nextcloud-vue', 'Locked by {user}', { user: holder })\n\t\t\t}\n\n\t\t\treturn t('nextcloud-vue', 'Locked')\n\t\t},\n\n\t\t/**\n\t\t * Name what is going to happen to the record.\n\t\t *\n\t\t * @param {string} value - The stored appraisal.\n\t\t * @return {string} The phrase, or the raw code when unrecognised.\n\t\t */\n\t\tformatAppraisal(value) {\n\t\t\tconst known = {\n\t\t\t\tretain_permanently: t('nextcloud-vue', 'Keep permanently'),\n\t\t\t\tdestroy: t('nextcloud-vue', 'Destroy'),\n\t\t\t\tnot_yet_determined: t('nextcloud-vue', 'Not yet determined'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * Name the record's place in the Archiefwet lifecycle.\n\t\t *\n\t\t * @param {string} value - The record state.\n\t\t * @return {string} The phrase, or the raw value.\n\t\t */\n\t\tformatRecordState(value) {\n\t\t\tconst known = {\n\t\t\t\tactive: t('nextcloud-vue', 'Active'),\n\t\t\t\tsemi_static: t('nextcloud-vue', 'Semi-static'),\n\t\t\t\ttransferred: t('nextcloud-vue', 'Transferred to archive'),\n\t\t\t\tdestroyed: t('nextcloud-vue', 'Destroyed'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * A Files deep-link for a folder held as a numeric node id.\n\t\t *\n\t\t * `@self.folder` is a string that is USUALLY a node id and sometimes a\n\t\t * legacy path, so only the digit form gets a link — a path would produce\n\t\t * a URL that 404s, which is worse than plain text.\n\t\t *\n\t\t * @param {unknown} raw - The raw metadata value.\n\t\t * @param {object} def - The field definition.\n\t\t * @return {string|null} The href, or null when it is not linkable.\n\t\t */\n\t\threfFor(raw, def) {\n\t\t\tif (def.format !== 'folder') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst id = String(raw).trim()\n\t\t\tif (!/^\\d+$/.test(id)) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn generateUrl('/apps/files/?fileid={id}&opendetails=true', { id })\n\t\t},\n\n\t\t/**\n\t\t * Turn an ISO-8601 duration into something readable.\n\t\t *\n\t\t * Deliberately handles only the whole-year / whole-month / whole-day\n\t\t * forms a retention period is actually written in (`P10Y`, `P6M`,\n\t\t * `P30D`). Anything else is returned as-is rather than parsed\n\t\t * half-correctly, because a retention period rendered wrong is worse\n\t\t * than one rendered raw.\n\t\t *\n\t\t * @param {string} value - The ISO-8601 duration.\n\t\t * @return {string} The readable period, or the raw duration.\n\t\t */\n\t\tformatDuration(value) {\n\t\t\tconst match = /^P(\\d+)([YMD])$/.exec(String(value))\n\t\t\tif (!match) {\n\t\t\t\treturn String(value)\n\t\t\t}\n\n\t\t\tconst amount = Number(match[1])\n\t\t\tif (match[2] === 'Y') {\n\t\t\t\treturn n('nextcloud-vue', '%n year', '%n years', amount)\n\t\t\t}\n\t\t\tif (match[2] === 'M') {\n\t\t\t\treturn n('nextcloud-vue', '%n month', '%n months', amount)\n\t\t\t}\n\t\t\treturn n('nextcloud-vue', '%n day', '%n days', amount)\n\t\t},\n\n\t\t/**\n\t\t * Say on whose authority the retention period rests.\n\t\t *\n\t\t * @param {string} value - The basis code.\n\t\t * @return {string} The phrase, or the raw code.\n\t\t */\n\t\tformatBasis(value) {\n\t\t\tconst known = {\n\t\t\t\tselection_list: t('nextcloud-vue', 'Selection list'),\n\t\t\t\t// Its own answer, not a variant of \"schema\": the schema expected\n\t\t\t\t// a selection list and none was consulted, which an operator who\n\t\t\t\t// believes one is configured needs to be told.\n\t\t\t\tselection_list_not_consulted: t('nextcloud-vue', 'Selection list not consulted'),\n\t\t\t\tschema: t('nextcloud-vue', 'Schema archive settings'),\n\t\t\t\tschema_annotation: t('nextcloud-vue', 'Schema archival annotation'),\n\t\t\t\ttmlo: t('nextcloud-vue', 'Record archival metadata'),\n\t\t\t\trecord: t('nextcloud-vue', 'Recorded on the object'),\n\t\t\t}\n\t\t\treturn known[value] || String(value)\n\t\t},\n\n\t\t/**\n\t\t * Render the legal-hold state.\n\t\t *\n\t\t * A released hold still reports itself: \"held once and released\" is a\n\t\t * different fact from \"never held\", and an archivist reads the\n\t\t * difference.\n\t\t *\n\t\t * @param {object} hold - The resolved hold state.\n\t\t * @return {string} The hold sentence.\n\t\t */\n\t\tformatLegalHold(hold) {\n\t\t\tif (typeof hold !== 'object') {\n\t\t\t\treturn String(hold)\n\t\t\t}\n\n\t\t\tif (hold.active) {\n\t\t\t\tif (hold.reason) {\n\t\t\t\t\treturn t('nextcloud-vue', 'On hold: {reason}', { reason: hold.reason })\n\t\t\t\t}\n\t\t\t\treturn t('nextcloud-vue', 'On hold')\n\t\t\t}\n\n\t\t\tif (hold.releasedCount) {\n\t\t\t\treturn n('nextcloud-vue', 'Released, %n earlier hold', 'Released, %n earlier holds', hold.releasedCount)\n\t\t\t}\n\n\t\t\treturn t('nextcloud-vue', 'No hold')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* Group headings. Quiet enough that they organise without competing with the\n values they sit over — a category label is a signpost, not content. */\n.cn-object-metadata__group + .cn-object-metadata__group {\n\tmargin-top: calc(3 * var(--default-grid-baseline, 4px));\n}\n\n.cn-object-metadata__group-title {\n\tmargin: 0 0 calc(0.5 * var(--default-grid-baseline, 4px));\n\tfont-size: 0.8em;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* Override CnDetailGrid item styling for a compact table-like appearance */\n:deep(.cn-detail-grid__item) {\n\tbackground: none;\n\tborder-radius: 0;\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding: calc(1.5 * var(--default-grid-baseline, 4px)) 0;\n}\n\n:deep(.cn-detail-grid__item:last-child) {\n\tborder-bottom: none;\n}\n\n:deep(.cn-detail-grid--horizontal) {\n\tgap: 0;\n}\n\n:deep(.cn-detail-grid__label) {\n\tfont-size: 0.8em;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.02em;\n}\n\n:deep(.cn-detail-grid__value) {\n\tfont-size: 0.9em;\n\tword-break: break-all;\n\tmargin: 0;\n}\n</style>\n"],"names":["_renderSlot","_createElementBlock","_Fragment","_renderList","_toDisplayString"],"mappings":";;AAqCQ,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,iCAAiB,GAAA;;;;;;;AAlBf,IAAA,KAAI,EAAG,MAAK,CAAA,KAAA;QACrB,EAAE,QAAa,CAAA,aAAA;eACR,EAAC,MAAY,CAAA,WAAA;AACpB,IAAA,SAAK,EAAG,MAAQ,CAAA,SAAA;;AACV,IAAA,OAAO,UACjB,MAAG;MAAHA,UAAG,CAAA,IAAA,CAAA,MAAA,EAAA,SAAA,CAAA;;qBAQD,MAgBQ;OAhBK,MAAM,CAAA,OAAA,IAAA,QAAA,CAAA,YAAA,CAAA,MAAA,GAAA,CAAA;4BACnBC,kBAcI,CAAAC,QAAA,EAAA,EAAA,GAAA,EAAA,CAAA,EAAA,EAAAC,UAAA,CAbW,QAAE,CAAA,YAAA,EAAA,CAAX,KAAK,KAAA;iCADXF,kBAcI,CAAA,KAAA,EAAA;cAZJ,GAAG,EAAE,KAAK,CAAC,GAAG;AACd,cAAA,KAAI,EAAC,2BAAS;;iCAGV,gBAAA,EADDG,eAAA,CAAA,KAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;yBAQU,CAAA,uBAAA,EAAA;gBALb,KAAM,EAAE,KAAK,CAAC,KAAK;sBACZ,QAAQ,CAAA,MAAA;AACd,gBAAA,OAAO,EAAC,MAAA,CAAA,OAAA;AACR,gBAAA,UAAE,EAAA,MAAA,CAAA,UAAA;AACF,gBAAA,MAAM,EAAE,KAAK;AACb,gBAAA,UAAU,EAAE,MAAA,CAAA,UAAA;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -2,7 +2,7 @@ import script from './CnAuditTrailTab.vue2.js';
|
|
|
2
2
|
import { render } from './CnAuditTrailTab.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-1f3f9f5d";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -6,6 +6,7 @@ import History from 'vue-material-design-icons/History.vue';
|
|
|
6
6
|
import __sfc_main from '../../dialogs/CnConfirmDialog.vue.js';
|
|
7
7
|
import { useRestoreVersion } from '../../composables/useRestoreVersion.js';
|
|
8
8
|
import { isObjectLocked, isLockedByCurrentUser, lockHolder } from '../../utils/objectLock.js';
|
|
9
|
+
import { userLocale } from '../../utils/userLocale.js';
|
|
9
10
|
import { buildHeaders } from '../../utils/headers.js';
|
|
10
11
|
|
|
11
12
|
var script = {
|
|
@@ -287,7 +288,7 @@ var script = {
|
|
|
287
288
|
return ''
|
|
288
289
|
}
|
|
289
290
|
try {
|
|
290
|
-
return new Date(dateStr).toLocaleString(
|
|
291
|
+
return new Date(dateStr).toLocaleString(userLocale(), {
|
|
291
292
|
year: 'numeric',
|
|
292
293
|
month: 'short',
|
|
293
294
|
day: 'numeric',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnAuditTrailTab.vue2.js","sources":["../../../../src/components/CnObjectSidebar/CnAuditTrailTab.vue"],"sourcesContent":["<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<template v-else-if=\"entries.length > 0\">\n\t\t\t<!-- Filters -->\n\t\t\t<div class=\"cn-audit-filters\">\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"filterAction\"\n\t\t\t\t\t:options=\"actionOptions\"\n\t\t\t\t\t:placeholder=\"actionFilterLabel\"\n\t\t\t\t\t:inputLabel=\"actionFilterLabel\"\n\t\t\t\t\t:multiple=\"true\"\n\t\t\t\t\t:keepOpen=\"true\"\n\t\t\t\t\tclass=\"cn-audit-filters__select\" />\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"filterUser\"\n\t\t\t\t\t:options=\"userOptions\"\n\t\t\t\t\t:placeholder=\"userFilterLabel\"\n\t\t\t\t\t:inputLabel=\"userFilterLabel\"\n\t\t\t\t\t:multiple=\"true\"\n\t\t\t\t\t:keepOpen=\"true\"\n\t\t\t\t\tclass=\"cn-audit-filters__select\" />\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tid=\"audit-date-from\"\n\t\t\t\t\tv-model=\"filterDateFrom\"\n\t\t\t\t\t:label=\"fromLabel\"\n\t\t\t\t\ttype=\"date\"\n\t\t\t\t\tclass=\"cn-audit-filters__date\" />\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tid=\"audit-date-to\"\n\t\t\t\t\tv-model=\"filterDateTo\"\n\t\t\t\t\t:label=\"toLabel\"\n\t\t\t\t\ttype=\"date\"\n\t\t\t\t\tclass=\"cn-audit-filters__date\" />\n\t\t\t</div>\n\n\t\t\t<div v-if=\"entries.length === 0 && !loading\" class=\"cn-sidebar-tab__empty\">\n\t\t\t\t{{ noMatchLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-sidebar-tab__list\">\n\t\t\t\t<div v-for=\"entry in entries\" :key=\"entry.id\" class=\"cn-audit-entry\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\t:name=\"formatDate(entry.created)\"\n\t\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t\t:details=\"entry.action\"\n\t\t\t\t\t\t:counterNumber=\"changedCount(entry)\"\n\t\t\t\t\t\t@click=\"toggleExpand(entry.id)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<History :size=\"32\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t{{ entry.userName || entry.user || 'System' }}\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t\t<!-- Expandable details -->\n\t\t\t\t\t<div v-if=\"expandedId === entry.id\" class=\"cn-audit-details\">\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Action</span>\n\t\t\t\t\t\t\t<span>{{ entry.action }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">User</span>\n\t\t\t\t\t\t\t<span>{{ entry.userName || entry.user || 'System' }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Date</span>\n\t\t\t\t\t\t\t<span>{{ formatDate(entry.created) }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"entry.ipAddress\" class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">IP</span>\n\t\t\t\t\t\t\t<span>{{ entry.ipAddress }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"entry.session\" class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Session</span>\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__mono\">{{ entry.session }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- Restore (allowRestore only; create and update entries) -->\n\t\t\t\t\t\t<div v-if=\"canRestore(entry)\" class=\"cn-audit-details__restore\">\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t\t:disabled=\"restoreBlocked\"\n\t\t\t\t\t\t\t\t:title=\"restoreBlocked ? restoreLockedLabel : undefined\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-audit-restore\"\n\t\t\t\t\t\t\t\t@click.stop=\"askRestore(entry)\">\n\t\t\t\t\t\t\t\t{{ restoreLabel }}\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- Changed fields -->\n\t\t\t\t\t\t<div v-if=\"entry.changed && Object.keys(entry.changed).length > 0\" class=\"cn-audit-details__changes\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Changes</span>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tv-for=\"(change, field) in entry.changed\"\n\t\t\t\t\t\t\t\t:key=\"field\"\n\t\t\t\t\t\t\t\tclass=\"cn-audit-details__change\">\n\t\t\t\t\t\t\t\t<span class=\"cn-audit-details__field\">{{ field }}</span>\n\t\t\t\t\t\t\t\t<div v-if=\"isSimpleValue(change)\" class=\"cn-audit-details__values\">\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old !== null && change.old !== undefined\" class=\"cn-audit-details__old\">{{ formatValue(change.old) }}</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old !== null && change.new !== null\" class=\"cn-audit-details__arrow\">→</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.new !== null && change.new !== undefined\" class=\"cn-audit-details__new\">{{ formatValue(change.new) }}</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old === null && change.new === null\" class=\"cn-audit-details__null\">null</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div v-else class=\"cn-audit-details__values\">\n\t\t\t\t\t\t\t\t\t<span class=\"cn-audit-details__mono\">{{ formatValue(change) }}</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<!-- Load more -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"hasMore\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:wide=\"true\"\n\t\t\t\t\t:disabled=\"loadingMore\"\n\t\t\t\t\tclass=\"cn-sidebar-tab__load-more\"\n\t\t\t\t\t@click=\"loadMore\">\n\t\t\t\t\t<template v-if=\"loadingMore\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ loadMoreLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</template>\n\t\t<div v-else class=\"cn-sidebar-tab__empty\">\n\t\t\t{{ noAuditTrailLabel }}\n\t\t</div>\n\t\t<CnConfirmDialog\n\t\t\tv-if=\"restoreEntry\"\n\t\t\tref=\"restoreDialog\"\n\t\t\t:dialogTitle=\"restoreLabel + '?'\"\n\t\t\t:message=\"restoreMessage\"\n\t\t\t:confirmLabel=\"restoreLabel\"\n\t\t\t:successText=\"restoredLabel\"\n\t\t\t@confirm=\"confirmRestore\"\n\t\t\t@close=\"restoreEntry = null\" />\n\t</div>\n</template>\n\n<script>\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcDateTimePickerNative, NcListItem, NcLoadingIcon, NcSelect } from '@nextcloud/vue'\nimport History from 'vue-material-design-icons/History.vue'\nimport CnConfirmDialog from '../../dialogs/CnConfirmDialog.vue'\nimport { useRestoreVersion } from '../../composables/useRestoreVersion.js'\nimport { buildHeaders } from '../../utils/index.js'\nimport { isLockedByCurrentUser, isObjectLocked, lockHolder } from '../../utils/objectLock.js'\n\nexport default {\n\tname: 'CnAuditTrailTab',\n\n\tcomponents: { CnConfirmDialog, NcButton, NcListItem, NcLoadingIcon, NcSelect, NcDateTimePickerNative, History },\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Text shown when there are no audit trail entries */\n\t\tnoAuditTrailLabel: { type: String, default: () => t('nextcloud-vue', 'No audit trail entries') },\n\t\t/** Text shown when no entries match the current filter */\n\t\tnoMatchLabel: { type: String, default: () => t('nextcloud-vue', 'No matching entries') },\n\t\t/** Label for the action filter control */\n\t\tactionFilterLabel: { type: String, default: () => t('nextcloud-vue', 'Action') },\n\t\t/** Label for the user filter control */\n\t\tuserFilterLabel: { type: String, default: () => t('nextcloud-vue', 'User') },\n\t\t/** Label for the date-from filter */\n\t\tfromLabel: { type: String, default: () => t('nextcloud-vue', 'From') },\n\t\t/** Label for the date-to filter */\n\t\ttoLabel: { type: String, default: () => t('nextcloud-vue', 'To') },\n\t\t/** Label for the load-more button */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/**\n\t\t * Offer \"Restore this version\" on an expanded create or update entry.\n\t\t * Off by default: a tab rendered without it shows no button.\n\t\t */\n\t\tallowRestore: { type: Boolean, default: false },\n\t\t/**\n\t\t * The record as the page holds it. Read for `@self.actions` (the button\n\t\t * is hidden when the reader may not update) and for the lock.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: { type: Object, default: null },\n\t},\n\n\temits: ['restored'],\n\n\tdata() {\n\t\treturn {\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\texpandedId: null,\n\t\t\tfilterAction: [],\n\t\t\tfilterUser: [],\n\t\t\tfilterDateFrom: null,\n\t\t\tfilterDateTo: null,\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tlimit: 20,\n\t\t\tactionOptions: ['create', 'read', 'update', 'delete'],\n\t\t\tuserOptions: [],\n\t\t\trestoreEntry: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\thasMore() {\n\t\t\treturn this.entries.length < this.total\n\t\t},\n\n\t\t/** Whether the record's lock belongs to somebody else. */\n\t\trestoreBlocked() {\n\t\t\treturn isObjectLocked(this.objectData) && !isLockedByCurrentUser(this.objectData)\n\t\t},\n\n\t\trestoreLabel() {\n\t\t\treturn t('nextcloud-vue', 'Restore this version')\n\t\t},\n\n\t\trestoredLabel() {\n\t\t\treturn t('nextcloud-vue', 'The record was restored.')\n\t\t},\n\n\t\trestoreLockedLabel() {\n\t\t\tconst holder = lockHolder(this.objectData)\n\t\t\treturn holder\n\t\t\t\t? t('nextcloud-vue', 'This record is locked by {name}.', { name: holder })\n\t\t\t\t: t('nextcloud-vue', 'This record is locked by someone else.')\n\t\t},\n\n\t\t/** The confirm text: which entry, and that nothing is removed. */\n\t\trestoreMessage() {\n\t\t\tif (!this.restoreEntry) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Restore the record to how it was after the change by {user} on {date}? This is saved as a new version and nothing is removed.', {\n\t\t\t\tuser: this.restoreEntry.userName || this.restoreEntry.user || 'System',\n\t\t\t\tdate: this.formatDate(this.restoreEntry.created),\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchAuditTrails()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tfilterAction() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterUser() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterDateFrom() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterDateTo() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tresetAndFetch() {\n\t\t\tthis.page = 1\n\t\t\tthis.entries = []\n\t\t\tthis.fetchAuditTrails()\n\t\t},\n\n\t\tbuildQueryParams() {\n\t\t\tconst params = new URLSearchParams()\n\t\t\tparams.set('limit', this.limit)\n\t\t\tparams.set('_page', this.page)\n\t\t\tparams.set('_sort[created]', 'DESC')\n\t\t\tif (this.filterAction?.length) {\n\t\t\t\tparams.set('action', this.filterAction.join(','))\n\t\t\t}\n\t\t\tif (this.filterUser?.length) {\n\t\t\t\tparams.set('user_name', this.filterUser.join(','))\n\t\t\t}\n\t\t\tif (this.filterDateFrom) {\n\t\t\t\tparams.set('_dateFrom', new Date(this.filterDateFrom).toISOString().split('T')[0])\n\t\t\t}\n\t\t\tif (this.filterDateTo) {\n\t\t\t\tparams.set('_dateTo', new Date(this.filterDateTo).toISOString().split('T')[0])\n\t\t\t}\n\t\t\treturn params.toString()\n\t\t},\n\n\t\tasync fetchAuditTrails() {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = this.page === 1\n\t\t\tthis.loadingMore = this.page > 1\n\t\t\ttry {\n\t\t\t\tconst query = this.buildQueryParams()\n\t\t\t\t// generateUrl prepends the Nextcloud webroot + `/index.php` so the\n\t\t\t\t// request resolves on instances without URL rewriting.\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails`)\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\t`${url}?${query}`,\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst results = data.results || data || []\n\t\t\t\t\tif (this.page === 1) {\n\t\t\t\t\t\tthis.entries = results\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.entries = [...this.entries, ...results]\n\t\t\t\t\t}\n\t\t\t\t\tthis.total = data.total || this.entries.length\n\t\t\t\t\t// Build user options from all seen entries\n\t\t\t\t\tconst users = new Set(this.entries.map((e) => e.userName || e.user).filter(Boolean))\n\t\t\t\t\tthis.userOptions = [...users].sort()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnAuditTrailTab: Failed to fetch audit trails', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.loadingMore = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an entry shows the restore button.\n\t\t *\n\t\t * @param {object} entry The audit-trail entry.\n\t\t * @return {boolean} True for a create or update entry when restore is allowed and the reader may update.\n\t\t */\n\t\tcanRestore(entry) {\n\t\t\tif (!this.allowRestore || !['create', 'update'].includes(entry.action)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst actions = this.objectData?.['@self']?.actions\n\t\t\treturn !Array.isArray(actions) || actions.includes('update')\n\t\t},\n\n\t\t/**\n\t\t * Open the confirm dialog for an entry.\n\t\t *\n\t\t * @param {object} entry The audit-trail entry to restore to.\n\t\t */\n\t\taskRestore(entry) {\n\t\t\tif (!this.restoreBlocked) {\n\t\t\t\tthis.restoreEntry = entry\n\t\t\t}\n\t\t},\n\n\t\t/** Call the revert route for the chosen entry and report back to the dialog. */\n\t\tasync confirmRestore() {\n\t\t\tconst entry = this.restoreEntry\n\t\t\tconst { restore } = useRestoreVersion({ apiBase: this.apiBase })\n\t\t\tconst result = await restore({\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tauditTrailId: entry.id,\n\t\t\t\tobject: this.objectData,\n\t\t\t})\n\t\t\tif (result.ok) {\n\t\t\t\tthis.page = 1\n\t\t\t\tthis.entries = []\n\t\t\t\tawait this.fetchAuditTrails()\n\t\t\t\t/**\n\t\t\t\t * @event restored Emitted with the restored record after a successful restore.\n\t\t\t\t * @type {object|null}\n\t\t\t\t */\n\t\t\t\tthis.$emit('restored', result.record)\n\t\t\t\temit('cn:page:refresh')\n\t\t\t} else if (result.status === 423) {\n\t\t\t\t// Re-read the record so the page shows the lock.\n\t\t\t\temit('cn:page:refresh')\n\t\t\t}\n\t\t\tthis.$refs.restoreDialog?.setResult(result.ok ? { success: true } : { error: result.message })\n\t\t},\n\n\t\tloadMore() {\n\t\t\tthis.page++\n\t\t\tthis.fetchAuditTrails()\n\t\t},\n\n\t\ttoggleExpand(id) {\n\t\t\tthis.expandedId = this.expandedId === id ? null : id\n\t\t},\n\n\t\tchangedCount(entry) {\n\t\t\tif (!entry.changed || typeof entry.changed !== 'object') {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Object.keys(entry.changed).length\n\t\t},\n\n\t\tisSimpleValue(change) {\n\t\t\treturn change && typeof change === 'object' && ('old' in change || 'new' in change)\n\t\t},\n\n\t\tformatValue(val) {\n\t\t\tif (val === null || val === undefined) {\n\t\t\t\treturn 'null'\n\t\t\t}\n\t\t\tif (typeof val === 'object') {\n\t\t\t\treturn JSON.stringify(val)\n\t\t\t}\n\t\t\treturn String(val)\n\t\t},\n\n\t\tformatDate(dateStr) {\n\t\t\tif (!dateStr) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(dateStr).toLocaleString(undefined, {\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\thour: '2-digit',\n\t\t\t\t\tminute: '2-digit',\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn dateStr\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; }\n\n.cn-audit-filters {\n\tdisplay: grid;\n\tgrid-template-columns: 1fr 1fr;\n\tgap: 8px;\n\tmargin-bottom: 12px;\n}\n\n.cn-audit-filters__select { min-width: 0; }\n\n.cn-audit-filters__date { min-width: 0; }\n\n.cn-sidebar-tab__load-more { margin-top: 8px; }\n\n.cn-audit-entry { cursor: pointer; }\n\n.cn-audit-details {\n\tpadding: 8px 12px 12px 52px;\n\tfont-size: 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tanimation: cn-slide-down 0.15s ease;\n}\n\n@keyframes cn-slide-down {\n\tfrom { opacity: 0; max-height: 0; }\n\tto { opacity: 1; max-height: 600px; }\n}\n\n.cn-audit-details__restore { margin: 8px 0; }\n\n.cn-audit-details__row {\n\tdisplay: flex;\n\tgap: 8px;\n\tpadding: 2px 0;\n}\n\n.cn-audit-details__label {\n\tcolor: var(--color-text-maxcontrast);\n\tmin-width: 56px;\n\tfont-weight: 500;\n}\n\n.cn-audit-details__mono {\n\tfont-family: monospace;\n\tfont-size: 11px;\n\tword-break: break-all;\n}\n\n.cn-audit-details__changes {\n\tmargin-top: 8px;\n\tpadding-top: 8px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-audit-details__change {\n\tpadding: 4px 0 4px 8px;\n\tborder-left: 2px solid var(--color-border);\n\tmargin: 4px 0;\n}\n\n.cn-audit-details__field {\n\tfont-weight: 500;\n\tdisplay: block;\n\tmargin-bottom: 2px;\n}\n\n.cn-audit-details__values {\n\tdisplay: flex;\n\tgap: 6px;\n\talign-items: baseline;\n\tflex-wrap: wrap;\n}\n\n.cn-audit-details__old {\n\tcolor: var(--color-error, #e53935);\n\ttext-decoration: line-through;\n}\n\n.cn-audit-details__arrow {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-audit-details__new {\n\tcolor: var(--color-success, #43a047);\n}\n\n.cn-audit-details__null {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-style: italic;\n}\n</style>\n"],"names":["CnConfirmDialog","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnAuditTrailTab.vue2.js","sources":["../../../../src/components/CnObjectSidebar/CnAuditTrailTab.vue"],"sourcesContent":["<template>\n\t<div class=\"cn-sidebar-tab\">\n\t\t<NcLoadingIcon v-if=\"loading\" />\n\t\t<template v-else-if=\"entries.length > 0\">\n\t\t\t<!-- Filters -->\n\t\t\t<div class=\"cn-audit-filters\">\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"filterAction\"\n\t\t\t\t\t:options=\"actionOptions\"\n\t\t\t\t\t:placeholder=\"actionFilterLabel\"\n\t\t\t\t\t:inputLabel=\"actionFilterLabel\"\n\t\t\t\t\t:multiple=\"true\"\n\t\t\t\t\t:keepOpen=\"true\"\n\t\t\t\t\tclass=\"cn-audit-filters__select\" />\n\t\t\t\t<NcSelect\n\t\t\t\t\tv-model=\"filterUser\"\n\t\t\t\t\t:options=\"userOptions\"\n\t\t\t\t\t:placeholder=\"userFilterLabel\"\n\t\t\t\t\t:inputLabel=\"userFilterLabel\"\n\t\t\t\t\t:multiple=\"true\"\n\t\t\t\t\t:keepOpen=\"true\"\n\t\t\t\t\tclass=\"cn-audit-filters__select\" />\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tid=\"audit-date-from\"\n\t\t\t\t\tv-model=\"filterDateFrom\"\n\t\t\t\t\t:label=\"fromLabel\"\n\t\t\t\t\ttype=\"date\"\n\t\t\t\t\tclass=\"cn-audit-filters__date\" />\n\t\t\t\t<NcDateTimePickerNative\n\t\t\t\t\tid=\"audit-date-to\"\n\t\t\t\t\tv-model=\"filterDateTo\"\n\t\t\t\t\t:label=\"toLabel\"\n\t\t\t\t\ttype=\"date\"\n\t\t\t\t\tclass=\"cn-audit-filters__date\" />\n\t\t\t</div>\n\n\t\t\t<div v-if=\"entries.length === 0 && !loading\" class=\"cn-sidebar-tab__empty\">\n\t\t\t\t{{ noMatchLabel }}\n\t\t\t</div>\n\t\t\t<div v-else class=\"cn-sidebar-tab__list\">\n\t\t\t\t<div v-for=\"entry in entries\" :key=\"entry.id\" class=\"cn-audit-entry\">\n\t\t\t\t\t<NcListItem\n\t\t\t\t\t\t:name=\"formatDate(entry.created)\"\n\t\t\t\t\t\t:bold=\"false\"\n\t\t\t\t\t\t:details=\"entry.action\"\n\t\t\t\t\t\t:counterNumber=\"changedCount(entry)\"\n\t\t\t\t\t\t@click=\"toggleExpand(entry.id)\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<History :size=\"32\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<template #subname>\n\t\t\t\t\t\t\t{{ entry.userName || entry.user || 'System' }}\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</NcListItem>\n\t\t\t\t\t<!-- Expandable details -->\n\t\t\t\t\t<div v-if=\"expandedId === entry.id\" class=\"cn-audit-details\">\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Action</span>\n\t\t\t\t\t\t\t<span>{{ entry.action }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">User</span>\n\t\t\t\t\t\t\t<span>{{ entry.userName || entry.user || 'System' }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Date</span>\n\t\t\t\t\t\t\t<span>{{ formatDate(entry.created) }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"entry.ipAddress\" class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">IP</span>\n\t\t\t\t\t\t\t<span>{{ entry.ipAddress }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div v-if=\"entry.session\" class=\"cn-audit-details__row\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Session</span>\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__mono\">{{ entry.session }}</span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- Restore (allowRestore only; create and update entries) -->\n\t\t\t\t\t\t<div v-if=\"canRestore(entry)\" class=\"cn-audit-details__restore\">\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t\t\t:disabled=\"restoreBlocked\"\n\t\t\t\t\t\t\t\t:title=\"restoreBlocked ? restoreLockedLabel : undefined\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-audit-restore\"\n\t\t\t\t\t\t\t\t@click.stop=\"askRestore(entry)\">\n\t\t\t\t\t\t\t\t{{ restoreLabel }}\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<!-- Changed fields -->\n\t\t\t\t\t\t<div v-if=\"entry.changed && Object.keys(entry.changed).length > 0\" class=\"cn-audit-details__changes\">\n\t\t\t\t\t\t\t<span class=\"cn-audit-details__label\">Changes</span>\n\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\tv-for=\"(change, field) in entry.changed\"\n\t\t\t\t\t\t\t\t:key=\"field\"\n\t\t\t\t\t\t\t\tclass=\"cn-audit-details__change\">\n\t\t\t\t\t\t\t\t<span class=\"cn-audit-details__field\">{{ field }}</span>\n\t\t\t\t\t\t\t\t<div v-if=\"isSimpleValue(change)\" class=\"cn-audit-details__values\">\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old !== null && change.old !== undefined\" class=\"cn-audit-details__old\">{{ formatValue(change.old) }}</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old !== null && change.new !== null\" class=\"cn-audit-details__arrow\">→</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.new !== null && change.new !== undefined\" class=\"cn-audit-details__new\">{{ formatValue(change.new) }}</span>\n\t\t\t\t\t\t\t\t\t<span v-if=\"change.old === null && change.new === null\" class=\"cn-audit-details__null\">null</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div v-else class=\"cn-audit-details__values\">\n\t\t\t\t\t\t\t\t\t<span class=\"cn-audit-details__mono\">{{ formatValue(change) }}</span>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<!-- Load more -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"hasMore\"\n\t\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t\t:wide=\"true\"\n\t\t\t\t\t:disabled=\"loadingMore\"\n\t\t\t\t\tclass=\"cn-sidebar-tab__load-more\"\n\t\t\t\t\t@click=\"loadMore\">\n\t\t\t\t\t<template v-if=\"loadingMore\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ loadMoreLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</template>\n\t\t<div v-else class=\"cn-sidebar-tab__empty\">\n\t\t\t{{ noAuditTrailLabel }}\n\t\t</div>\n\t\t<CnConfirmDialog\n\t\t\tv-if=\"restoreEntry\"\n\t\t\tref=\"restoreDialog\"\n\t\t\t:dialogTitle=\"restoreLabel + '?'\"\n\t\t\t:message=\"restoreMessage\"\n\t\t\t:confirmLabel=\"restoreLabel\"\n\t\t\t:successText=\"restoredLabel\"\n\t\t\t@confirm=\"confirmRestore\"\n\t\t\t@close=\"restoreEntry = null\" />\n\t</div>\n</template>\n\n<script>\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcDateTimePickerNative, NcListItem, NcLoadingIcon, NcSelect } from '@nextcloud/vue'\nimport History from 'vue-material-design-icons/History.vue'\nimport CnConfirmDialog from '../../dialogs/CnConfirmDialog.vue'\nimport { useRestoreVersion } from '../../composables/useRestoreVersion.js'\nimport { buildHeaders } from '../../utils/index.js'\nimport { isLockedByCurrentUser, isObjectLocked, lockHolder } from '../../utils/objectLock.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\nexport default {\n\tname: 'CnAuditTrailTab',\n\n\tcomponents: { CnConfirmDialog, NcButton, NcListItem, NcLoadingIcon, NcSelect, NcDateTimePickerNative, History },\n\n\tprops: {\n\t\t/** ID of the object this tab belongs to */\n\t\tobjectId: { type: String, required: true },\n\t\t/** OpenRegister register slug */\n\t\tregister: { type: String, default: '' },\n\t\t/** JSON Schema definition for the object */\n\t\tschema: { type: String, default: '' },\n\t\t/** Base URL for the OpenRegister API */\n\t\tapiBase: { type: String, default: '/apps/openregister/api' },\n\t\t/** Text shown when there are no audit trail entries */\n\t\tnoAuditTrailLabel: { type: String, default: () => t('nextcloud-vue', 'No audit trail entries') },\n\t\t/** Text shown when no entries match the current filter */\n\t\tnoMatchLabel: { type: String, default: () => t('nextcloud-vue', 'No matching entries') },\n\t\t/** Label for the action filter control */\n\t\tactionFilterLabel: { type: String, default: () => t('nextcloud-vue', 'Action') },\n\t\t/** Label for the user filter control */\n\t\tuserFilterLabel: { type: String, default: () => t('nextcloud-vue', 'User') },\n\t\t/** Label for the date-from filter */\n\t\tfromLabel: { type: String, default: () => t('nextcloud-vue', 'From') },\n\t\t/** Label for the date-to filter */\n\t\ttoLabel: { type: String, default: () => t('nextcloud-vue', 'To') },\n\t\t/** Label for the load-more button */\n\t\tloadMoreLabel: { type: String, default: () => t('nextcloud-vue', 'Load more') },\n\t\t/**\n\t\t * Offer \"Restore this version\" on an expanded create or update entry.\n\t\t * Off by default: a tab rendered without it shows no button.\n\t\t */\n\t\tallowRestore: { type: Boolean, default: false },\n\t\t/**\n\t\t * The record as the page holds it. Read for `@self.actions` (the button\n\t\t * is hidden when the reader may not update) and for the lock.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobjectData: { type: Object, default: null },\n\t},\n\n\temits: ['restored'],\n\n\tdata() {\n\t\treturn {\n\t\t\tentries: [],\n\t\t\tloading: false,\n\t\t\tloadingMore: false,\n\t\t\texpandedId: null,\n\t\t\tfilterAction: [],\n\t\t\tfilterUser: [],\n\t\t\tfilterDateFrom: null,\n\t\t\tfilterDateTo: null,\n\t\t\tpage: 1,\n\t\t\ttotal: 0,\n\t\t\tlimit: 20,\n\t\t\tactionOptions: ['create', 'read', 'update', 'delete'],\n\t\t\tuserOptions: [],\n\t\t\trestoreEntry: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\thasMore() {\n\t\t\treturn this.entries.length < this.total\n\t\t},\n\n\t\t/** Whether the record's lock belongs to somebody else. */\n\t\trestoreBlocked() {\n\t\t\treturn isObjectLocked(this.objectData) && !isLockedByCurrentUser(this.objectData)\n\t\t},\n\n\t\trestoreLabel() {\n\t\t\treturn t('nextcloud-vue', 'Restore this version')\n\t\t},\n\n\t\trestoredLabel() {\n\t\t\treturn t('nextcloud-vue', 'The record was restored.')\n\t\t},\n\n\t\trestoreLockedLabel() {\n\t\t\tconst holder = lockHolder(this.objectData)\n\t\t\treturn holder\n\t\t\t\t? t('nextcloud-vue', 'This record is locked by {name}.', { name: holder })\n\t\t\t\t: t('nextcloud-vue', 'This record is locked by someone else.')\n\t\t},\n\n\t\t/** The confirm text: which entry, and that nothing is removed. */\n\t\trestoreMessage() {\n\t\t\tif (!this.restoreEntry) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', 'Restore the record to how it was after the change by {user} on {date}? This is saved as a new version and nothing is removed.', {\n\t\t\t\tuser: this.restoreEntry.userName || this.restoreEntry.user || 'System',\n\t\t\t\tdate: this.formatDate(this.restoreEntry.created),\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\tobjectId: {\n\t\t\timmediate: true,\n\t\t\thandler(id) {\n\t\t\t\tif (id) {\n\t\t\t\t\tthis.fetchAuditTrails()\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\tfilterAction() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterUser() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterDateFrom() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\n\t\tfilterDateTo() {\n\t\t\tthis.resetAndFetch()\n\t\t},\n\t},\n\n\tmethods: {\n\t\tresetAndFetch() {\n\t\t\tthis.page = 1\n\t\t\tthis.entries = []\n\t\t\tthis.fetchAuditTrails()\n\t\t},\n\n\t\tbuildQueryParams() {\n\t\t\tconst params = new URLSearchParams()\n\t\t\tparams.set('limit', this.limit)\n\t\t\tparams.set('_page', this.page)\n\t\t\tparams.set('_sort[created]', 'DESC')\n\t\t\tif (this.filterAction?.length) {\n\t\t\t\tparams.set('action', this.filterAction.join(','))\n\t\t\t}\n\t\t\tif (this.filterUser?.length) {\n\t\t\t\tparams.set('user_name', this.filterUser.join(','))\n\t\t\t}\n\t\t\tif (this.filterDateFrom) {\n\t\t\t\tparams.set('_dateFrom', new Date(this.filterDateFrom).toISOString().split('T')[0])\n\t\t\t}\n\t\t\tif (this.filterDateTo) {\n\t\t\t\tparams.set('_dateTo', new Date(this.filterDateTo).toISOString().split('T')[0])\n\t\t\t}\n\t\t\treturn params.toString()\n\t\t},\n\n\t\tasync fetchAuditTrails() {\n\t\t\tif (!this.register || !this.schema) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.loading = this.page === 1\n\t\t\tthis.loadingMore = this.page > 1\n\t\t\ttry {\n\t\t\t\tconst query = this.buildQueryParams()\n\t\t\t\t// generateUrl prepends the Nextcloud webroot + `/index.php` so the\n\t\t\t\t// request resolves on instances without URL rewriting.\n\t\t\t\tconst url = generateUrl(`${this.apiBase}/objects/${this.register}/${this.schema}/${this.objectId}/audit-trails`)\n\t\t\t\tconst response = await fetch(\n\t\t\t\t\t`${url}?${query}`,\n\t\t\t\t\t{ headers: buildHeaders() },\n\t\t\t\t)\n\t\t\t\tif (response.ok) {\n\t\t\t\t\tconst data = await response.json()\n\t\t\t\t\tconst results = data.results || data || []\n\t\t\t\t\tif (this.page === 1) {\n\t\t\t\t\t\tthis.entries = results\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.entries = [...this.entries, ...results]\n\t\t\t\t\t}\n\t\t\t\t\tthis.total = data.total || this.entries.length\n\t\t\t\t\t// Build user options from all seen entries\n\t\t\t\t\tconst users = new Set(this.entries.map((e) => e.userName || e.user).filter(Boolean))\n\t\t\t\t\tthis.userOptions = [...users].sort()\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.error('CnAuditTrailTab: Failed to fetch audit trails', err)\n\t\t\t} finally {\n\t\t\t\tthis.loading = false\n\t\t\t\tthis.loadingMore = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Whether an entry shows the restore button.\n\t\t *\n\t\t * @param {object} entry The audit-trail entry.\n\t\t * @return {boolean} True for a create or update entry when restore is allowed and the reader may update.\n\t\t */\n\t\tcanRestore(entry) {\n\t\t\tif (!this.allowRestore || !['create', 'update'].includes(entry.action)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tconst actions = this.objectData?.['@self']?.actions\n\t\t\treturn !Array.isArray(actions) || actions.includes('update')\n\t\t},\n\n\t\t/**\n\t\t * Open the confirm dialog for an entry.\n\t\t *\n\t\t * @param {object} entry The audit-trail entry to restore to.\n\t\t */\n\t\taskRestore(entry) {\n\t\t\tif (!this.restoreBlocked) {\n\t\t\t\tthis.restoreEntry = entry\n\t\t\t}\n\t\t},\n\n\t\t/** Call the revert route for the chosen entry and report back to the dialog. */\n\t\tasync confirmRestore() {\n\t\t\tconst entry = this.restoreEntry\n\t\t\tconst { restore } = useRestoreVersion({ apiBase: this.apiBase })\n\t\t\tconst result = await restore({\n\t\t\t\tregister: this.register,\n\t\t\t\tschema: this.schema,\n\t\t\t\tobjectId: this.objectId,\n\t\t\t\tauditTrailId: entry.id,\n\t\t\t\tobject: this.objectData,\n\t\t\t})\n\t\t\tif (result.ok) {\n\t\t\t\tthis.page = 1\n\t\t\t\tthis.entries = []\n\t\t\t\tawait this.fetchAuditTrails()\n\t\t\t\t/**\n\t\t\t\t * @event restored Emitted with the restored record after a successful restore.\n\t\t\t\t * @type {object|null}\n\t\t\t\t */\n\t\t\t\tthis.$emit('restored', result.record)\n\t\t\t\temit('cn:page:refresh')\n\t\t\t} else if (result.status === 423) {\n\t\t\t\t// Re-read the record so the page shows the lock.\n\t\t\t\temit('cn:page:refresh')\n\t\t\t}\n\t\t\tthis.$refs.restoreDialog?.setResult(result.ok ? { success: true } : { error: result.message })\n\t\t},\n\n\t\tloadMore() {\n\t\t\tthis.page++\n\t\t\tthis.fetchAuditTrails()\n\t\t},\n\n\t\ttoggleExpand(id) {\n\t\t\tthis.expandedId = this.expandedId === id ? null : id\n\t\t},\n\n\t\tchangedCount(entry) {\n\t\t\tif (!entry.changed || typeof entry.changed !== 'object') {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Object.keys(entry.changed).length\n\t\t},\n\n\t\tisSimpleValue(change) {\n\t\t\treturn change && typeof change === 'object' && ('old' in change || 'new' in change)\n\t\t},\n\n\t\tformatValue(val) {\n\t\t\tif (val === null || val === undefined) {\n\t\t\t\treturn 'null'\n\t\t\t}\n\t\t\tif (typeof val === 'object') {\n\t\t\t\treturn JSON.stringify(val)\n\t\t\t}\n\t\t\treturn String(val)\n\t\t},\n\n\t\tformatDate(dateStr) {\n\t\t\tif (!dateStr) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn new Date(dateStr).toLocaleString(userLocale(), {\n\t\t\t\t\tyear: 'numeric',\n\t\t\t\t\tmonth: 'short',\n\t\t\t\t\tday: 'numeric',\n\t\t\t\t\thour: '2-digit',\n\t\t\t\t\tminute: '2-digit',\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\treturn dateStr\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-sidebar-tab { padding: 12px; }\n\n.cn-sidebar-tab__empty {\n\ttext-align: center;\n\tpadding: 24px 12px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-sidebar-tab__list { display: flex; flex-direction: column; gap: 2px; }\n\n.cn-audit-filters {\n\tdisplay: grid;\n\tgrid-template-columns: 1fr 1fr;\n\tgap: 8px;\n\tmargin-bottom: 12px;\n}\n\n.cn-audit-filters__select { min-width: 0; }\n\n.cn-audit-filters__date { min-width: 0; }\n\n.cn-sidebar-tab__load-more { margin-top: 8px; }\n\n.cn-audit-entry { cursor: pointer; }\n\n.cn-audit-details {\n\tpadding: 8px 12px 12px 52px;\n\tfont-size: 12px;\n\tborder-bottom: 1px solid var(--color-border);\n\tanimation: cn-slide-down 0.15s ease;\n}\n\n@keyframes cn-slide-down {\n\tfrom { opacity: 0; max-height: 0; }\n\tto { opacity: 1; max-height: 600px; }\n}\n\n.cn-audit-details__restore { margin: 8px 0; }\n\n.cn-audit-details__row {\n\tdisplay: flex;\n\tgap: 8px;\n\tpadding: 2px 0;\n}\n\n.cn-audit-details__label {\n\tcolor: var(--color-text-maxcontrast);\n\tmin-width: 56px;\n\tfont-weight: 500;\n}\n\n.cn-audit-details__mono {\n\tfont-family: monospace;\n\tfont-size: 11px;\n\tword-break: break-all;\n}\n\n.cn-audit-details__changes {\n\tmargin-top: 8px;\n\tpadding-top: 8px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-audit-details__change {\n\tpadding: 4px 0 4px 8px;\n\tborder-left: 2px solid var(--color-border);\n\tmargin: 4px 0;\n}\n\n.cn-audit-details__field {\n\tfont-weight: 500;\n\tdisplay: block;\n\tmargin-bottom: 2px;\n}\n\n.cn-audit-details__values {\n\tdisplay: flex;\n\tgap: 6px;\n\talign-items: baseline;\n\tflex-wrap: wrap;\n}\n\n.cn-audit-details__old {\n\tcolor: var(--color-error, #e53935);\n\ttext-decoration: line-through;\n}\n\n.cn-audit-details__arrow {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-audit-details__new {\n\tcolor: var(--color-success, #43a047);\n}\n\n.cn-audit-details__null {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-style: italic;\n}\n</style>\n"],"names":["CnConfirmDialog","t"],"mappings":"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"}
|