@conduction/nextcloud-vue 2.56.0-beta.36 → 2.56.0-beta.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +131 -3
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +54 -18
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- 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 +376 -6
- package/dist/esm/components/CnBoardView/CnBoardView.vue2.js.map +1 -1
- package/dist/esm/components/CnBoardView/CnBoardView.vue3.js +146 -71
- 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 +47 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +22 -12
- 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/CnDetailPage/CnDetailPage.vue2.js +23 -4
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +3 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.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/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +18 -5
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.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 +571 -77
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +191 -82
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +11 -2
- package/dist/esm/components/CnIndexPage/useSelfFetchList.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/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +70 -2
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +67 -5
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js +181 -124
- package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.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/CnSettingsPage/CnSettingsPage.vue.js +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js +5 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsPage/CnSettingsPage.vue3.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue.js +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +134 -10
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -2
- package/dist/esm/components/CnStatWidget/CnStatWidget.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 +6 -3
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- 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/CnToggleTableWidget/CnToggleTableWidget.vue.js +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js +140 -7
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnToggleTableWidget/CnToggleTableWidget.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/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +37 -9
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +6 -5
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js +53 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js +3 -2
- package/dist/esm/components/CnWidgetCardGrid/CnWidgetCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +135 -0
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue.js +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +19 -0
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +37 -19
- package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
- package/dist/esm/composables/useListView.js +21 -0
- package/dist/esm/composables/useListView.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 +57 -2
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +78 -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 +1541 -1166
- package/dist/esm/store/useObjectStore.js +23 -4
- package/dist/esm/store/useObjectStore.js.map +1 -1
- package/dist/esm/utils/boardColumns.js +58 -2
- package/dist/esm/utils/boardColumns.js.map +1 -1
- package/dist/esm/utils/boardReferenceColumns.js +330 -0
- package/dist/esm/utils/boardReferenceColumns.js.map +1 -0
- package/dist/esm/utils/buildManifest.js +4 -1
- package/dist/esm/utils/buildManifest.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 +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/widgetDispatch.js +8 -2
- package/dist/esm/utils/widgetDispatch.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +30291 -27618
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1541 -1166
- package/l10n/en.json +57 -2
- package/l10n/nl.json +78 -2
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +160 -8
- 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 +433 -12
- 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 +59 -3
- package/src/components/CnDataMatrix/CnDataMatrix.vue +2 -1
- package/src/components/CnDetailPage/CnDetailHeaderChips.vue +2 -1
- package/src/components/CnDetailPage/CnDetailPage.md +1 -1
- package/src/components/CnDetailPage/CnDetailPage.vue +23 -4
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +3 -1
- package/src/components/CnEmailPicker/CnEmailPicker.vue +2 -1
- package/src/components/CnFactsWidget/CnFactsWidget.vue +18 -5
- 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 +610 -25
- package/src/components/CnIndexPage/useSelfFetchList.js +10 -1
- 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/CnRecordListWidget/CnRecordListWidget.vue +70 -2
- package/src/components/CnRegisterMapping/CnRegisterMapping.md +5 -0
- package/src/components/CnRegisterMapping/CnRegisterMapping.vue +231 -96
- package/src/components/CnRoadmapItem/CnRoadmapItem.vue +2 -1
- package/src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue +4 -2
- package/src/components/CnSettingsPage/CnSettingsPage.vue +5 -1
- package/src/components/CnStatWidget/CnStatWidget.vue +136 -11
- package/src/components/CnStatsBlock/CnStatsBlock.vue +2 -1
- package/src/components/CnSummaryAggregates/CnSummaryAggregates.vue +2 -1
- package/src/components/CnTabsWidget/CnTabsWidget.vue +6 -3
- package/src/components/CnTasksCard/CnTasksCard.vue +2 -1
- package/src/components/CnTimelineWidget/CnTimelineWidget.vue +2 -1
- package/src/components/CnToggleTableWidget/CnToggleTableWidget.vue +140 -7
- package/src/components/CnTranslatedBadge/CnTranslatedBadge.vue +2 -1
- package/src/components/CnVersionHistory/CnVersionHistory.vue +2 -1
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.md +2 -1
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +42 -13
- package/src/components/CnWidgetCardGrid/CnWidgetCardGrid.vue +55 -2
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +135 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +10 -0
- package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +44 -1
- package/src/composables/useListView.js +21 -0
- package/src/css/board.css +105 -4
- package/src/css/dialog.css +4 -2
- package/src/css/index-page.css +49 -0
- package/src/css/look-board.css +77 -7
- 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 +116 -5
- package/src/store/useObjectStore.js +23 -4
- package/src/utils/boardColumns.js +57 -1
- package/src/utils/boardReferenceColumns.js +326 -0
- package/src/utils/buildManifest.js +4 -1
- package/src/utils/schema.js +5 -4
- package/src/utils/userLocale.js +26 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/widgetDispatch.js +8 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnSchemaFormDialog.vue3.js","sources":["../../../../src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue?vue&type=template&id=0f2ea630&lang.js"],"sourcesContent":["<template>\n\t<CnTabbedFormDialog\n\t\tref=\"dialog\"\n\t\t:look=\"look\"\n\t\t:width=\"width\"\n\t\t:eyebrow=\"eyebrow\"\n\t\t:subtitle=\"subtitle\"\n\t\t:tabs=\"dialogTabs\"\n\t\t:item=\"item\"\n\t\t:dialogTitle=\"dialogTitle\"\n\t\tentityName=\"Schema\"\n\t\t:size=\"size\"\n\t\t:disableSave=\"!!saveDisabledReason\"\n\t\t:disableSaveTooltip=\"saveDisabledReason\"\n\t\t:successText=\"resolvedSuccessText\"\n\t\t:cancelLabel=\"cancelLabel\"\n\t\t:closeLabel=\"closeLabel\"\n\t\t:confirmLabel=\"confirmLabel\"\n\t\t@confirm=\"handleConfirm\"\n\t\t@close=\"$emit('close')\">\n\t\t<!-- Metadata Display -->\n\t\t<template #above-tabs=\"{ loading: dialogLoading }\">\n\t\t\t<div class=\"cn-schema-form__detail-grid\">\n\t\t\t\t<div v-if=\"schemaItem.id\"\n\t\t\t\t\tclass=\"cn-schema-form__detail-item cn-schema-form__id-card\">\n\t\t\t\t\t<div class=\"cn-schema-form__id-card-header\">\n\t\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'ID / UUID:') }}</span>\n\t\t\t\t\t\t<NcButton class=\"cn-schema-form__copy-button\"\n\t\t\t\t\t\t\t@click=\"copyToClipboard(schemaItem.uuid || schemaItem.id)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Check v-if=\"isCopied\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<ContentCopy v-else :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ isCopied ? t('nextcloud-vue', 'Copied') : t('nextcloud-vue', 'Copy') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ schemaItem.id }}</span>\n\t\t\t\t\t<span v-if=\"schemaItem.uuid && schemaItem.uuid !== schemaItem.id\"\n\t\t\t\t\t\tclass=\"cn-schema-form__detail-value cn-schema-form__uuid-value\">{{ schemaItem.uuid }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-schema-form__detail-item cn-schema-form__title-with-badge\">\n\t\t\t\t\t<NcTextField v-model=\"schemaItem.title\"\n\t\t\t\t\t\t:disabled=\"dialogLoading\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'Title *')\" />\n\t\t\t\t\t<span v-if=\"schemaItem.allOf && schemaItem.allOf.length > 0\"\n\t\t\t\t\t\tclass=\"cn-schema-form__statusPill cn-schema-form__statusPill--success\">\n\t\t\t\t\t\tallOf\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"schemaItem.oneOf && schemaItem.oneOf.length > 0\"\n\t\t\t\t\t\tclass=\"cn-schema-form__statusPill cn-schema-form__statusPill--info\">\n\t\t\t\t\t\toneOf\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"schemaItem.anyOf && schemaItem.anyOf.length > 0\"\n\t\t\t\t\t\tclass=\"cn-schema-form__statusPill cn-schema-form__statusPill--info\">\n\t\t\t\t\t\tanyOf\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"schemaItem.created\" class=\"cn-schema-form__detail-item\">\n\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'Created:') }}</span>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ new Date(schemaItem.created).toLocaleString() }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"schemaItem.updated\" class=\"cn-schema-form__detail-item\">\n\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'Updated:') }}</span>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ new Date(schemaItem.updated).toLocaleString() }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-schema-form__detail-item\">\n\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'Version:') }}</span>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ schemaItem.version || t('nextcloud-vue', 'Not set') }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-schema-form__detail-item\">\n\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'Owner:') }}</span>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ schemaItem.owner || t('nextcloud-vue', 'Not set') }}</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- Properties Tab -->\n\t\t<template #tab-properties=\"{ loading: dialogLoading }\">\n\t\t\t<CnSchemaPropertiesTab\n\t\t\t\t:schemaItem=\"schemaItem\"\n\t\t\t\t:loading=\"dialogLoading\"\n\t\t\t\t:selectedProperty=\"selectedProperty\"\n\t\t\t\t:propertiesModified=\"propertiesModified\"\n\t\t\t\t:originalProperties=\"originalProperties\"\n\t\t\t\t:inheritedProperties=\"inheritedProperties\"\n\t\t\t\t:typeOptionsForSelect=\"typeOptionsForSelect\"\n\t\t\t\t:availableSchemas=\"availableSchemas\"\n\t\t\t\t:availableRegisters=\"availableRegisters\"\n\t\t\t\t:availableTagsOptions=\"availableTagsOptions\"\n\t\t\t\t:userGroups=\"userGroups\"\n\t\t\t\t:sortedUserGroups=\"sortedUserGroups\"\n\t\t\t\t:loadingGroups=\"loadingGroups\"\n\t\t\t\t@addProperty=\"addProperty\"\n\t\t\t\t@update:selectedProperty=\"selectedProperty = $event\"\n\t\t\t\t@update:propertyKey=\"updatePropertyKey($event.oldKey, $event.newKey)\"\n\t\t\t\t@copyProperty=\"copyProperty\"\n\t\t\t\t@deleteProperty=\"deleteProperty\" />\n\t\t</template>\n\n\t\t<!-- Configuration Tab -->\n\t\t<template #tab-configuration=\"{ loading: dialogLoading }\">\n\t\t\t<CnSchemaConfigurationTab\n\t\t\t\t:schemaItem=\"schemaItem\"\n\t\t\t\t:loading=\"dialogLoading\"\n\t\t\t\t:availableSchemas=\"availableSchemas\"\n\t\t\t\t:propertyOptions=\"propertyOptions\"\n\t\t\t\t:allOfSchemaNames=\"allOfSchemaNames\" />\n\t\t</template>\n\n\t\t<!-- Security Tab -->\n\t\t<template #tab-security>\n\t\t\t<CnSchemaSecurityTab\n\t\t\t\t:schemaItem=\"schemaItem\"\n\t\t\t\t:userGroups=\"userGroups\"\n\t\t\t\t:sortedUserGroups=\"sortedUserGroups\"\n\t\t\t\t:loadingGroups=\"loadingGroups\"\n\t\t\t\t:hasAnyPermissions=\"hasAnyPermissions\"\n\t\t\t\t:isRestrictiveSchema=\"isRestrictiveSchema\"\n\t\t\t\t:inheritedProperties=\"inheritedProperties\" />\n\t\t</template>\n\n\t\t<!-- Optional Action Buttons (edit mode only) -->\n\t\t<template #actions-right=\"{ loading: dialogLoading, isCreateMode, result: dialogResult }\">\n\t\t\t<template v-if=\"!isCreateMode && dialogResult === null\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showExtendSchema\"\n\t\t\t\t\t:disabled=\"dialogLoading\"\n\t\t\t\t\t@click=\"$emit('extend-schema')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<CallSplit :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ extendSchemaLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showAnalyzeProperties\"\n\t\t\t\t\t:disabled=\"dialogLoading\"\n\t\t\t\t\t@click=\"$emit('analyze-properties')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<DatabaseSearch :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ analyzePropertiesLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showValidateObjects\"\n\t\t\t\t\t:disabled=\"dialogLoading\"\n\t\t\t\t\t@click=\"$emit('validate-objects')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<CheckCircle :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ validateObjectsLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showDeleteObjects\"\n\t\t\t\t\t:title=\"objectCount > 0 ? deleteObjectsTooltip : noDeleteObjectsTooltip\"\n\t\t\t\t\t:disabled=\"dialogLoading || objectCount === 0\"\n\t\t\t\t\t@click=\"$emit('delete-objects')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<DeleteSweep :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ deleteObjectsLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showPublishObjects\"\n\t\t\t\t\t:title=\"objectCount > 0 ? publishObjectsTooltip : noPublishObjectsTooltip\"\n\t\t\t\t\t:disabled=\"dialogLoading || objectCount === 0\"\n\t\t\t\t\t@click=\"$emit('publish-objects')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Upload :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ publishObjectsLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showDelete\"\n\t\t\t\t\t:title=\"objectCount > 0 ? cannotDeleteTooltip : ''\"\n\t\t\t\t\t:disabled=\"dialogLoading || objectCount > 0\"\n\t\t\t\t\tvariant=\"error\"\n\t\t\t\t\t@click=\"$emit('delete-schema')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<TrashCanOutline :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ deleteLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</template>\n\t</CnTabbedFormDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport {\n\tNcButton,\n\tNcTextField,\n} from '@nextcloud/vue'\nimport CallSplit from 'vue-material-design-icons/CallSplit.vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport CheckCircle from 'vue-material-design-icons/CheckCircle.vue'\nimport ContentCopy from 'vue-material-design-icons/ContentCopy.vue'\nimport DatabaseSearch from 'vue-material-design-icons/DatabaseSearch.vue'\nimport DeleteSweep from 'vue-material-design-icons/DeleteSweep.vue'\nimport TrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'\nimport Upload from 'vue-material-design-icons/Upload.vue'\nimport CnTabbedFormDialog from '../CnTabbedFormDialog/CnTabbedFormDialog.vue'\nimport CnSchemaConfigurationTab from './CnSchemaConfigurationTab.vue'\nimport CnSchemaPropertiesTab from './CnSchemaPropertiesTab.vue'\nimport CnSchemaSecurityTab from './CnSchemaSecurityTab.vue'\nimport { dialogBoardMixin } from '../../mixins/dialogBoard.js'\n\n/**\n * CnSchemaFormDialog — Generic JSON Schema editor dialog.\n *\n * Provides a full-featured form for creating and editing JSON Schemas with\n * properties table, configuration, and security (RBAC) tabs. Uses CnTabbedFormDialog.\n *\n * The dialog does NOT perform saves — it emits a `confirm` event with the schema data.\n * The parent performs the actual API call and calls `setResult()` via a ref.\n *\n * @event confirm Emitted when the user confirms. Payload: cleaned schema data object.\n * @event close Emitted when the dialog should be closed.\n * @event extend-schema Emitted when the Extend Schema button is clicked.\n * @event analyze-properties Emitted when the Analyze Properties button is clicked.\n * @event validate-objects Emitted when the Validate Objects button is clicked.\n * @event delete-objects Emitted when the Delete Objects button is clicked.\n * @event publish-objects Emitted when the Publish Objects button is clicked.\n * @event delete-schema Emitted when the Delete button is clicked.\n */\nexport default {\n\tname: 'CnSchemaFormDialog',\n\tcomponents: {\n\t\tNcTextField,\n\t\tNcButton,\n\t\tCnTabbedFormDialog,\n\t\tCnSchemaPropertiesTab,\n\t\tCnSchemaConfigurationTab,\n\t\tCnSchemaSecurityTab,\n\t\t// Icons\n\t\tContentCopy,\n\t\tCheck,\n\t\tTrashCanOutline,\n\t\tCallSplit,\n\t\tDatabaseSearch,\n\t\tCheckCircle,\n\t\tDeleteSweep,\n\t\tUpload,\n\t},\n\n\tmixins: [dialogBoardMixin],\n\n\tprops: {\n\t\t/** Existing schema item for edit mode. Pass null for create mode. */\n\t\titem: { type: Object, default: null },\n\t\t/** Dialog title. Defaults to \"Create Schema\" or \"Edit Schema\". */\n\t\tdialogTitle: { type: String, default: '' },\n\t\t/** NcDialog size */\n\t\tsize: { type: String, default: 'large' },\n\t\t/** Available schemas for references and composition. Array of { id, title, description, reference } */\n\t\tavailableSchemas: { type: Array, default: () => [] },\n\t\t/** Available registers. Array of { id, label } */\n\t\tavailableRegisters: { type: Array, default: () => [] },\n\t\t/** User groups for RBAC. Array of { id, displayname } */\n\t\tuserGroups: { type: Array, default: () => [] },\n\t\t/** Available tags for file property configuration */\n\t\tavailableTags: { type: Array, default: () => [] },\n\t\t/** Whether user groups are still loading */\n\t\tloadingGroups: { type: Boolean, default: false },\n\t\t/** Properties inherited from parent schemas (allOf) — shown as locked rows in the properties tab */\n\t\tinheritedProperties: { type: Object, default: () => ({}) },\n\t\t/** Number of objects attached to this schema (used for action button disable logic) */\n\t\tobjectCount: { type: Number, default: 0 },\n\t\t// Optional action button visibility\n\t\t/** Show \"Extend Schema\" button */\n\t\tshowExtendSchema: { type: Boolean, default: false },\n\t\t/** Show \"Analyze Properties\" button */\n\t\tshowAnalyzeProperties: { type: Boolean, default: false },\n\t\t/** Show \"Validate Objects\" button */\n\t\tshowValidateObjects: { type: Boolean, default: false },\n\t\t/** Show \"Delete Objects\" button */\n\t\tshowDeleteObjects: { type: Boolean, default: false },\n\t\t/** Show \"Publish Objects\" button */\n\t\tshowPublishObjects: { type: Boolean, default: false },\n\t\t/** Show \"Delete\" button */\n\t\tshowDelete: { type: Boolean, default: false },\n\t\t// Labels (pre-translated strings with English defaults)\n\t\t/** Label for the cancel button shown while editing. */\n\t\tcancelLabel: { type: String, default: () => t('nextcloud-vue', 'Cancel') },\n\t\t/** Label for the close button shown after a save or error. */\n\t\tcloseLabel: { type: String, default: () => t('nextcloud-vue', 'Close') },\n\t\t/** Confirm button label. Defaults to \"Create\" or \"Save\". */\n\t\tconfirmLabel: { type: String, default: '' },\n\t\t/** Success message. Defaults to \"Schema saved successfully.\" */\n\t\tsuccessText: { type: String, default: '' },\n\t\t/** Label for the Extend Schema action button. */\n\t\textendSchemaLabel: { type: String, default: () => t('nextcloud-vue', 'Extend schema') },\n\t\t/** Label for the Analyze Properties action button. */\n\t\tanalyzePropertiesLabel: { type: String, default: () => t('nextcloud-vue', 'Analyze properties') },\n\t\t/** Label for the Validate Objects action button. */\n\t\tvalidateObjectsLabel: { type: String, default: () => t('nextcloud-vue', 'Validate objects') },\n\t\t/** Label for the Delete Objects action button. */\n\t\tdeleteObjectsLabel: { type: String, default: () => t('nextcloud-vue', 'Delete objects') },\n\t\t/** Label for the Publish Objects action button. */\n\t\tpublishObjectsLabel: { type: String, default: () => t('nextcloud-vue', 'Publish objects') },\n\t\t/** Label for the Delete schema button shown in edit mode. */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete') },\n\t\t/** Tooltip for the Delete Objects button when objects exist. */\n\t\tdeleteObjectsTooltip: { type: String, default: () => t('nextcloud-vue', 'Delete all objects in this schema') },\n\t\t/** Tooltip for the Publish Objects button when objects exist. */\n\t\tpublishObjectsTooltip: { type: String, default: () => t('nextcloud-vue', 'Publish all objects in this schema') },\n\t\t/** Tooltip for the Delete Objects button when no objects exist */\n\t\tnoDeleteObjectsTooltip: { type: String, default: () => t('nextcloud-vue', 'No objects to delete') },\n\t\t/** Tooltip for the Publish Objects button when no objects exist */\n\t\tnoPublishObjectsTooltip: { type: String, default: () => t('nextcloud-vue', 'No objects to publish') },\n\t\t/** Tooltip for the Delete schema button while objects are still attached. */\n\t\tcannotDeleteTooltip: { type: String, default: () => t('nextcloud-vue', 'Cannot delete: objects are still attached') },\n\t},\n\n\temits: [\n\t\t'analyze-properties',\n\t\t'close',\n\t\t'confirm',\n\t\t'delete-objects',\n\t\t'delete-schema',\n\t\t'extend-schema',\n\t\t'publish-objects',\n\t\t'validate-objects',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tisCopied: false,\n\t\t\tselectedProperty: null,\n\t\t\tpropertiesModified: false,\n\t\t\toriginalProperties: null,\n\t\t\tschemaItem: {\n\t\t\t\ttitle: '',\n\t\t\t\tversion: '0.0.0',\n\t\t\t\tdescription: '',\n\t\t\t\tsummary: '',\n\t\t\t\tslug: '',\n\t\t\t\tproperties: {},\n\t\t\t\tconfiguration: {\n\t\t\t\t\tobjectNameField: '',\n\t\t\t\t\tobjectDescriptionField: '',\n\t\t\t\t\tobjectImageField: '',\n\t\t\t\t\tobjectSummaryField: '',\n\t\t\t\t\tallowFiles: false,\n\t\t\t\t\tallowedTags: [],\n\t\t\t\t\tautoPublish: false,\n\t\t\t\t\tdefaultAutoShare: false,\n\t\t\t\t},\n\n\t\t\t\tauthorization: {},\n\t\t\t\thardValidation: false,\n\t\t\t\timmutable: false,\n\t\t\t\tsearchable: true,\n\t\t\t\ticon: null,\n\t\t\t\tmaxDepth: 0,\n\t\t\t},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Tab definitions for CnTabbedFormDialog.\n\t\t *\n\t\t * @return {Array} Tab configuration\n\t\t */\n\t\tdialogTabs() {\n\t\t\treturn [\n\t\t\t\t{ id: 'properties', title: t('nextcloud-vue', 'Properties') },\n\t\t\t\t{ id: 'configuration', title: t('nextcloud-vue', 'Configuration') },\n\t\t\t\t{ id: 'security', title: t('nextcloud-vue', 'Security') },\n\t\t\t]\n\t\t},\n\n\t\tsortedUserGroups() {\n\t\t\treturn this.userGroups\n\t\t\t\t.filter((group) => group.id !== 'admin' && group.id !== 'public' && group.id !== 'authenticated')\n\t\t\t\t.sort((a, b) => {\n\t\t\t\t\tconst nameA = a.displayname || a.id\n\t\t\t\t\tconst nameB = b.displayname || b.id\n\t\t\t\t\treturn nameA.localeCompare(nameB)\n\t\t\t\t})\n\t\t},\n\n\t\thasAnyPermissions() {\n\t\t\tconst auth = this.schemaItem.authorization || {}\n\t\t\treturn Object.keys(auth).some((action) => Array.isArray(auth[action]) && auth[action].length > 0)\n\t\t},\n\n\t\tisRestrictiveSchema() {\n\t\t\tconst auth = this.schemaItem.authorization || {}\n\t\t\tconst actions = ['create', 'read', 'update', 'delete']\n\t\t\treturn actions.some((action) => Array.isArray(auth[action]) && auth[action].length > 0\n\t\t\t\t&& !auth[action].includes('public'))\n\t\t},\n\n\t\ttypeOptionsForSelect() {\n\t\t\treturn [\n\t\t\t\t{ id: 'string', label: t('nextcloud-vue', 'String') },\n\t\t\t\t{ id: 'number', label: t('nextcloud-vue', 'Number') },\n\t\t\t\t{ id: 'integer', label: t('nextcloud-vue', 'Integer') },\n\t\t\t\t{ id: 'boolean', label: t('nextcloud-vue', 'Boolean') },\n\t\t\t\t{ id: 'array', label: t('nextcloud-vue', 'Array') },\n\t\t\t\t{ id: 'object', label: t('nextcloud-vue', 'Object') },\n\t\t\t\t{ id: 'dictionary', label: t('nextcloud-vue', 'Dictionary') },\n\t\t\t\t{ id: 'file', label: t('nextcloud-vue', 'File') },\n\t\t\t\t{ id: 'oneOf', label: t('nextcloud-vue', 'One of') },\n\t\t\t]\n\t\t},\n\n\t\tpropertyOptions() {\n\t\t\tconst ownKeys = Object.keys(this.schemaItem.properties || {}).filter((k) => k !== '')\n\t\t\tconst inheritedKeys = Object.keys(this.inheritedProperties || {}).filter((k) => k !== '')\n\t\t\treturn [...new Set([...inheritedKeys, ...ownKeys])]\n\t\t},\n\n\t\tavailableTagsOptions() {\n\t\t\treturn this.availableTags.map((tag) => ({\n\t\t\t\tid: tag,\n\t\t\t\tlabel: tag,\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Resolved success text for backwards compatibility (includes trailing period).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedSuccessText() {\n\t\t\tif (this.successText) {\n\t\t\t\treturn this.successText\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{title} saved successfully.', { title: t('nextcloud-vue', 'Schema') })\n\t\t},\n\n\t\t/**\n\t\t * Returns a human-readable reason the save button is disabled, or '' when saving is allowed.\n\t\t * Used for both :disable-save and the WCAG tooltip/aria-label on the button.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsaveDisabledReason() {\n\t\t\tif (!this.schemaItem.title) {\n\t\t\t\treturn t('nextcloud-vue', 'A schema title is required before saving')\n\t\t\t}\n\t\t\tconst hasUnnamedProperty = Object.keys(this.schemaItem.properties || {}).some((key) => key === '')\n\t\t\tif (hasUnnamedProperty) {\n\t\t\t\treturn t('nextcloud-vue', 'All properties must have a name before saving')\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\tallOfSchemaNames() {\n\t\t\tif (!this.schemaItem.allOf || !Array.isArray(this.schemaItem.allOf) || this.schemaItem.allOf.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\treturn this.schemaItem.allOf\n\t\t\t\t.map((ref) => {\n\t\t\t\t\tconst schemaId = typeof ref === 'object' ? ref.id : ref\n\t\t\t\t\tconst schema = this.availableSchemas.find((s) => s.id === schemaId)\n\t\t\t\t\treturn schema ? (schema.title || `Schema ${schema.id}`) : schemaId\n\t\t\t\t})\n\t\t\t\t.filter((name) => name)\n\t\t},\n\t},\n\n\twatch: {\n\t\titem: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.initializeSchemaItem()\n\t\t\t},\n\t\t},\n\n\t\t'schemaItem.properties': {\n\t\t\thandler(newProperties) {\n\t\t\t\tif (newProperties) {\n\t\t\t\t\tObject.keys(newProperties).forEach((key) => {\n\t\t\t\t\t\tconst property = newProperties[key]\n\t\t\t\t\t\tif (property) {\n\t\t\t\t\t\t\t// Initialize nested objects if they don't exist\n\t\t\t\t\t\t\tif (property.type === 'array' && !property.items) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items = { type: 'string' }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (property.type === 'object' && !property.objectConfiguration) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration = { handling: 'nested-object' }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (property.type === 'array' && property.items && property.items.type === 'object' && !property.items.objectConfiguration) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration = { handling: 'nested-object' }\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert property type from object to string\n\t\t\t\t\t\t\tif (property.type && typeof property.type === 'object' && property.type.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].type = property.type.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert property format from object to string\n\t\t\t\t\t\t\tif (property.format && typeof property.format === 'object' && property.format.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].format = property.format.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert array item type from object to string\n\t\t\t\t\t\t\tif (property.items && property.items.type && typeof property.items.type === 'object' && property.items.type.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.type = property.items.type.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert object handling from object to string\n\t\t\t\t\t\t\tif (property.objectConfiguration && property.objectConfiguration.handling\n\t\t\t\t\t\t\t\t&& typeof property.objectConfiguration.handling === 'object' && property.objectConfiguration.handling.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration.handling = property.objectConfiguration.handling.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert register from object to ID\n\t\t\t\t\t\t\tif (property.objectConfiguration && property.objectConfiguration.register\n\t\t\t\t\t\t\t\t&& typeof property.objectConfiguration.register === 'object' && property.objectConfiguration.register.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration.register = property.objectConfiguration.register.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert array item object handling from object to string\n\t\t\t\t\t\t\tif (property.items && property.items.objectConfiguration && property.items.objectConfiguration.handling\n\t\t\t\t\t\t\t\t&& typeof property.items.objectConfiguration.handling === 'object' && property.items.objectConfiguration.handling.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration.handling = property.items.objectConfiguration.handling.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert array item register from object to ID\n\t\t\t\t\t\t\tif (property.items && property.items.objectConfiguration && property.items.objectConfiguration.register\n\t\t\t\t\t\t\t\t&& typeof property.items.objectConfiguration.register === 'object' && property.items.objectConfiguration.register.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration.register = property.items.objectConfiguration.register.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Ensure $ref is always a string\n\t\t\t\t\t\t\tthis.ensureRefIsString(this.schemaItem.properties, key)\n\n\t\t\t\t\t\t\t// Ensure inversedBy is always a string for regular properties\n\t\t\t\t\t\t\tif (property.inversedBy && typeof property.inversedBy === 'object' && property.inversedBy.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].inversedBy = property.inversedBy.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Ensure inversedBy is always a string for array items\n\t\t\t\t\t\t\tif (property.items && property.items.inversedBy && typeof property.items.inversedBy === 'object' && property.items.inversedBy.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.inversedBy = property.items.inversedBy.id\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tthis.checkPropertiesModified()\n\t\t\t},\n\n\t\t\tdeep: true,\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tfindSchemaBySlug(schemaSlug) {\n\t\t\tif (!schemaSlug) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn this.availableSchemas.find((schema) => (schema.slug && schema.slug.toLowerCase() === schemaSlug.toLowerCase())\n\t\t\t\t|| schema.id === schemaSlug\n\t\t\t\t|| schema.title === schemaSlug)\n\t\t},\n\n\t\tensureRefIsString(obj, key) {\n\t\t\tif (!obj || !key) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (obj[key] && typeof obj[key].$ref === 'object' && obj[key].$ref !== null) {\n\t\t\t\tif (obj[key].$ref.id) {\n\t\t\t\t\tobj[key].$ref = obj[key].$ref.id\n\t\t\t\t} else {\n\t\t\t\t\tobj[key].$ref = ''\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (obj[key] && obj[key].items && typeof obj[key].items.$ref === 'object' && obj[key].items.$ref !== null) {\n\t\t\t\tif (obj[key].items.$ref.id) {\n\t\t\t\t\tobj[key].items.$ref = obj[key].items.$ref.id\n\t\t\t\t} else {\n\t\t\t\t\tobj[key].items.$ref = ''\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tinitializeSchemaItem() {\n\t\t\t// Reset CnTabbedFormDialog state if available (not yet mounted on first call)\n\t\t\tif (this.$refs.dialog) {\n\t\t\t\tthis.$refs.dialog.resetDialog()\n\t\t\t}\n\n\t\t\t// Always rebuild schemaItem from defaults + incoming item. This handles\n\t\t\t// create mode (item null), edit mode (item with id), and extend mode\n\t\t\t// (item non-null with no id) without leaking stale state across opens.\n\t\t\tconst defaults = {\n\t\t\t\ttitle: '',\n\t\t\t\tversion: '0.0.0',\n\t\t\t\tdescription: '',\n\t\t\t\tsummary: '',\n\t\t\t\tslug: '',\n\t\t\t\tproperties: {},\n\t\t\t\tconfiguration: {\n\t\t\t\t\tobjectNameField: '',\n\t\t\t\t\tobjectDescriptionField: '',\n\t\t\t\t\tobjectImageField: '',\n\t\t\t\t\tobjectSummaryField: '',\n\t\t\t\t\tallowFiles: false,\n\t\t\t\t\tallowedTags: [],\n\t\t\t\t\tautoPublish: false,\n\t\t\t\t\tdefaultAutoShare: false,\n\t\t\t\t},\n\n\t\t\t\tauthorization: {},\n\t\t\t\thardValidation: false,\n\t\t\t\timmutable: false,\n\t\t\t\tsearchable: true,\n\t\t\t\ticon: null,\n\t\t\t\tmaxDepth: 0,\n\t\t\t}\n\t\t\tthis.schemaItem = this.item\n\t\t\t\t? { ...defaults, ...JSON.parse(JSON.stringify(this.item)) }\n\t\t\t\t: { ...defaults }\n\n\t\t\t// Ensure configuration object has all expected keys (the spread above may\n\t\t\t// have replaced our defaults with a partial configuration from the item)\n\t\t\tif (!this.schemaItem.configuration) {\n\t\t\t\tthis.schemaItem.configuration = { ...defaults.configuration }\n\t\t\t} else {\n\t\t\t\tif (!this.schemaItem.configuration.objectNameField) {\n\t\t\t\t\tthis.schemaItem.configuration.objectNameField = ''\n\t\t\t\t}\n\t\t\t\tif (!this.schemaItem.configuration.objectDescriptionField) {\n\t\t\t\t\tthis.schemaItem.configuration.objectDescriptionField = ''\n\t\t\t\t}\n\t\t\t\tif (!this.schemaItem.configuration.objectImageField) {\n\t\t\t\t\tthis.schemaItem.configuration.objectImageField = ''\n\t\t\t\t}\n\t\t\t\tif (!this.schemaItem.configuration.objectSummaryField) {\n\t\t\t\t\tthis.schemaItem.configuration.objectSummaryField = ''\n\t\t\t\t}\n\t\t\t\tif (this.schemaItem.configuration.allowFiles === undefined) {\n\t\t\t\t\tthis.schemaItem.configuration.allowFiles = false\n\t\t\t\t}\n\t\t\t\tif (!this.schemaItem.configuration.allowedTags) {\n\t\t\t\t\tthis.schemaItem.configuration.allowedTags = []\n\t\t\t\t}\n\t\t\t\tif (this.schemaItem.configuration.autoPublish === undefined) {\n\t\t\t\t\tthis.schemaItem.configuration.autoPublish = false\n\t\t\t\t}\n\t\t\t\tif (this.schemaItem.configuration.defaultAutoShare === undefined) {\n\t\t\t\t\tthis.schemaItem.configuration.defaultAutoShare = false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Ensure authorization object exists\n\t\t\tif (!this.schemaItem.authorization) {\n\t\t\t\tthis.schemaItem.authorization = {}\n\t\t\t}\n\n\t\t\t// Ensure existing properties have facetable set to false by default\n\t\t\tObject.keys(this.schemaItem.properties || {}).forEach((key) => {\n\t\t\t\tif (this.schemaItem.properties[key].facetable === undefined) {\n\t\t\t\t\tthis.schemaItem.properties[key].facetable = false\n\t\t\t\t}\n\n\t\t\t\tif (this.schemaItem.properties[key].enum && Array.isArray(this.schemaItem.properties[key].enum)) {\n\t\t\t\t\tthis.schemaItem.properties[key].enum = [...this.schemaItem.properties[key].enum]\n\t\t\t\t}\n\n\t\t\t\tconst property = this.schemaItem.properties[key]\n\t\t\t\tif (property.type === 'array' && property.items && property.items.type === 'object' && !property.items.objectConfiguration) {\n\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration = { handling: 'nested-object' }\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Ensure all $ref values are strings and migrate old structure\n\t\t\tObject.keys(this.schemaItem.properties || {}).forEach((key) => {\n\t\t\t\tthis.ensureRefIsString(this.schemaItem.properties, key)\n\t\t\t\tthis.migratePropertyToNewStructure(key)\n\t\t\t})\n\n\t\t\t// Snapshot original properties for change detection. For new/extending\n\t\t\t// items (no id), there's no \"original\" — start empty so any added\n\t\t\t// properties register as modifications.\n\t\t\tthis.originalProperties = this.schemaItem.id\n\t\t\t\t? JSON.parse(JSON.stringify(this.schemaItem.properties || {}))\n\t\t\t\t: {}\n\n\t\t\tthis.propertiesModified = false\n\t\t},\n\n\t\tcheckPropertiesModified() {\n\t\t\tif (!this.originalProperties) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tconst currentProperties = JSON.stringify(this.schemaItem.properties || {})\n\t\t\tconst originalProperties = JSON.stringify(this.originalProperties)\n\n\t\t\tthis.propertiesModified = currentProperties !== originalProperties\n\t\t},\n\n\t\tasync copyToClipboard(text) {\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(text)\n\t\t\t\tthis.isCopied = true\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis.isCopied = false\n\t\t\t\t}, 2000)\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console -- the failure is already handled; the console is the only channel a host app can read the detail on\n\t\t\t\tconsole.error('Failed to copy text:', err)\n\t\t\t}\n\t\t},\n\n\t\taddProperty() {\n\t\t\tthis.schemaItem.properties[''] = {\n\t\t\t\ttype: 'string',\n\t\t\t\tformat: '',\n\t\t\t\ttitle: '',\n\t\t\t\tdescription: '',\n\t\t\t\tfacetable: false,\n\t\t\t}\n\n\t\t\tthis.checkPropertiesModified()\n\t\t\tthis.selectedProperty = ''\n\t\t},\n\n\t\tupdatePropertyKey(oldKey, newKey) {\n\t\t\tif (newKey === oldKey) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.schemaItem.properties[newKey] !== undefined && newKey !== oldKey) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst propertyData = { ...this.schemaItem.properties[oldKey] }\n\n\t\t\tthis.schemaItem.properties[newKey] = propertyData\n\t\t\tdelete this.schemaItem.properties[oldKey]\n\n\t\t\tthis.selectedProperty = newKey\n\t\t\tthis.checkPropertiesModified()\n\t\t},\n\n\t\tdeleteProperty(key) {\n\t\t\tdelete this.schemaItem.properties[key]\n\n\t\t\tif (this.selectedProperty === key) {\n\t\t\t\tthis.selectedProperty = null\n\t\t\t}\n\n\t\t\tthis.checkPropertiesModified()\n\t\t},\n\n\t\tcopyProperty(key) {\n\t\t\tif (this.schemaItem.properties[key]) {\n\t\t\t\tconst originalProperty = JSON.parse(JSON.stringify(this.schemaItem.properties[key]))\n\n\t\t\t\tlet newPropertyName = `${key}_copy`\n\t\t\t\tlet counter = 1\n\n\t\t\t\twhile (this.schemaItem.properties[newPropertyName]) {\n\t\t\t\t\tcounter++\n\t\t\t\t\tnewPropertyName = `${key}_copy_${counter}`\n\t\t\t\t}\n\n\t\t\t\tconst originalTitle = originalProperty.title || key\n\t\t\t\tthis.schemaItem.properties[newPropertyName] = {\n\t\t\t\t\t...originalProperty,\n\t\t\t\t\ttitle: `${originalTitle} (copy)`,\n\t\t\t\t}\n\n\t\t\t\tthis.checkPropertiesModified()\n\t\t\t\tthis.selectedProperty = newPropertyName\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle confirm from CnTabbedFormDialog.\n\t\t * Cleans schema data and emits confirm with the cleaned payload.\n\t\t */\n\t\thandleConfirm() {\n\t\t\tconst cleanedSchemaItem = JSON.parse(JSON.stringify(this.schemaItem))\n\t\t\tObject.keys(cleanedSchemaItem.properties || {}).forEach((key) => {\n\t\t\t\tthis.ensureRefIsString(cleanedSchemaItem.properties, key)\n\n\t\t\t\tif (cleanedSchemaItem.properties[key].register\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].objectConfiguration\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].objectConfiguration.register) {\n\t\t\t\t\tdelete cleanedSchemaItem.properties[key].register\n\t\t\t\t}\n\n\t\t\t\tif (cleanedSchemaItem.properties[key].items\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].items.register\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].items.objectConfiguration\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].items.objectConfiguration.register) {\n\t\t\t\t\tdelete cleanedSchemaItem.properties[key].items.register\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// NcSelect (track-by=\"id\") can convert plain IDs to full option objects.\n\t\t\t// Normalise back to plain IDs before emitting so the backend always gets scalars.\n\t\t\tfor (const field of ['allOf', 'oneOf', 'anyOf']) {\n\t\t\t\tif (Array.isArray(cleanedSchemaItem[field])) {\n\t\t\t\t\tcleanedSchemaItem[field] = cleanedSchemaItem[field]\n\t\t\t\t\t\t.map((ref) => (typeof ref === 'object' && ref !== null ? ref.id : ref))\n\t\t\t\t\t\t.filter((id) => id !== null && id !== undefined && id !== '')\n\t\t\t\t\tif (cleanedSchemaItem[field].length === 0) {\n\t\t\t\t\t\tdelete cleanedSchemaItem[field]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.$emit('confirm', cleanedSchemaItem)\n\t\t},\n\n\t\t/**\n\t\t * Set the result of the save operation. Call this from the parent\n\t\t * after the API call completes.\n\t\t *\n\t\t * @param {{ success?: boolean, error?: string }} resultData - result data\n\t\t * @public\n\t\t */\n\t\tsetResult(resultData) {\n\t\t\tthis.$refs.dialog.setResult(resultData)\n\t\t\tif (resultData.success) {\n\t\t\t\tthis.originalProperties = JSON.parse(JSON.stringify(this.schemaItem.properties || {}))\n\t\t\t\tthis.propertiesModified = false\n\t\t\t}\n\t\t},\n\n\t\tmigratePropertyToNewStructure(key) {\n\t\t\tif (!this.schemaItem.properties[key]) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst property = this.schemaItem.properties[key]\n\n\t\t\tif (property.$ref && property.register && !property.objectConfiguration?.register) {\n\t\t\t\tif (!property.objectConfiguration) {\n\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration = { handling: 'related-object' }\n\t\t\t\t}\n\n\t\t\t\tconst registerId = typeof property.register === 'object' && property.register.id\n\t\t\t\t\t? property.register.id\n\t\t\t\t\t: property.register\n\n\t\t\t\tthis.schemaItem.properties[key].objectConfiguration.register = registerId\n\n\t\t\t\tif (property.$ref) {\n\t\t\t\t\tlet schemaSlug = property.$ref\n\t\t\t\t\tif (schemaSlug.includes('/')) {\n\t\t\t\t\t\tschemaSlug = schemaSlug.substring(schemaSlug.lastIndexOf('/') + 1)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst referencedSchema = this.findSchemaBySlug(schemaSlug)\n\t\t\t\t\tif (referencedSchema) {\n\t\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration.schema = referencedSchema.id\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (property.items && property.items.$ref && property.items.register && !property.items.objectConfiguration?.register) {\n\t\t\t\tif (!property.items.objectConfiguration) {\n\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration = { handling: 'related-object' }\n\t\t\t\t}\n\n\t\t\t\tconst registerId = typeof property.items.register === 'object' && property.items.register.id\n\t\t\t\t\t? property.items.register.id\n\t\t\t\t\t: property.items.register\n\n\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration.register = registerId\n\n\t\t\t\tif (property.items.$ref) {\n\t\t\t\t\tlet schemaSlug = property.items.$ref\n\t\t\t\t\tif (schemaSlug.includes('/')) {\n\t\t\t\t\t\tschemaSlug = schemaSlug.substring(schemaSlug.lastIndexOf('/') + 1)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst referencedSchema = this.findSchemaBySlug(schemaSlug)\n\t\t\t\t\tif (referencedSchema) {\n\t\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration.schema = referencedSchema.id\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n"],"names":["_createBlock","_withCtx","_createElementVNode","_openBlock","_createElementBlock","_toDisplayString","_createVNode","_createTextVNode","_Fragment"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnSchemaFormDialog.vue3.js","sources":["../../../../src/components/CnSchemaFormDialog/CnSchemaFormDialog.vue?vue&type=template&id=3cba1325&lang.js"],"sourcesContent":["<template>\n\t<CnTabbedFormDialog\n\t\tref=\"dialog\"\n\t\t:look=\"look\"\n\t\t:width=\"width\"\n\t\t:eyebrow=\"eyebrow\"\n\t\t:subtitle=\"subtitle\"\n\t\t:tabs=\"dialogTabs\"\n\t\t:item=\"item\"\n\t\t:dialogTitle=\"dialogTitle\"\n\t\tentityName=\"Schema\"\n\t\t:size=\"size\"\n\t\t:disableSave=\"!!saveDisabledReason\"\n\t\t:disableSaveTooltip=\"saveDisabledReason\"\n\t\t:successText=\"resolvedSuccessText\"\n\t\t:cancelLabel=\"cancelLabel\"\n\t\t:closeLabel=\"closeLabel\"\n\t\t:confirmLabel=\"confirmLabel\"\n\t\t@confirm=\"handleConfirm\"\n\t\t@close=\"$emit('close')\">\n\t\t<!-- Metadata Display -->\n\t\t<template #above-tabs=\"{ loading: dialogLoading }\">\n\t\t\t<div class=\"cn-schema-form__detail-grid\">\n\t\t\t\t<div v-if=\"schemaItem.id\"\n\t\t\t\t\tclass=\"cn-schema-form__detail-item cn-schema-form__id-card\">\n\t\t\t\t\t<div class=\"cn-schema-form__id-card-header\">\n\t\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'ID / UUID:') }}</span>\n\t\t\t\t\t\t<NcButton class=\"cn-schema-form__copy-button\"\n\t\t\t\t\t\t\t@click=\"copyToClipboard(schemaItem.uuid || schemaItem.id)\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<Check v-if=\"isCopied\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<ContentCopy v-else :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ isCopied ? t('nextcloud-vue', 'Copied') : t('nextcloud-vue', 'Copy') }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ schemaItem.id }}</span>\n\t\t\t\t\t<span v-if=\"schemaItem.uuid && schemaItem.uuid !== schemaItem.id\"\n\t\t\t\t\t\tclass=\"cn-schema-form__detail-value cn-schema-form__uuid-value\">{{ schemaItem.uuid }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-schema-form__detail-item cn-schema-form__title-with-badge\">\n\t\t\t\t\t<NcTextField v-model=\"schemaItem.title\"\n\t\t\t\t\t\t:disabled=\"dialogLoading\"\n\t\t\t\t\t\t:label=\"t('nextcloud-vue', 'Title *')\" />\n\t\t\t\t\t<span v-if=\"schemaItem.allOf && schemaItem.allOf.length > 0\"\n\t\t\t\t\t\tclass=\"cn-schema-form__statusPill cn-schema-form__statusPill--success\">\n\t\t\t\t\t\tallOf\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"schemaItem.oneOf && schemaItem.oneOf.length > 0\"\n\t\t\t\t\t\tclass=\"cn-schema-form__statusPill cn-schema-form__statusPill--info\">\n\t\t\t\t\t\toneOf\n\t\t\t\t\t</span>\n\t\t\t\t\t<span v-if=\"schemaItem.anyOf && schemaItem.anyOf.length > 0\"\n\t\t\t\t\t\tclass=\"cn-schema-form__statusPill cn-schema-form__statusPill--info\">\n\t\t\t\t\t\tanyOf\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"schemaItem.created\" class=\"cn-schema-form__detail-item\">\n\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'Created:') }}</span>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ new Date(schemaItem.created).toLocaleString(userLocale()) }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"schemaItem.updated\" class=\"cn-schema-form__detail-item\">\n\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'Updated:') }}</span>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ new Date(schemaItem.updated).toLocaleString(userLocale()) }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-schema-form__detail-item\">\n\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'Version:') }}</span>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ schemaItem.version || t('nextcloud-vue', 'Not set') }}</span>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"cn-schema-form__detail-item\">\n\t\t\t\t\t<span class=\"cn-schema-form__detail-label\">{{ t('nextcloud-vue', 'Owner:') }}</span>\n\t\t\t\t\t<span class=\"cn-schema-form__detail-value\">{{ schemaItem.owner || t('nextcloud-vue', 'Not set') }}</span>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</template>\n\n\t\t<!-- Properties Tab -->\n\t\t<template #tab-properties=\"{ loading: dialogLoading }\">\n\t\t\t<CnSchemaPropertiesTab\n\t\t\t\t:schemaItem=\"schemaItem\"\n\t\t\t\t:loading=\"dialogLoading\"\n\t\t\t\t:selectedProperty=\"selectedProperty\"\n\t\t\t\t:propertiesModified=\"propertiesModified\"\n\t\t\t\t:originalProperties=\"originalProperties\"\n\t\t\t\t:inheritedProperties=\"inheritedProperties\"\n\t\t\t\t:typeOptionsForSelect=\"typeOptionsForSelect\"\n\t\t\t\t:availableSchemas=\"availableSchemas\"\n\t\t\t\t:availableRegisters=\"availableRegisters\"\n\t\t\t\t:availableTagsOptions=\"availableTagsOptions\"\n\t\t\t\t:userGroups=\"userGroups\"\n\t\t\t\t:sortedUserGroups=\"sortedUserGroups\"\n\t\t\t\t:loadingGroups=\"loadingGroups\"\n\t\t\t\t@addProperty=\"addProperty\"\n\t\t\t\t@update:selectedProperty=\"selectedProperty = $event\"\n\t\t\t\t@update:propertyKey=\"updatePropertyKey($event.oldKey, $event.newKey)\"\n\t\t\t\t@copyProperty=\"copyProperty\"\n\t\t\t\t@deleteProperty=\"deleteProperty\" />\n\t\t</template>\n\n\t\t<!-- Configuration Tab -->\n\t\t<template #tab-configuration=\"{ loading: dialogLoading }\">\n\t\t\t<CnSchemaConfigurationTab\n\t\t\t\t:schemaItem=\"schemaItem\"\n\t\t\t\t:loading=\"dialogLoading\"\n\t\t\t\t:availableSchemas=\"availableSchemas\"\n\t\t\t\t:propertyOptions=\"propertyOptions\"\n\t\t\t\t:allOfSchemaNames=\"allOfSchemaNames\" />\n\t\t</template>\n\n\t\t<!-- Security Tab -->\n\t\t<template #tab-security>\n\t\t\t<CnSchemaSecurityTab\n\t\t\t\t:schemaItem=\"schemaItem\"\n\t\t\t\t:userGroups=\"userGroups\"\n\t\t\t\t:sortedUserGroups=\"sortedUserGroups\"\n\t\t\t\t:loadingGroups=\"loadingGroups\"\n\t\t\t\t:hasAnyPermissions=\"hasAnyPermissions\"\n\t\t\t\t:isRestrictiveSchema=\"isRestrictiveSchema\"\n\t\t\t\t:inheritedProperties=\"inheritedProperties\" />\n\t\t</template>\n\n\t\t<!-- Optional Action Buttons (edit mode only) -->\n\t\t<template #actions-right=\"{ loading: dialogLoading, isCreateMode, result: dialogResult }\">\n\t\t\t<template v-if=\"!isCreateMode && dialogResult === null\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showExtendSchema\"\n\t\t\t\t\t:disabled=\"dialogLoading\"\n\t\t\t\t\t@click=\"$emit('extend-schema')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<CallSplit :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ extendSchemaLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showAnalyzeProperties\"\n\t\t\t\t\t:disabled=\"dialogLoading\"\n\t\t\t\t\t@click=\"$emit('analyze-properties')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<DatabaseSearch :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ analyzePropertiesLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showValidateObjects\"\n\t\t\t\t\t:disabled=\"dialogLoading\"\n\t\t\t\t\t@click=\"$emit('validate-objects')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<CheckCircle :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ validateObjectsLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showDeleteObjects\"\n\t\t\t\t\t:title=\"objectCount > 0 ? deleteObjectsTooltip : noDeleteObjectsTooltip\"\n\t\t\t\t\t:disabled=\"dialogLoading || objectCount === 0\"\n\t\t\t\t\t@click=\"$emit('delete-objects')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<DeleteSweep :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ deleteObjectsLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showPublishObjects\"\n\t\t\t\t\t:title=\"objectCount > 0 ? publishObjectsTooltip : noPublishObjectsTooltip\"\n\t\t\t\t\t:disabled=\"dialogLoading || objectCount === 0\"\n\t\t\t\t\t@click=\"$emit('publish-objects')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<Upload :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ publishObjectsLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showDelete\"\n\t\t\t\t\t:title=\"objectCount > 0 ? cannotDeleteTooltip : ''\"\n\t\t\t\t\t:disabled=\"dialogLoading || objectCount > 0\"\n\t\t\t\t\tvariant=\"error\"\n\t\t\t\t\t@click=\"$emit('delete-schema')\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<TrashCanOutline :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ deleteLabel }}\n\t\t\t\t</NcButton>\n\t\t\t</template>\n\t\t</template>\n\t</CnTabbedFormDialog>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport {\n\tNcButton,\n\tNcTextField,\n} from '@nextcloud/vue'\nimport CallSplit from 'vue-material-design-icons/CallSplit.vue'\nimport Check from 'vue-material-design-icons/Check.vue'\nimport CheckCircle from 'vue-material-design-icons/CheckCircle.vue'\nimport ContentCopy from 'vue-material-design-icons/ContentCopy.vue'\nimport DatabaseSearch from 'vue-material-design-icons/DatabaseSearch.vue'\nimport DeleteSweep from 'vue-material-design-icons/DeleteSweep.vue'\nimport TrashCanOutline from 'vue-material-design-icons/TrashCanOutline.vue'\nimport Upload from 'vue-material-design-icons/Upload.vue'\nimport CnTabbedFormDialog from '../CnTabbedFormDialog/CnTabbedFormDialog.vue'\nimport CnSchemaConfigurationTab from './CnSchemaConfigurationTab.vue'\nimport CnSchemaPropertiesTab from './CnSchemaPropertiesTab.vue'\nimport CnSchemaSecurityTab from './CnSchemaSecurityTab.vue'\nimport { dialogBoardMixin } from '../../mixins/dialogBoard.js'\nimport { userLocale } from '../../utils/userLocale.js'\n\n/**\n * CnSchemaFormDialog — Generic JSON Schema editor dialog.\n *\n * Provides a full-featured form for creating and editing JSON Schemas with\n * properties table, configuration, and security (RBAC) tabs. Uses CnTabbedFormDialog.\n *\n * The dialog does NOT perform saves — it emits a `confirm` event with the schema data.\n * The parent performs the actual API call and calls `setResult()` via a ref.\n *\n * @event confirm Emitted when the user confirms. Payload: cleaned schema data object.\n * @event close Emitted when the dialog should be closed.\n * @event extend-schema Emitted when the Extend Schema button is clicked.\n * @event analyze-properties Emitted when the Analyze Properties button is clicked.\n * @event validate-objects Emitted when the Validate Objects button is clicked.\n * @event delete-objects Emitted when the Delete Objects button is clicked.\n * @event publish-objects Emitted when the Publish Objects button is clicked.\n * @event delete-schema Emitted when the Delete button is clicked.\n */\nexport default {\n\tname: 'CnSchemaFormDialog',\n\tcomponents: {\n\t\tNcTextField,\n\t\tNcButton,\n\t\tCnTabbedFormDialog,\n\t\tCnSchemaPropertiesTab,\n\t\tCnSchemaConfigurationTab,\n\t\tCnSchemaSecurityTab,\n\t\t// Icons\n\t\tContentCopy,\n\t\tCheck,\n\t\tTrashCanOutline,\n\t\tCallSplit,\n\t\tDatabaseSearch,\n\t\tCheckCircle,\n\t\tDeleteSweep,\n\t\tUpload,\n\t},\n\n\tmixins: [dialogBoardMixin],\n\n\tprops: {\n\t\t/** Existing schema item for edit mode. Pass null for create mode. */\n\t\titem: { type: Object, default: null },\n\t\t/** Dialog title. Defaults to \"Create Schema\" or \"Edit Schema\". */\n\t\tdialogTitle: { type: String, default: '' },\n\t\t/** NcDialog size */\n\t\tsize: { type: String, default: 'large' },\n\t\t/** Available schemas for references and composition. Array of { id, title, description, reference } */\n\t\tavailableSchemas: { type: Array, default: () => [] },\n\t\t/** Available registers. Array of { id, label } */\n\t\tavailableRegisters: { type: Array, default: () => [] },\n\t\t/** User groups for RBAC. Array of { id, displayname } */\n\t\tuserGroups: { type: Array, default: () => [] },\n\t\t/** Available tags for file property configuration */\n\t\tavailableTags: { type: Array, default: () => [] },\n\t\t/** Whether user groups are still loading */\n\t\tloadingGroups: { type: Boolean, default: false },\n\t\t/** Properties inherited from parent schemas (allOf) — shown as locked rows in the properties tab */\n\t\tinheritedProperties: { type: Object, default: () => ({}) },\n\t\t/** Number of objects attached to this schema (used for action button disable logic) */\n\t\tobjectCount: { type: Number, default: 0 },\n\t\t// Optional action button visibility\n\t\t/** Show \"Extend Schema\" button */\n\t\tshowExtendSchema: { type: Boolean, default: false },\n\t\t/** Show \"Analyze Properties\" button */\n\t\tshowAnalyzeProperties: { type: Boolean, default: false },\n\t\t/** Show \"Validate Objects\" button */\n\t\tshowValidateObjects: { type: Boolean, default: false },\n\t\t/** Show \"Delete Objects\" button */\n\t\tshowDeleteObjects: { type: Boolean, default: false },\n\t\t/** Show \"Publish Objects\" button */\n\t\tshowPublishObjects: { type: Boolean, default: false },\n\t\t/** Show \"Delete\" button */\n\t\tshowDelete: { type: Boolean, default: false },\n\t\t// Labels (pre-translated strings with English defaults)\n\t\t/** Label for the cancel button shown while editing. */\n\t\tcancelLabel: { type: String, default: () => t('nextcloud-vue', 'Cancel') },\n\t\t/** Label for the close button shown after a save or error. */\n\t\tcloseLabel: { type: String, default: () => t('nextcloud-vue', 'Close') },\n\t\t/** Confirm button label. Defaults to \"Create\" or \"Save\". */\n\t\tconfirmLabel: { type: String, default: '' },\n\t\t/** Success message. Defaults to \"Schema saved successfully.\" */\n\t\tsuccessText: { type: String, default: '' },\n\t\t/** Label for the Extend Schema action button. */\n\t\textendSchemaLabel: { type: String, default: () => t('nextcloud-vue', 'Extend schema') },\n\t\t/** Label for the Analyze Properties action button. */\n\t\tanalyzePropertiesLabel: { type: String, default: () => t('nextcloud-vue', 'Analyze properties') },\n\t\t/** Label for the Validate Objects action button. */\n\t\tvalidateObjectsLabel: { type: String, default: () => t('nextcloud-vue', 'Validate objects') },\n\t\t/** Label for the Delete Objects action button. */\n\t\tdeleteObjectsLabel: { type: String, default: () => t('nextcloud-vue', 'Delete objects') },\n\t\t/** Label for the Publish Objects action button. */\n\t\tpublishObjectsLabel: { type: String, default: () => t('nextcloud-vue', 'Publish objects') },\n\t\t/** Label for the Delete schema button shown in edit mode. */\n\t\tdeleteLabel: { type: String, default: () => t('nextcloud-vue', 'Delete') },\n\t\t/** Tooltip for the Delete Objects button when objects exist. */\n\t\tdeleteObjectsTooltip: { type: String, default: () => t('nextcloud-vue', 'Delete all objects in this schema') },\n\t\t/** Tooltip for the Publish Objects button when objects exist. */\n\t\tpublishObjectsTooltip: { type: String, default: () => t('nextcloud-vue', 'Publish all objects in this schema') },\n\t\t/** Tooltip for the Delete Objects button when no objects exist */\n\t\tnoDeleteObjectsTooltip: { type: String, default: () => t('nextcloud-vue', 'No objects to delete') },\n\t\t/** Tooltip for the Publish Objects button when no objects exist */\n\t\tnoPublishObjectsTooltip: { type: String, default: () => t('nextcloud-vue', 'No objects to publish') },\n\t\t/** Tooltip for the Delete schema button while objects are still attached. */\n\t\tcannotDeleteTooltip: { type: String, default: () => t('nextcloud-vue', 'Cannot delete: objects are still attached') },\n\t},\n\n\temits: [\n\t\t'analyze-properties',\n\t\t'close',\n\t\t'confirm',\n\t\t'delete-objects',\n\t\t'delete-schema',\n\t\t'extend-schema',\n\t\t'publish-objects',\n\t\t'validate-objects',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tisCopied: false,\n\t\t\tselectedProperty: null,\n\t\t\tpropertiesModified: false,\n\t\t\toriginalProperties: null,\n\t\t\tschemaItem: {\n\t\t\t\ttitle: '',\n\t\t\t\tversion: '0.0.0',\n\t\t\t\tdescription: '',\n\t\t\t\tsummary: '',\n\t\t\t\tslug: '',\n\t\t\t\tproperties: {},\n\t\t\t\tconfiguration: {\n\t\t\t\t\tobjectNameField: '',\n\t\t\t\t\tobjectDescriptionField: '',\n\t\t\t\t\tobjectImageField: '',\n\t\t\t\t\tobjectSummaryField: '',\n\t\t\t\t\tallowFiles: false,\n\t\t\t\t\tallowedTags: [],\n\t\t\t\t\tautoPublish: false,\n\t\t\t\t\tdefaultAutoShare: false,\n\t\t\t\t},\n\n\t\t\t\tauthorization: {},\n\t\t\t\thardValidation: false,\n\t\t\t\timmutable: false,\n\t\t\t\tsearchable: true,\n\t\t\t\ticon: null,\n\t\t\t\tmaxDepth: 0,\n\t\t\t},\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Tab definitions for CnTabbedFormDialog.\n\t\t *\n\t\t * @return {Array} Tab configuration\n\t\t */\n\t\tdialogTabs() {\n\t\t\treturn [\n\t\t\t\t{ id: 'properties', title: t('nextcloud-vue', 'Properties') },\n\t\t\t\t{ id: 'configuration', title: t('nextcloud-vue', 'Configuration') },\n\t\t\t\t{ id: 'security', title: t('nextcloud-vue', 'Security') },\n\t\t\t]\n\t\t},\n\n\t\tsortedUserGroups() {\n\t\t\treturn this.userGroups\n\t\t\t\t.filter((group) => group.id !== 'admin' && group.id !== 'public' && group.id !== 'authenticated')\n\t\t\t\t.sort((a, b) => {\n\t\t\t\t\tconst nameA = a.displayname || a.id\n\t\t\t\t\tconst nameB = b.displayname || b.id\n\t\t\t\t\treturn nameA.localeCompare(nameB)\n\t\t\t\t})\n\t\t},\n\n\t\thasAnyPermissions() {\n\t\t\tconst auth = this.schemaItem.authorization || {}\n\t\t\treturn Object.keys(auth).some((action) => Array.isArray(auth[action]) && auth[action].length > 0)\n\t\t},\n\n\t\tisRestrictiveSchema() {\n\t\t\tconst auth = this.schemaItem.authorization || {}\n\t\t\tconst actions = ['create', 'read', 'update', 'delete']\n\t\t\treturn actions.some((action) => Array.isArray(auth[action]) && auth[action].length > 0\n\t\t\t\t&& !auth[action].includes('public'))\n\t\t},\n\n\t\ttypeOptionsForSelect() {\n\t\t\treturn [\n\t\t\t\t{ id: 'string', label: t('nextcloud-vue', 'String') },\n\t\t\t\t{ id: 'number', label: t('nextcloud-vue', 'Number') },\n\t\t\t\t{ id: 'integer', label: t('nextcloud-vue', 'Integer') },\n\t\t\t\t{ id: 'boolean', label: t('nextcloud-vue', 'Boolean') },\n\t\t\t\t{ id: 'array', label: t('nextcloud-vue', 'Array') },\n\t\t\t\t{ id: 'object', label: t('nextcloud-vue', 'Object') },\n\t\t\t\t{ id: 'dictionary', label: t('nextcloud-vue', 'Dictionary') },\n\t\t\t\t{ id: 'file', label: t('nextcloud-vue', 'File') },\n\t\t\t\t{ id: 'oneOf', label: t('nextcloud-vue', 'One of') },\n\t\t\t]\n\t\t},\n\n\t\tpropertyOptions() {\n\t\t\tconst ownKeys = Object.keys(this.schemaItem.properties || {}).filter((k) => k !== '')\n\t\t\tconst inheritedKeys = Object.keys(this.inheritedProperties || {}).filter((k) => k !== '')\n\t\t\treturn [...new Set([...inheritedKeys, ...ownKeys])]\n\t\t},\n\n\t\tavailableTagsOptions() {\n\t\t\treturn this.availableTags.map((tag) => ({\n\t\t\t\tid: tag,\n\t\t\t\tlabel: tag,\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * Resolved success text for backwards compatibility (includes trailing period).\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedSuccessText() {\n\t\t\tif (this.successText) {\n\t\t\t\treturn this.successText\n\t\t\t}\n\t\t\treturn t('nextcloud-vue', '{title} saved successfully.', { title: t('nextcloud-vue', 'Schema') })\n\t\t},\n\n\t\t/**\n\t\t * Returns a human-readable reason the save button is disabled, or '' when saving is allowed.\n\t\t * Used for both :disable-save and the WCAG tooltip/aria-label on the button.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tsaveDisabledReason() {\n\t\t\tif (!this.schemaItem.title) {\n\t\t\t\treturn t('nextcloud-vue', 'A schema title is required before saving')\n\t\t\t}\n\t\t\tconst hasUnnamedProperty = Object.keys(this.schemaItem.properties || {}).some((key) => key === '')\n\t\t\tif (hasUnnamedProperty) {\n\t\t\t\treturn t('nextcloud-vue', 'All properties must have a name before saving')\n\t\t\t}\n\t\t\treturn ''\n\t\t},\n\n\t\tallOfSchemaNames() {\n\t\t\tif (!this.schemaItem.allOf || !Array.isArray(this.schemaItem.allOf) || this.schemaItem.allOf.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\n\t\t\treturn this.schemaItem.allOf\n\t\t\t\t.map((ref) => {\n\t\t\t\t\tconst schemaId = typeof ref === 'object' ? ref.id : ref\n\t\t\t\t\tconst schema = this.availableSchemas.find((s) => s.id === schemaId)\n\t\t\t\t\treturn schema ? (schema.title || `Schema ${schema.id}`) : schemaId\n\t\t\t\t})\n\t\t\t\t.filter((name) => name)\n\t\t},\n\t},\n\n\twatch: {\n\t\titem: {\n\t\t\timmediate: true,\n\t\t\thandler() {\n\t\t\t\tthis.initializeSchemaItem()\n\t\t\t},\n\t\t},\n\n\t\t'schemaItem.properties': {\n\t\t\thandler(newProperties) {\n\t\t\t\tif (newProperties) {\n\t\t\t\t\tObject.keys(newProperties).forEach((key) => {\n\t\t\t\t\t\tconst property = newProperties[key]\n\t\t\t\t\t\tif (property) {\n\t\t\t\t\t\t\t// Initialize nested objects if they don't exist\n\t\t\t\t\t\t\tif (property.type === 'array' && !property.items) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items = { type: 'string' }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (property.type === 'object' && !property.objectConfiguration) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration = { handling: 'nested-object' }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (property.type === 'array' && property.items && property.items.type === 'object' && !property.items.objectConfiguration) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration = { handling: 'nested-object' }\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert property type from object to string\n\t\t\t\t\t\t\tif (property.type && typeof property.type === 'object' && property.type.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].type = property.type.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert property format from object to string\n\t\t\t\t\t\t\tif (property.format && typeof property.format === 'object' && property.format.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].format = property.format.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert array item type from object to string\n\t\t\t\t\t\t\tif (property.items && property.items.type && typeof property.items.type === 'object' && property.items.type.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.type = property.items.type.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert object handling from object to string\n\t\t\t\t\t\t\tif (property.objectConfiguration && property.objectConfiguration.handling\n\t\t\t\t\t\t\t\t&& typeof property.objectConfiguration.handling === 'object' && property.objectConfiguration.handling.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration.handling = property.objectConfiguration.handling.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert register from object to ID\n\t\t\t\t\t\t\tif (property.objectConfiguration && property.objectConfiguration.register\n\t\t\t\t\t\t\t\t&& typeof property.objectConfiguration.register === 'object' && property.objectConfiguration.register.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration.register = property.objectConfiguration.register.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert array item object handling from object to string\n\t\t\t\t\t\t\tif (property.items && property.items.objectConfiguration && property.items.objectConfiguration.handling\n\t\t\t\t\t\t\t\t&& typeof property.items.objectConfiguration.handling === 'object' && property.items.objectConfiguration.handling.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration.handling = property.items.objectConfiguration.handling.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Convert array item register from object to ID\n\t\t\t\t\t\t\tif (property.items && property.items.objectConfiguration && property.items.objectConfiguration.register\n\t\t\t\t\t\t\t\t&& typeof property.items.objectConfiguration.register === 'object' && property.items.objectConfiguration.register.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration.register = property.items.objectConfiguration.register.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Ensure $ref is always a string\n\t\t\t\t\t\t\tthis.ensureRefIsString(this.schemaItem.properties, key)\n\n\t\t\t\t\t\t\t// Ensure inversedBy is always a string for regular properties\n\t\t\t\t\t\t\tif (property.inversedBy && typeof property.inversedBy === 'object' && property.inversedBy.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].inversedBy = property.inversedBy.id\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Ensure inversedBy is always a string for array items\n\t\t\t\t\t\t\tif (property.items && property.items.inversedBy && typeof property.items.inversedBy === 'object' && property.items.inversedBy.id) {\n\t\t\t\t\t\t\t\tthis.schemaItem.properties[key].items.inversedBy = property.items.inversedBy.id\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tthis.checkPropertiesModified()\n\t\t\t},\n\n\t\t\tdeep: true,\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tuserLocale,\n\t\tfindSchemaBySlug(schemaSlug) {\n\t\t\tif (!schemaSlug) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn this.availableSchemas.find((schema) => (schema.slug && schema.slug.toLowerCase() === schemaSlug.toLowerCase())\n\t\t\t\t|| schema.id === schemaSlug\n\t\t\t\t|| schema.title === schemaSlug)\n\t\t},\n\n\t\tensureRefIsString(obj, key) {\n\t\t\tif (!obj || !key) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (obj[key] && typeof obj[key].$ref === 'object' && obj[key].$ref !== null) {\n\t\t\t\tif (obj[key].$ref.id) {\n\t\t\t\t\tobj[key].$ref = obj[key].$ref.id\n\t\t\t\t} else {\n\t\t\t\t\tobj[key].$ref = ''\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (obj[key] && obj[key].items && typeof obj[key].items.$ref === 'object' && obj[key].items.$ref !== null) {\n\t\t\t\tif (obj[key].items.$ref.id) {\n\t\t\t\t\tobj[key].items.$ref = obj[key].items.$ref.id\n\t\t\t\t} else {\n\t\t\t\t\tobj[key].items.$ref = ''\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tinitializeSchemaItem() {\n\t\t\t// Reset CnTabbedFormDialog state if available (not yet mounted on first call)\n\t\t\tif (this.$refs.dialog) {\n\t\t\t\tthis.$refs.dialog.resetDialog()\n\t\t\t}\n\n\t\t\t// Always rebuild schemaItem from defaults + incoming item. This handles\n\t\t\t// create mode (item null), edit mode (item with id), and extend mode\n\t\t\t// (item non-null with no id) without leaking stale state across opens.\n\t\t\tconst defaults = {\n\t\t\t\ttitle: '',\n\t\t\t\tversion: '0.0.0',\n\t\t\t\tdescription: '',\n\t\t\t\tsummary: '',\n\t\t\t\tslug: '',\n\t\t\t\tproperties: {},\n\t\t\t\tconfiguration: {\n\t\t\t\t\tobjectNameField: '',\n\t\t\t\t\tobjectDescriptionField: '',\n\t\t\t\t\tobjectImageField: '',\n\t\t\t\t\tobjectSummaryField: '',\n\t\t\t\t\tallowFiles: false,\n\t\t\t\t\tallowedTags: [],\n\t\t\t\t\tautoPublish: false,\n\t\t\t\t\tdefaultAutoShare: false,\n\t\t\t\t},\n\n\t\t\t\tauthorization: {},\n\t\t\t\thardValidation: false,\n\t\t\t\timmutable: false,\n\t\t\t\tsearchable: true,\n\t\t\t\ticon: null,\n\t\t\t\tmaxDepth: 0,\n\t\t\t}\n\t\t\tthis.schemaItem = this.item\n\t\t\t\t? { ...defaults, ...JSON.parse(JSON.stringify(this.item)) }\n\t\t\t\t: { ...defaults }\n\n\t\t\t// Ensure configuration object has all expected keys (the spread above may\n\t\t\t// have replaced our defaults with a partial configuration from the item)\n\t\t\tif (!this.schemaItem.configuration) {\n\t\t\t\tthis.schemaItem.configuration = { ...defaults.configuration }\n\t\t\t} else {\n\t\t\t\tif (!this.schemaItem.configuration.objectNameField) {\n\t\t\t\t\tthis.schemaItem.configuration.objectNameField = ''\n\t\t\t\t}\n\t\t\t\tif (!this.schemaItem.configuration.objectDescriptionField) {\n\t\t\t\t\tthis.schemaItem.configuration.objectDescriptionField = ''\n\t\t\t\t}\n\t\t\t\tif (!this.schemaItem.configuration.objectImageField) {\n\t\t\t\t\tthis.schemaItem.configuration.objectImageField = ''\n\t\t\t\t}\n\t\t\t\tif (!this.schemaItem.configuration.objectSummaryField) {\n\t\t\t\t\tthis.schemaItem.configuration.objectSummaryField = ''\n\t\t\t\t}\n\t\t\t\tif (this.schemaItem.configuration.allowFiles === undefined) {\n\t\t\t\t\tthis.schemaItem.configuration.allowFiles = false\n\t\t\t\t}\n\t\t\t\tif (!this.schemaItem.configuration.allowedTags) {\n\t\t\t\t\tthis.schemaItem.configuration.allowedTags = []\n\t\t\t\t}\n\t\t\t\tif (this.schemaItem.configuration.autoPublish === undefined) {\n\t\t\t\t\tthis.schemaItem.configuration.autoPublish = false\n\t\t\t\t}\n\t\t\t\tif (this.schemaItem.configuration.defaultAutoShare === undefined) {\n\t\t\t\t\tthis.schemaItem.configuration.defaultAutoShare = false\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Ensure authorization object exists\n\t\t\tif (!this.schemaItem.authorization) {\n\t\t\t\tthis.schemaItem.authorization = {}\n\t\t\t}\n\n\t\t\t// Ensure existing properties have facetable set to false by default\n\t\t\tObject.keys(this.schemaItem.properties || {}).forEach((key) => {\n\t\t\t\tif (this.schemaItem.properties[key].facetable === undefined) {\n\t\t\t\t\tthis.schemaItem.properties[key].facetable = false\n\t\t\t\t}\n\n\t\t\t\tif (this.schemaItem.properties[key].enum && Array.isArray(this.schemaItem.properties[key].enum)) {\n\t\t\t\t\tthis.schemaItem.properties[key].enum = [...this.schemaItem.properties[key].enum]\n\t\t\t\t}\n\n\t\t\t\tconst property = this.schemaItem.properties[key]\n\t\t\t\tif (property.type === 'array' && property.items && property.items.type === 'object' && !property.items.objectConfiguration) {\n\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration = { handling: 'nested-object' }\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// Ensure all $ref values are strings and migrate old structure\n\t\t\tObject.keys(this.schemaItem.properties || {}).forEach((key) => {\n\t\t\t\tthis.ensureRefIsString(this.schemaItem.properties, key)\n\t\t\t\tthis.migratePropertyToNewStructure(key)\n\t\t\t})\n\n\t\t\t// Snapshot original properties for change detection. For new/extending\n\t\t\t// items (no id), there's no \"original\" — start empty so any added\n\t\t\t// properties register as modifications.\n\t\t\tthis.originalProperties = this.schemaItem.id\n\t\t\t\t? JSON.parse(JSON.stringify(this.schemaItem.properties || {}))\n\t\t\t\t: {}\n\n\t\t\tthis.propertiesModified = false\n\t\t},\n\n\t\tcheckPropertiesModified() {\n\t\t\tif (!this.originalProperties) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tconst currentProperties = JSON.stringify(this.schemaItem.properties || {})\n\t\t\tconst originalProperties = JSON.stringify(this.originalProperties)\n\n\t\t\tthis.propertiesModified = currentProperties !== originalProperties\n\t\t},\n\n\t\tasync copyToClipboard(text) {\n\t\t\ttry {\n\t\t\t\tawait navigator.clipboard.writeText(text)\n\t\t\t\tthis.isCopied = true\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis.isCopied = false\n\t\t\t\t}, 2000)\n\t\t\t} catch (err) {\n\t\t\t\t// eslint-disable-next-line no-console -- the failure is already handled; the console is the only channel a host app can read the detail on\n\t\t\t\tconsole.error('Failed to copy text:', err)\n\t\t\t}\n\t\t},\n\n\t\taddProperty() {\n\t\t\tthis.schemaItem.properties[''] = {\n\t\t\t\ttype: 'string',\n\t\t\t\tformat: '',\n\t\t\t\ttitle: '',\n\t\t\t\tdescription: '',\n\t\t\t\tfacetable: false,\n\t\t\t}\n\n\t\t\tthis.checkPropertiesModified()\n\t\t\tthis.selectedProperty = ''\n\t\t},\n\n\t\tupdatePropertyKey(oldKey, newKey) {\n\t\t\tif (newKey === oldKey) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.schemaItem.properties[newKey] !== undefined && newKey !== oldKey) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst propertyData = { ...this.schemaItem.properties[oldKey] }\n\n\t\t\tthis.schemaItem.properties[newKey] = propertyData\n\t\t\tdelete this.schemaItem.properties[oldKey]\n\n\t\t\tthis.selectedProperty = newKey\n\t\t\tthis.checkPropertiesModified()\n\t\t},\n\n\t\tdeleteProperty(key) {\n\t\t\tdelete this.schemaItem.properties[key]\n\n\t\t\tif (this.selectedProperty === key) {\n\t\t\t\tthis.selectedProperty = null\n\t\t\t}\n\n\t\t\tthis.checkPropertiesModified()\n\t\t},\n\n\t\tcopyProperty(key) {\n\t\t\tif (this.schemaItem.properties[key]) {\n\t\t\t\tconst originalProperty = JSON.parse(JSON.stringify(this.schemaItem.properties[key]))\n\n\t\t\t\tlet newPropertyName = `${key}_copy`\n\t\t\t\tlet counter = 1\n\n\t\t\t\twhile (this.schemaItem.properties[newPropertyName]) {\n\t\t\t\t\tcounter++\n\t\t\t\t\tnewPropertyName = `${key}_copy_${counter}`\n\t\t\t\t}\n\n\t\t\t\tconst originalTitle = originalProperty.title || key\n\t\t\t\tthis.schemaItem.properties[newPropertyName] = {\n\t\t\t\t\t...originalProperty,\n\t\t\t\t\ttitle: `${originalTitle} (copy)`,\n\t\t\t\t}\n\n\t\t\t\tthis.checkPropertiesModified()\n\t\t\t\tthis.selectedProperty = newPropertyName\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle confirm from CnTabbedFormDialog.\n\t\t * Cleans schema data and emits confirm with the cleaned payload.\n\t\t */\n\t\thandleConfirm() {\n\t\t\tconst cleanedSchemaItem = JSON.parse(JSON.stringify(this.schemaItem))\n\t\t\tObject.keys(cleanedSchemaItem.properties || {}).forEach((key) => {\n\t\t\t\tthis.ensureRefIsString(cleanedSchemaItem.properties, key)\n\n\t\t\t\tif (cleanedSchemaItem.properties[key].register\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].objectConfiguration\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].objectConfiguration.register) {\n\t\t\t\t\tdelete cleanedSchemaItem.properties[key].register\n\t\t\t\t}\n\n\t\t\t\tif (cleanedSchemaItem.properties[key].items\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].items.register\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].items.objectConfiguration\n\t\t\t\t\t&& cleanedSchemaItem.properties[key].items.objectConfiguration.register) {\n\t\t\t\t\tdelete cleanedSchemaItem.properties[key].items.register\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// NcSelect (track-by=\"id\") can convert plain IDs to full option objects.\n\t\t\t// Normalise back to plain IDs before emitting so the backend always gets scalars.\n\t\t\tfor (const field of ['allOf', 'oneOf', 'anyOf']) {\n\t\t\t\tif (Array.isArray(cleanedSchemaItem[field])) {\n\t\t\t\t\tcleanedSchemaItem[field] = cleanedSchemaItem[field]\n\t\t\t\t\t\t.map((ref) => (typeof ref === 'object' && ref !== null ? ref.id : ref))\n\t\t\t\t\t\t.filter((id) => id !== null && id !== undefined && id !== '')\n\t\t\t\t\tif (cleanedSchemaItem[field].length === 0) {\n\t\t\t\t\t\tdelete cleanedSchemaItem[field]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.$emit('confirm', cleanedSchemaItem)\n\t\t},\n\n\t\t/**\n\t\t * Set the result of the save operation. Call this from the parent\n\t\t * after the API call completes.\n\t\t *\n\t\t * @param {{ success?: boolean, error?: string }} resultData - result data\n\t\t * @public\n\t\t */\n\t\tsetResult(resultData) {\n\t\t\tthis.$refs.dialog.setResult(resultData)\n\t\t\tif (resultData.success) {\n\t\t\t\tthis.originalProperties = JSON.parse(JSON.stringify(this.schemaItem.properties || {}))\n\t\t\t\tthis.propertiesModified = false\n\t\t\t}\n\t\t},\n\n\t\tmigratePropertyToNewStructure(key) {\n\t\t\tif (!this.schemaItem.properties[key]) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tconst property = this.schemaItem.properties[key]\n\n\t\t\tif (property.$ref && property.register && !property.objectConfiguration?.register) {\n\t\t\t\tif (!property.objectConfiguration) {\n\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration = { handling: 'related-object' }\n\t\t\t\t}\n\n\t\t\t\tconst registerId = typeof property.register === 'object' && property.register.id\n\t\t\t\t\t? property.register.id\n\t\t\t\t\t: property.register\n\n\t\t\t\tthis.schemaItem.properties[key].objectConfiguration.register = registerId\n\n\t\t\t\tif (property.$ref) {\n\t\t\t\t\tlet schemaSlug = property.$ref\n\t\t\t\t\tif (schemaSlug.includes('/')) {\n\t\t\t\t\t\tschemaSlug = schemaSlug.substring(schemaSlug.lastIndexOf('/') + 1)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst referencedSchema = this.findSchemaBySlug(schemaSlug)\n\t\t\t\t\tif (referencedSchema) {\n\t\t\t\t\t\tthis.schemaItem.properties[key].objectConfiguration.schema = referencedSchema.id\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (property.items && property.items.$ref && property.items.register && !property.items.objectConfiguration?.register) {\n\t\t\t\tif (!property.items.objectConfiguration) {\n\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration = { handling: 'related-object' }\n\t\t\t\t}\n\n\t\t\t\tconst registerId = typeof property.items.register === 'object' && property.items.register.id\n\t\t\t\t\t? property.items.register.id\n\t\t\t\t\t: property.items.register\n\n\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration.register = registerId\n\n\t\t\t\tif (property.items.$ref) {\n\t\t\t\t\tlet schemaSlug = property.items.$ref\n\t\t\t\t\tif (schemaSlug.includes('/')) {\n\t\t\t\t\t\tschemaSlug = schemaSlug.substring(schemaSlug.lastIndexOf('/') + 1)\n\t\t\t\t\t}\n\n\t\t\t\t\tconst referencedSchema = this.findSchemaBySlug(schemaSlug)\n\t\t\t\t\tif (referencedSchema) {\n\t\t\t\t\t\tthis.schemaItem.properties[key].items.objectConfiguration.schema = referencedSchema.id\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n"],"names":["_createBlock","_withCtx","_createElementVNode","_openBlock","_createElementBlock","_toDisplayString","_createVNode","_createTextVNode","_Fragment"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnSettingsPage.vue2.js';
|
|
|
2
2
|
import { render } from './CnSettingsPage.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-04e49f77";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -4,6 +4,7 @@ import { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextField }
|
|
|
4
4
|
import ContentSave from 'vue-material-design-icons/ContentSave.vue';
|
|
5
5
|
import __sfc_main from '../CnBuildiqEditButton/CnBuildiqEditButton.vue.js';
|
|
6
6
|
import __sfc_main$5 from '../CnRegisterMapping/CnRegisterMapping.vue.js';
|
|
7
|
+
import __sfc_main$6 from '../CnToggleTableWidget/CnToggleTableWidget.vue.js';
|
|
7
8
|
import __sfc_main$4 from '../CnVersionInfoCard/CnVersionInfoCard.vue.js';
|
|
8
9
|
import { useLook } from '../../composables/useLook.js';
|
|
9
10
|
import { prefixUrl } from '../../utils/headers.js';
|
|
@@ -41,6 +42,8 @@ const COMPONENT_DISCRIMINATOR = Symbol('cn-settings-component-widget');
|
|
|
41
42
|
const BUILTIN_SETTINGS_WIDGETS = Object.freeze({
|
|
42
43
|
'version-info': __sfc_main$4,
|
|
43
44
|
'register-mapping': __sfc_main$5,
|
|
45
|
+
// Rows with a switch: objects (`bind.mode: 'each'`) or a config map (`'map'`).
|
|
46
|
+
'toggle-table': __sfc_main$6,
|
|
44
47
|
component: COMPONENT_DISCRIMINATOR,
|
|
45
48
|
});
|
|
46
49
|
|
|
@@ -68,7 +71,8 @@ const BUILTIN_SETTINGS_WIDGETS = Object.freeze({
|
|
|
68
71
|
* - `widgets[]` — ordered list of widgets. Each entry has a `type`
|
|
69
72
|
* string and optional `props`. Built-in widget types resolve
|
|
70
73
|
* first (`version-info` → `CnVersionInfoCard`, `register-mapping`
|
|
71
|
-
* → `CnRegisterMapping`);
|
|
74
|
+
* → `CnRegisterMapping`, `toggle-table` → `CnToggleTableWidget`);
|
|
75
|
+
* unknown types fall back to the
|
|
72
76
|
* `customComponents` registry.
|
|
73
77
|
*
|
|
74
78
|
* Widget events (e.g. CnRegisterMapping's `@save`, CnVersionInfoCard's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnSettingsPage.vue2.js","sources":["../../../../src/components/CnSettingsPage/CnSettingsPage.vue"],"sourcesContent":["<!--\n CnSettingsPage — Admin / config surface.\n\n Renders manifest-driven config sections. The page MAY declare\n EITHER a flat `sections[]` array (back-compat) OR a `tabs[]` array\n (each tab owns its own `sections[]`) — XOR, never both. See\n manifest-settings-orchestration spec.\n\n Each section is a CnSettingsCard wrapping a CnSettingsSection.\n A section MUST declare exactly one of three body kinds:\n\n 1. `fields[]` — flat form fields (back-compat, default)\n 2. `component` — registry-resolved component as the section body\n 3. `widgets[]` — ordered list of widgets (built-in + customComponents)\n\n Built-in widget types (resolved BEFORE the customComponents registry):\n - `version-info` → CnVersionInfoCard\n - `register-mapping` → CnRegisterMapping\n - `component` → discriminator; `widget.componentName`\n resolves against customComponents\n\n Saves via `axios.put(saveEndpoint, formData)` with the consumer's\n settings controller URL. Widget events bubble up through\n `@widget-event` so consumers wire one page-level handler that\n dispatches by `widgetType` + event `name` (the manifest can't carry\n inline JS).\n\n Supports the same `headerComponent` / `actionsComponent` / generic\n `slots` overrides that the other built-in page types do — the\n CnPageRenderer wires them via the `#header`, `#actions`, and named\n `slots[]` slots exposed here.\n-->\n<template>\n\t<div class=\"cn-settings-page\" data-testid=\"cn-settings-page\">\n\t\t<!-- Header — overridable via #header slot. CnPageHeader renders whenever\n\t\t there is a title: `visuallyHidden` keeps the <h1> in the\n\t\t accessibility tree (and out of the visual layout) when showTitle is\n\t\t false, so <main> is never left with no heading at all\n\t\t (WCAG 2.4.6 / 1.3.1). -->\n\t\t<slot\n\t\t\tname=\"header\"\n\t\t\t:title=\"title\"\n\t\t\t:description=\"description\"\n\t\t\t:icon=\"icon\">\n\t\t\t<CnPageHeader\n\t\t\t\tv-if=\"title\"\n\t\t\t\t:title=\"title\"\n\t\t\t\t:description=\"resolvedDescription\"\n\t\t\t\t:icon=\"icon\"\n\t\t\t\t:visuallyHidden=\"!showTitle\">\n\t\t\t\t<!-- Board look: the buildiq square, then the page Save as the\n\t\t\t\t last header button. -->\n\t\t\t\t<template v-if=\"headerButtonsInHeader\" #extra>\n\t\t\t\t\t<div class=\"cn-settings-page__header-buttons\" data-testid=\"cn-settings-page-header-buttons\">\n\t\t\t\t\t\t<CnBuildiqEditButton v-if=\"isBoard\" />\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"pageSave\"\n\t\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t\t:disabled=\"saving || !dirty\"\n\t\t\t\t\t\t\tdata-testid=\"cn-settings-page-save\"\n\t\t\t\t\t\t\t@click=\"save\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"saving\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<ContentSave v-else :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ saveLabel }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t</CnPageHeader>\n\t\t</slot>\n\n\t\t<!-- The same buttons when the header itself is hidden or replaced. -->\n\t\t<div\n\t\t\tv-if=\"headerButtonsOutside\"\n\t\t\tclass=\"cn-settings-page__header-buttons\"\n\t\t\tdata-testid=\"cn-settings-page-header-buttons\">\n\t\t\t<CnBuildiqEditButton v-if=\"isBoard\" />\n\t\t\t<NcButton\n\t\t\t\tv-if=\"pageSave\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"saving || !dirty\"\n\t\t\t\tdata-testid=\"cn-settings-page-save\"\n\t\t\t\t@click=\"save\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"saving\" :size=\"20\" />\n\t\t\t\t\t<ContentSave v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ saveLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- The Changes card of a page that saves in its header. -->\n\t\t<div\n\t\t\tv-if=\"pageSave && changedFields.length > 0\"\n\t\t\tclass=\"cn-settings-page__changes\"\n\t\t\tdata-testid=\"cn-settings-page-changes\">\n\t\t\t<h2 class=\"cn-settings-page__changes-title\">\n\t\t\t\t{{ changesLabel }}\n\t\t\t</h2>\n\t\t\t<ul>\n\t\t\t\t<li v-for=\"field in changedFields\" :key=\"field.key\">\n\t\t\t\t\t{{ field.label }}\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<!-- Actions slot for save / discard / reset overrides -->\n\t\t<div v-if=\"$slots.actions || $slots.actions\" class=\"cn-settings-page__actions\">\n\t\t\t<slot name=\"actions\" />\n\t\t</div>\n\n\t\t<!-- Tab strip — only rendered when `tabs[]` is set\n\t\t\t (manifest-settings-orchestration REQ-MSO-5). Built with\n\t\t\t native <button role=\"tab\"> + ARIA wiring; uses Nextcloud\n\t\t\t CSS variables only (no hex literals). -->\n\t\t<div\n\t\t\tv-if=\"hasTabs\"\n\t\t\tclass=\"cn-settings-page__tabs\"\n\t\t\trole=\"tablist\"\n\t\t\tdata-testid=\"cn-settings-page-tabs\">\n\t\t\t<button\n\t\t\t\tv-for=\"(tab, tabIndex) in tabs\"\n\t\t\t\t:key=\"`tab-${tab.id}`\"\n\t\t\t\trole=\"tab\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"cn-settings-page__tab\"\n\t\t\t\t:class=\"{ 'cn-settings-page__tab--active': activeTabId === tab.id }\"\n\t\t\t\t:aria-selected=\"activeTabId === tab.id ? 'true' : 'false'\"\n\t\t\t\t:aria-controls=\"`cn-settings-tab-panel-${tab.id}`\"\n\t\t\t\t:data-testid=\"`cn-settings-page-tab-${tab.id}`\"\n\t\t\t\t@click=\"onTabClick(tab, tabIndex)\">\n\t\t\t\t{{ resolveLabel(tab.label) }}\n\t\t\t</button>\n\t\t</div>\n\n\t\t<!-- Sections — rendered for the active tab when `tabs[]` is\n\t\t\t set, otherwise the flat `sections[]` (back-compat). The wrapper\n\t\t\t draws no box of its own (`display: contents`); the board look\n\t\t\t turns it into the card grid. -->\n\t\t<div class=\"cn-settings-page__sections\">\n\t\t\t<CnSettingsCard\n\t\t\t\tv-for=\"(section, sectionIndex) in activeSections\"\n\t\t\t\t:key=\"`section-${activeTabId || 'flat'}-${sectionIndex}`\"\n\t\t\t\t:title=\"resolveLabel(section.title)\"\n\t\t\t\t:icon=\"section.icon || ''\"\n\t\t\t\t:collapsible=\"section.collapsible || false\">\n\t\t\t\t<!--\n\t\t\t\t\tBody resolution — see `sectionBodyKind(section)` in the\n\t\t\t\t\tscript: returns 'fields' (default + back-compat),\n\t\t\t\t\t'component', or 'widgets'.\n\t\t\t\t-->\n\n\t\t\t\t<!-- Body: bare fields[] (back-compat). Wrapped in a\n\t\t\t\t\t CnSettingsSection mirroring the pre-rich-sections layout. -->\n\t\t\t\t<CnSettingsSection\n\t\t\t\t\tv-if=\"sectionBodyKind(section) === 'fields'\"\n\t\t\t\t\t:name=\"resolveLabel(section.title)\"\n\t\t\t\t\t:description=\"resolveLabel(section.description)\"\n\t\t\t\t\t:docUrl=\"section.docUrl || ''\"\n\t\t\t\t\t:wide=\"Boolean(section.wide)\">\n\t\t\t\t\t<div class=\"cn-settings-page__fields\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tv-for=\"field in section.fields\"\n\t\t\t\t\t\t\t:key=\"field.key\"\n\t\t\t\t\t\t\tclass=\"cn-settings-page__field\">\n\t\t\t\t\t\t\t<!-- Per-field slot — `field-<key>` lets a consumer override the input entirely. -->\n\t\t\t\t\t\t\t<slot\n\t\t\t\t\t\t\t\t:name=\"`field-${field.key}`\"\n\t\t\t\t\t\t\t\t:field=\"field\"\n\t\t\t\t\t\t\t\t:value=\"formData[field.key]\"\n\t\t\t\t\t\t\t\t:onInput=\"(v) => updateField(field.key, v)\">\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\tv-if=\"field.type === 'boolean'\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"!!formData[field.key]\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, $event)\">\n\t\t\t\t\t\t\t\t\t{{ resolveLabel(field.label) }}\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\t\t\tv-else-if=\"field.type === 'number'\"\n\t\t\t\t\t\t\t\t\t:label=\"resolveLabel(field.label)\"\n\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"String(fieldValue(field.key, ''))\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, $event === '' ? null : Number($event))\" />\n\t\t\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\t\t\tv-else-if=\"field.type === 'password'\"\n\t\t\t\t\t\t\t\t\t:label=\"resolveLabel(field.label)\"\n\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"fieldValue(field.key, '')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, $event)\" />\n\t\t\t\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t\t\t\tv-else-if=\"field.type === 'enum' && Array.isArray(field.options)\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"selectedOption(field)\"\n\t\t\t\t\t\t\t\t\t:options=\"field.options\"\n\t\t\t\t\t\t\t\t\t:inputLabel=\"resolveLabel(field.label)\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, optionValue($event))\" />\n\t\t\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t\t:label=\"resolveLabel(field.label)\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"fieldValue(field.key, '')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, $event)\" />\n\t\t\t\t\t\t\t</slot>\n\t\t\t\t\t\t\t<small\n\t\t\t\t\t\t\t\tv-if=\"field.help\"\n\t\t\t\t\t\t\t\tclass=\"cn-settings-page__field-help\">\n\t\t\t\t\t\t\t\t{{ resolveLabel(field.help) }}\n\t\t\t\t\t\t\t</small>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<template v-if=\"sectionSave\" #footer>\n\t\t\t\t\t\t<div class=\"cn-settings-section__save\" data-testid=\"cn-settings-section-save\">\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t\t\t:disabled=\"saving || !dirty\"\n\t\t\t\t\t\t\t\t@click=\"save\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"saving\" :size=\"20\" />\n\t\t\t\t\t\t\t\t\t<ContentSave v-else :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ saveLabel }}\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</template>\n\t\t\t\t</CnSettingsSection>\n\n\t\t\t\t<!-- Body: a single registry-resolved component. The\n\t\t\t\t\t component is responsible for its own chrome — we do\n\t\t\t\t\t NOT wrap it in CnSettingsSection because the existing\n\t\t\t\t\t widget shape (CnVersionInfoCard, CnRegisterMapping)\n\t\t\t\t\t already wraps itself. Custom components are expected\n\t\t\t\t\t to do the same OR opt in by adding their own section\n\t\t\t\t\t wrapper.\n\n\t\t\t\t\t Wrapped in CnSettingsWidgetMount so the child's $emit\n\t\t\t\t\t is intercepted and re-emitted as @widget-event on this\n\t\t\t\t\t page (manifests can't carry inline JS). -->\n\t\t\t\t<CnSettingsWidgetMount\n\t\t\t\t\tv-else-if=\"sectionBodyKind(section) === 'component' && resolveSectionComponent(section)\"\n\t\t\t\t\t:component=\"resolveSectionComponent(section)\"\n\t\t\t\t\t:componentProps=\"section.props || {}\"\n\t\t\t\t\t:widgetType=\"section.component\"\n\t\t\t\t\t:sectionIndex=\"sectionIndex\"\n\t\t\t\t\t:widgetIndex=\"0\"\n\t\t\t\t\t@widgetEvent=\"onWidgetEvent\" />\n\n\t\t\t\t<!-- Body: ordered list of widgets. Each widget is its own\n\t\t\t\t\t mounted component with v-bind props + bubbled events\n\t\t\t\t\t via CnSettingsWidgetMount. Built-ins (version-info,\n\t\t\t\t\t register-mapping) wrap themselves in CnSettingsSection;\n\t\t\t\t\t custom widgets are expected to do the same. -->\n\t\t\t\t<template v-else-if=\"sectionBodyKind(section) === 'widgets'\">\n\t\t\t\t\t<CnSettingsWidgetMount\n\t\t\t\t\t\tv-for=\"entry in resolvedWidgetEntries(section, sectionIndex)\"\n\t\t\t\t\t\t:key=\"entry.key\"\n\t\t\t\t\t\t:component=\"entry.component\"\n\t\t\t\t\t\t:componentProps=\"entry.props\"\n\t\t\t\t\t\t:widgetType=\"entry.widgetType\"\n\t\t\t\t\t\t:sectionIndex=\"sectionIndex\"\n\t\t\t\t\t\t:widgetIndex=\"entry.widgetIndex\"\n\t\t\t\t\t\t@widgetEvent=\"onWidgetEvent\" />\n\t\t\t\t</template>\n\t\t\t</CnSettingsCard>\n\t\t</div>\n\n\t\t<!-- Save bar -->\n\t\t<div v-if=\"showSaveBar && !saveMode && !autosave\" class=\"cn-settings-page__save-bar\">\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"saving || !dirty\"\n\t\t\t\t@click=\"save\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"saving\" :size=\"20\" />\n\t\t\t\t\t<ContentSave v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ saveLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"dirty\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:disabled=\"saving\"\n\t\t\t\t@click=\"reset\">\n\t\t\t\t{{ resetLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Error -->\n\t\t<div v-if=\"lastError\" class=\"cn-settings-page__error\">\n\t\t\t{{ lastError }}\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport {\n\tNcButton,\n\tNcCheckboxRadioSwitch,\n\tNcLoadingIcon,\n\tNcSelect,\n\tNcTextField,\n} from '@nextcloud/vue'\nimport ContentSave from 'vue-material-design-icons/ContentSave.vue'\nimport CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'\nimport CnRegisterMapping from '../CnRegisterMapping/CnRegisterMapping.vue'\nimport CnVersionInfoCard from '../CnVersionInfoCard/CnVersionInfoCard.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { CnPageHeader } from '../CnPageHeader/index.js'\nimport { CnSettingsCard } from '../CnSettingsCard/index.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\nimport CnSettingsWidgetMount from './CnSettingsWidgetMount.js'\n\n/**\n * Sentinel value used in the built-in widget registry to mark the\n * `'component'` discriminator (manifest-settings-orchestration\n * REQ-MSO-6). The discriminator does NOT resolve to a fixed\n * component — instead, the resolver detects this sentinel and looks\n * up `widget.componentName` in the customComponents registry.\n */\nconst COMPONENT_DISCRIMINATOR = Symbol('cn-settings-component-widget')\n\n/**\n * Built-in widget registry. Used by `CnSettingsPage` to resolve\n * `widgets[].type` to a component BEFORE consulting the\n * consumer-provided customComponents registry.\n *\n * The order matters — built-ins win on collision so consumers can't\n * accidentally shadow `version-info` with their own component. If a\n * consumer needs to truly replace one of these, they can render their\n * own component via `section.component` or\n * `{ type: \"component\", componentName: <name> }` instead of `widgets[]`.\n *\n * Spec:\n * - REQ-MSRS-2 (manifest-settings-rich-sections) — fixed-component\n * built-ins (`version-info`, `register-mapping`).\n * - REQ-MSO-6 (manifest-settings-orchestration) — `'component'`\n * discriminator (sentinel value, resolved via componentName).\n */\nconst BUILTIN_SETTINGS_WIDGETS = Object.freeze({\n\t'version-info': CnVersionInfoCard,\n\t'register-mapping': CnRegisterMapping,\n\tcomponent: COMPONENT_DISCRIMINATOR,\n})\n\n/**\n * CnSettingsPage — Manifest-driven settings page.\n *\n * Reads `sections[]` from `pages[].config` and renders one\n * `CnSettingsCard` per section. Each section declares EXACTLY ONE of\n * three body kinds:\n *\n * - `fields[]` — flat form fields (back-compat default).\n * Each field's `type` controls which input renders:\n * - `boolean` → NcCheckboxRadioSwitch\n * - `number` → NcTextField (type=number)\n * - `string` → NcTextField (default)\n * - `password` → NcTextField (type=password)\n * - `enum` → NcSelect (requires `options: string[]`)\n * Per-field `#field-<key>` slots are exposed so consumers can drop\n * in their own widget.\n *\n * - `component` — registry-resolved component as the section body.\n * `section.props` is v-bind'd to it. Useful when a whole section\n * is one bespoke widget the library doesn't know about.\n *\n * - `widgets[]` — ordered list of widgets. Each entry has a `type`\n * string and optional `props`. Built-in widget types resolve\n * first (`version-info` → `CnVersionInfoCard`, `register-mapping`\n * → `CnRegisterMapping`); unknown types fall back to the\n * `customComponents` registry.\n *\n * Widget events (e.g. CnRegisterMapping's `@save`, CnVersionInfoCard's\n * `@update`) bubble up as a single `@widget-event` event on the page,\n * with payload `{ widgetType, widgetIndex, sectionIndex, name, args }`.\n * Consumers wire one handler at the CnAppRoot level and dispatch by\n * `widgetType` / `name` — the manifest can't carry inline JS, so this\n * is the documented event-wiring escape hatch.\n *\n * Saves via `axios.put(saveEndpoint, formData)`. The `saveEndpoint`\n * default is `/index.php/apps/{appId}/api/settings` — consumers should\n * pass a fully-qualified URL via the manifest (or `saveEndpoint` prop)\n * because the library has no knowledge of the consumer's app id at\n * import time.\n *\n * Slots:\n * - `#header` — Replaces the CnPageHeader.\n * - `#actions` — Right-aligned actions area (the renderer fills this\n * via `pages[].actionsComponent`).\n * - `#field-<key>` — Replaces the input for a specific field within\n * a `fields[]` section. Scope: `{ field, value, onInput }`.\n *\n * Events:\n * - `@save` — Emitted on successful save. Payload: the form data.\n * - `@error` — Emitted when save fails. Payload: the error.\n * - `@input` — Emitted on every field change. Payload: `{ key, value }`.\n * - `@widget-event` — Emitted when a widget mounted via `widgets[]`\n * or `component` re-emits one of its own events. Payload:\n * `{ widgetType, widgetIndex, sectionIndex, name, args }`.\n */\nexport default {\n\tname: 'CnSettingsPage',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcLoadingIcon,\n\t\tNcSelect,\n\t\tNcTextField,\n\t\tContentSave,\n\t\tCnBuildiqEditButton,\n\t\tCnSettingsCard,\n\t\tCnSettingsSection,\n\t\tCnPageHeader,\n\t\tCnSettingsWidgetMount,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Custom-component registry injected from CnAppRoot. Used to\n\t\t * resolve `section.component` and to fall back when a\n\t\t * `widgets[].type` isn't in the built-in widget map. Defaults\n\t\t * to an empty object when the page is mounted standalone.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcnCustomComponents: { default: () => ({}) },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the page is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot (or the page's `config.look`) provides.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/app-look/spec.md#requirement-an-app-can-take-the-board-look\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Where the page saves (`config.saveMode`): `section` ends each section\n\t\t * that has fields in its own Save button, `page` draws one Save as the\n\t\t * last header button and a Changes card, and empty keeps the save bar\n\t\t * under the last section. Never both a section and a page save.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-a-settings-page-saves-in-one-declared-place\n\t\t * @type {'section'|'page'|''}\n\t\t */\n\t\tsaveMode: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t\tvalidator: (value) => ['', 'section', 'page'].includes(value),\n\t\t},\n\n\t\t/**\n\t\t * The page saves on change (`config.autosave`): no save button at all,\n\t\t * and the description ends with \"Changes are saved automatically.\"\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-a-settings-page-saves-in-one-declared-place\n\t\t */\n\t\tautosave: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Page title. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Settings'),\n\t\t},\n\n\t\t/** Description shown under the title when `showTitle` is set. */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether to render the inline page header VISIBLY. When false the\n\t\t * `<h1>` is still rendered visually-hidden, so the `<main>` landmark\n\t\t * always has an accessible heading (WCAG 2.4.6 / 1.3.1).\n\t\t */\n\t\tshowTitle: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** MDI icon name for the header. */\n\t\ticon: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Section definitions (flat shape — back-compat). Each section\n\t\t * MUST declare EXACTLY ONE of:\n\t\t * - `fields: Array<Field>` (back-compat flat-field body)\n\t\t * - `component: <registry-name>` + optional `props`\n\t\t * - `widgets: Array<{ type, props?, componentName? }>`\n\t\t *\n\t\t * Common keys: `{ title, description?, icon?, collapsible?, docUrl? }`.\n\t\t *\n\t\t * Mutually exclusive with `tabs[]` (XOR — see\n\t\t * manifest-settings-orchestration REQ-MSO-1).\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\tsections: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Tab definitions (orchestration shape — manifest-settings-\n\t\t * orchestration REQ-MSO-2). When set, CnSettingsPage renders\n\t\t * a tab strip above the section area; the active tab's\n\t\t * `sections[]` flow into the same renderer used by the flat\n\t\t * shape. Mutually exclusive with `sections[]`.\n\t\t *\n\t\t * Each tab MUST be `{ id: string, label: string,\n\t\t * icon?: string, sections: array<Section> }`.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Optional ID of the tab to activate on mount. When empty AND\n\t\t * `tabs[]` is non-empty, the first tab is active by default.\n\t\t * Unknown IDs fall back to the first tab.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tinitialTab: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Initial values keyed by `field.key`. Defaults to an empty\n\t\t * object; in practice the consumer passes the current\n\t\t * IAppConfig snapshot loaded from their settings controller.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tinitialValues: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Endpoint that receives the PUT on save. Pass a fully-qualified\n\t\t * URL — the library has no knowledge of the consumer's app id.\n\t\t * When empty, no PUT is issued and `@save` is emitted with the\n\t\t * form data so the consumer can persist it themselves.\n\t\t */\n\t\tsaveEndpoint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether to render the built-in save/reset bar. */\n\t\tshowSaveBar: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Label for the save button. */\n\t\tsaveLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Save'),\n\t\t},\n\n\t\t/** Label for the reset (discard) button. */\n\t\tresetLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Discard changes'),\n\t\t},\n\n\t\t/**\n\t\t * Optional translation function. When provided, applied to\n\t\t * section titles, field labels, and other i18n-key strings\n\t\t * declared in the manifest. Defaults to the identity function.\n\t\t *\n\t\t * @type {((key: string) => string)|null}\n\t\t */\n\t\ttranslate: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional explicit custom-component registry. When set, takes\n\t\t * precedence over the injected `cnCustomComponents`. Use this\n\t\t * when mounting CnSettingsPage outside a CnAppRoot tree (or\n\t\t * when test-mounting with a stub registry).\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tcustomComponents: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['save', 'error', 'input', 'widget-event', 'tab-change'],\n\n\tsetup(props) {\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tdata() {\n\t\t// Resolve the initial active-tab id synchronously so the very\n\t\t// first render has the correct tab active (otherwise tests\n\t\t// that mount + assert without an `await tick` see the empty\n\t\t// default). Mirrors the logic in `resolveInitialTabId` (the\n\t\t// watcher path); keep them aligned.\n\t\tlet activeTabId = ''\n\t\tconst tabs = Array.isArray(this.tabs) ? this.tabs : []\n\t\tif (tabs.length > 0) {\n\t\t\tif (typeof this.initialTab === 'string' && this.initialTab.length > 0\n\t\t\t\t&& tabs.some((t) => t && t.id === this.initialTab)) {\n\t\t\t\tactiveTabId = this.initialTab\n\t\t\t} else if (tabs[0] && typeof tabs[0].id === 'string') {\n\t\t\t\tactiveTabId = tabs[0].id\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tformData: this.cloneInitial(),\n\t\t\toriginalData: this.cloneInitial(),\n\t\t\tsaving: false,\n\t\t\tlastError: null,\n\t\t\tactiveTabId,\n\t\t\tautosaveTimer: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {boolean} The page saves from its header (`saveMode: \"page\"`, not autosave). */\n\t\tpageSave() {\n\t\t\treturn this.saveMode === 'page' && !this.autosave\n\t\t},\n\n\t\t/** @return {boolean} Each section with fields saves on its own (`saveMode: \"section\"`). */\n\t\tsectionSave() {\n\t\t\treturn this.saveMode === 'section' && !this.autosave\n\t\t},\n\n\t\t/**\n\t\t * The description, with the autosave note appended when the page saves\n\t\t * on change.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedDescription() {\n\t\t\tif (!this.autosave) {\n\t\t\t\treturn this.description\n\t\t\t}\n\t\t\tconst note = t('nextcloud-vue', 'Changes are saved automatically.')\n\t\t\treturn this.description ? `${this.description} ${note}` : note\n\t\t},\n\n\t\t/** @return {boolean} The header buttons render inside the visible page header. */\n\t\theaderButtonsInHeader() {\n\t\t\treturn Boolean(this.title && this.showTitle && !this.$slots.header && (this.isBoard || this.pageSave))\n\t\t},\n\n\t\t/** @return {boolean} The header buttons need a row of their own (header hidden or replaced). */\n\t\theaderButtonsOutside() {\n\t\t\treturn Boolean((this.isBoard || this.pageSave) && !this.headerButtonsInHeader)\n\t\t},\n\n\t\t/** @return {string} Title of the Changes card. */\n\t\tchangesLabel() {\n\t\t\treturn t('nextcloud-vue', 'Changes')\n\t\t},\n\n\t\t/**\n\t\t * The fields that differ from their saved value, across every section,\n\t\t * labelled for the Changes card.\n\t\t *\n\t\t * @return {Array<{key: string, label: string}>}\n\t\t */\n\t\tchangedFields() {\n\t\t\tconst labels = {}\n\t\t\tconst sections = [...(this.sections || [])]\n\t\t\tfor (const tab of this.tabs || []) {\n\t\t\t\tif (tab && Array.isArray(tab.sections)) {\n\t\t\t\t\tsections.push(...tab.sections)\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const section of sections) {\n\t\t\t\tfor (const field of (section && section.fields) || []) {\n\t\t\t\t\tlabels[field.key] = this.resolveLabel(field.label) || field.key\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst keys = new Set([...Object.keys(this.formData), ...Object.keys(this.originalData)])\n\t\t\treturn [...keys]\n\t\t\t\t.filter((key) => JSON.stringify(this.formData[key]) !== JSON.stringify(this.originalData[key]))\n\t\t\t\t.map((key) => ({ key, label: labels[key] || key }))\n\t\t},\n\n\t\t/** Whether any field has changed since load. */\n\t\tdirty() {\n\t\t\treturn JSON.stringify(this.formData) !== JSON.stringify(this.originalData)\n\t\t},\n\n\t\t/**\n\t\t * Effective custom-component registry. Explicit prop wins over\n\t\t * the injected value (mirrors CnPageRenderer's resolution\n\t\t * order).\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\teffectiveCustomComponents() {\n\t\t\treturn this.customComponents ?? this.cnCustomComponents ?? {}\n\t\t},\n\n\t\t/**\n\t\t * Whether the page is in tabs orchestration mode. True when\n\t\t * `tabs[]` is non-empty — drives the tab-strip render gate\n\t\t * (manifest-settings-orchestration REQ-MSO-5).\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasTabs() {\n\t\t\treturn Array.isArray(this.tabs) && this.tabs.length > 0\n\t\t},\n\n\t\t/**\n\t\t * The sections to render right now. In flat mode, this is the\n\t\t * `sections` prop directly. In tabs mode, this is the\n\t\t * `sections[]` array of the currently active tab. Centralising\n\t\t * this in one computed keeps the template's `v-for` simple\n\t\t * and decouples it from the body kind dispatcher (which\n\t\t * applies per-section, not per-mode).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tactiveSections() {\n\t\t\tif (!this.hasTabs) {\n\t\t\t\treturn this.sections || []\n\t\t\t}\n\t\t\tconst active = this.tabs.find((t) => t && t.id === this.activeTabId)\n\t\t\tif (active && Array.isArray(active.sections)) {\n\t\t\t\treturn active.sections\n\t\t\t}\n\t\t\t// Defensive fallback — should not happen because\n\t\t\t// `resolveInitialTabId` always lands on a known tab.\n\t\t\tconst first = this.tabs[0]\n\t\t\treturn first && Array.isArray(first.sections) ? first.sections : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tinitialValues: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.formData = this.cloneInitial()\n\t\t\t\tthis.originalData = this.cloneInitial()\n\t\t\t},\n\t\t},\n\n\t\t// When `tabs[]` changes (e.g. consumer swaps manifests at\n\t\t// runtime), re-resolve the active tab so the page doesn't get\n\t\t// stuck on a removed id.\n\t\ttabs: {\n\t\t\thandler() {\n\t\t\t\tthis.activeTabId = this.resolveInitialTabId()\n\t\t\t},\n\t\t},\n\n\t\t// When `initialTab` changes (consumer-controlled tab\n\t\t// activation), follow it.\n\t\tinitialTab(next) {\n\t\t\tif (typeof next === 'string' && next.length > 0) {\n\t\t\t\tconst exists = this.tabs.some((t) => t && t.id === next)\n\t\t\t\tif (exists) {\n\t\t\t\t\tthis.activeTabId = next\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n\n\tbeforeUnmount() {\n\t\tclearTimeout(this.autosaveTimer)\n\t},\n\n\tmethods: {\n\t\t// Coalesce a field value to a fallback when null / undefined.\n\t\t// Used in template bindings instead of `formData[key] ?? ''` because\n\t\t// vue-template-es2015-compiler (the Rollup VuePlugin's parser) does\n\t\t// not accept ES2020 nullish-coalescing inside template expressions.\n\t\tfieldValue(key, fallback) {\n\t\t\tconst v = this.formData[key]\n\t\t\treturn (v === null || v === undefined) ? fallback : v\n\t\t},\n\n\t\t// Resolve the currently-selected option for an enum field.\n\t\t// `field.options` may be an array of strings/numbers OR an array\n\t\t// of `{ label, value }`-shaped objects. NcSelect needs the actual\n\t\t// option entry (not the bare value) to render the selection\n\t\t// correctly, so this resolver looks up the matching object form\n\t\t// when a primitive value is stored. Returns `null` when nothing\n\t\t// is selected so NcSelect renders the empty state instead of\n\t\t// emitting a Vue warning about an undefined `value` prop.\n\t\tselectedOption(field) {\n\t\t\tconst v = this.formData[field.key]\n\t\t\tif (v === null || v === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (!Array.isArray(field.options)) {\n\t\t\t\treturn v\n\t\t\t}\n\t\t\tfor (const opt of field.options) {\n\t\t\t\tif (opt && typeof opt === 'object') {\n\t\t\t\t\tif (opt.value === v) {\n\t\t\t\t\t\treturn opt\n\t\t\t\t\t}\n\t\t\t\t} else if (opt === v) {\n\t\t\t\t\treturn opt\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn v\n\t\t},\n\n\t\t// Inverse of `selectedOption` — extract the storable value from\n\t\t// whatever NcSelect emits. NcSelect emits the full option entry\n\t\t// when options are objects, the primitive when options are\n\t\t// primitives, or `null` on clear.\n\t\toptionValue(emitted) {\n\t\t\tif (emitted === null || emitted === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof emitted === 'object' && 'value' in emitted) {\n\t\t\t\treturn emitted.value\n\t\t\t}\n\t\t\treturn emitted\n\t\t},\n\n\t\tcloneInitial() {\n\t\t\tconst merged = { ...(this.initialValues || {}) }\n\t\t\t// Collect every section across both modes (flat\n\t\t\t// `sections[]` AND `tabs[].sections[]`) so default values\n\t\t\t// are applied regardless of orchestration shape.\n\t\t\t// Only flat-field sections contribute defaults; component\n\t\t\t// and widgets sections own their own state.\n\t\t\tconst allSections = []\n\t\t\tfor (const section of this.sections || []) {\n\t\t\t\tallSections.push(section)\n\t\t\t}\n\t\t\tfor (const tab of this.tabs || []) {\n\t\t\t\tif (tab && Array.isArray(tab.sections)) {\n\t\t\t\t\tfor (const section of tab.sections) {\n\t\t\t\t\t\tallSections.push(section)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const section of allSections) {\n\t\t\t\tif (!section || !Array.isArray(section.fields)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor (const field of section.fields) {\n\t\t\t\t\tif (field.default !== undefined && merged[field.key] === undefined) {\n\t\t\t\t\t\tmerged[field.key] = field.default\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn merged\n\t\t},\n\n\t\tresolveLabel(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (this.translate) {\n\t\t\t\treturn this.translate(value)\n\t\t\t}\n\t\t\treturn value\n\t\t},\n\n\t\tupdateField(key, value) {\n\t\t\tthis.formData[key] = value\n\t\t\tthis.$emit('input', { key, value })\n\t\t\tif (this.autosave) {\n\t\t\t\tthis.queueAutosave()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Determine which body kind a section declares. Returns\n\t\t * `'fields'` (default + back-compat), `'component'`, or\n\t\t * `'widgets'`. The validator (`validateManifest`) enforces\n\t\t * exactly-one at parse time; this method is the runtime\n\t\t * equivalent and is permissive when one of the keys is set\n\t\t * (last-defined wins in the rare case of an unvalidated\n\t\t * manifest).\n\t\t *\n\t\t * @param {object} section A section entry from `sections[]`.\n\t\t * @return {'fields' | 'component' | 'widgets'}\n\t\t */\n\t\tsectionBodyKind(section) {\n\t\t\tif (Array.isArray(section.widgets) && section.widgets.length > 0) {\n\t\t\t\treturn 'widgets'\n\t\t\t}\n\t\t\tif (typeof section.component === 'string' && section.component.length > 0) {\n\t\t\t\treturn 'component'\n\t\t\t}\n\t\t\treturn 'fields'\n\t\t},\n\n\t\t/**\n\t\t * Resolve a `section.component` registry name to a Vue\n\t\t * component via `effectiveCustomComponents`. Returns `null`\n\t\t * (and warns) when the registry has no entry.\n\t\t *\n\t\t * @param {object} section A section entry.\n\t\t * @return {object|null} Vue component or null.\n\t\t */\n\t\tresolveSectionComponent(section) {\n\t\t\tconst name = section.component\n\t\t\tif (!name) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst resolved = this.effectiveCustomComponents[name]\n\t\t\tif (!resolved) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnSettingsPage] Section component \"${name}\" not found in customComponents registry. Section body will be empty.`)\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn resolved\n\t\t},\n\n\t\t/**\n\t\t * Resolve a single `widgets[]` entry to a concrete Vue\n\t\t * component. Lookup order:\n\t\t *\n\t\t * 1. Built-in widget map (`version-info`, `register-mapping`).\n\t\t * 2. `'component'` discriminator (REQ-MSO-6) — resolves\n\t\t * `widget.componentName` against `effectiveCustomComponents`.\n\t\t * 3. Legacy fallback — looks up `widget.type` against\n\t\t * `effectiveCustomComponents`. Kept for back-compat with\n\t\t * manifest-settings-rich-sections consumers; flagged as\n\t\t * deprecated in JSDoc — manifest authors should migrate to\n\t\t * the explicit `{ type: \"component\", componentName }` shape.\n\t\t *\n\t\t * Returns `null` (and warns) when nothing resolves. Built-ins\n\t\t * win on collision so consumers can't accidentally shadow them.\n\t\t *\n\t\t * @param {object} widget A `widgets[]` entry, e.g. `{ type, props?, componentName? }`.\n\t\t * @return {object|null} Vue component or null.\n\t\t */\n\t\tresolveWidgetComponent(widget) {\n\t\t\tconst type = widget && typeof widget.type === 'string' ? widget.type : ''\n\t\t\tif (!type) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (Object.hasOwn(BUILTIN_SETTINGS_WIDGETS, type)) {\n\t\t\t\tconst builtin = BUILTIN_SETTINGS_WIDGETS[type]\n\t\t\t\tif (builtin === COMPONENT_DISCRIMINATOR) {\n\t\t\t\t\t// REQ-MSO-6: discriminator — look up `componentName`.\n\t\t\t\t\tconst name = widget.componentName\n\t\t\t\t\tif (typeof name !== 'string' || name.length === 0) {\n\t\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\t\tconsole.warn('[CnSettingsPage] Widget {type:\"component\"} requires a non-empty `componentName`. Widget will be skipped.')\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\tconst resolved = this.effectiveCustomComponents[name]\n\t\t\t\t\tif (!resolved) {\n\t\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\t\tconsole.warn(`[CnSettingsPage] Widget component \"${name}\" not found in customComponents registry. Widget will be skipped.`)\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\treturn resolved\n\t\t\t\t}\n\t\t\t\treturn builtin\n\t\t\t}\n\t\t\t// Legacy fallback (manifest-settings-rich-sections REQ-MSRS-2).\n\t\t\t// Deprecated — manifest authors should migrate to\n\t\t\t// `{ type: \"component\", componentName: <X> }`. Kept here so\n\t\t\t// existing consumers continue working unchanged.\n\t\t\tconst resolved = this.effectiveCustomComponents[type]\n\t\t\tif (!resolved) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnSettingsPage] Widget type \"${type}\" not found in built-in widgets or customComponents registry. Widget will be skipped.`)\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn resolved\n\t\t},\n\n\t\t/**\n\t\t * Build the list of widget mount entries for a `widgets[]`\n\t\t * section. Filters out entries whose `widget.type` doesn't\n\t\t * resolve (built-in OR customComponents) — `resolveWidgetComponent`\n\t\t * has already logged a warn. The filter happens here so the\n\t\t * template can use a clean `v-for` without nested `v-if`.\n\t\t *\n\t\t * The `widgetType` carried on the bubbled `@widget-event`\n\t\t * payload is the widget's `componentName` (when the\n\t\t * discriminator is `'component'`) or `widget.type` otherwise —\n\t\t * giving consumers a stable identifier for the dispatch.\n\t\t *\n\t\t * @param {object} section A section entry with `widgets[]`.\n\t\t * @param {number} sectionIndex Index in `sections[]`.\n\t\t * @return {Array<{key: string, component: object, props: object, widgetType: string, widgetIndex: number}>}\n\t\t */\n\t\tresolvedWidgetEntries(section, sectionIndex) {\n\t\t\tconst entries = []\n\t\t\tconst widgets = Array.isArray(section.widgets) ? section.widgets : []\n\t\t\tfor (let widgetIndex = 0; widgetIndex < widgets.length; widgetIndex++) {\n\t\t\t\tconst widget = widgets[widgetIndex] || {}\n\t\t\t\tconst component = this.resolveWidgetComponent(widget)\n\t\t\t\tif (!component) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst widgetType = widget.type === 'component' && typeof widget.componentName === 'string'\n\t\t\t\t\t? widget.componentName\n\t\t\t\t\t: widget.type\n\t\t\t\tentries.push({\n\t\t\t\t\tkey: `widget-${sectionIndex}-${widgetIndex}`,\n\t\t\t\t\tcomponent,\n\t\t\t\t\tprops: widget.props || {},\n\t\t\t\t\twidgetType,\n\t\t\t\t\twidgetIndex,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn entries\n\t\t},\n\n\t\t/**\n\t\t * Resolve the active-tab id on mount / when `tabs[]` changes.\n\t\t * Lookup order: explicit `initialTab` prop → first tab in\n\t\t * `tabs[]` → empty string. Unknown `initialTab` values fall\n\t\t * back to the first tab so the page never gets stuck.\n\t\t * (manifest-settings-orchestration REQ-MSO-5.)\n\t\t *\n\t\t * @return {string} The resolved tab id (empty in flat mode).\n\t\t */\n\t\tresolveInitialTabId() {\n\t\t\tif (!this.hasTabs) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (typeof this.initialTab === 'string' && this.initialTab.length > 0) {\n\t\t\t\tconst exists = this.tabs.some((t) => t && t.id === this.initialTab)\n\t\t\t\tif (exists) {\n\t\t\t\t\treturn this.initialTab\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst first = this.tabs[0]\n\t\t\treturn first && typeof first.id === 'string' ? first.id : ''\n\t\t},\n\n\t\t/**\n\t\t * Handle a tab button click. Switches the active tab and\n\t\t * emits `@tab-change` so consumers can react (e.g. persist the\n\t\t * active tab in their preference store, update the URL hash).\n\t\t * (manifest-settings-orchestration REQ-MSO-5.)\n\t\t *\n\t\t * @param {object} tab The clicked tab definition.\n\t\t * @param {number} tabIndex The tab's index in `tabs[]`.\n\t\t */\n\t\tonTabClick(tab, tabIndex) {\n\t\t\tif (!tab || typeof tab.id !== 'string') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.activeTabId === tab.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.activeTabId = tab.id\n\t\t\tthis.$emit('tab-change', { tabId: tab.id, tabIndex })\n\t\t},\n\n\t\t/**\n\t\t * Re-emit a widget's `widget-event` (caught by the local\n\t\t * CnSettingsWidgetMount helper) as a top-level `widget-event`\n\t\t * on this page. Consumers wire one `@widget-event` handler at\n\t\t * the CnAppRoot mount point and dispatch by `widgetType` /\n\t\t * `name`.\n\t\t *\n\t\t * @param {object} payload `{ widgetType, widgetIndex, sectionIndex, name, args }`\n\t\t */\n\t\tonWidgetEvent(payload) {\n\t\t\tthis.$emit('widget-event', payload)\n\t\t},\n\n\t\t/**\n\t\t * Save shortly after the last change (`autosave`): a burst of typing\n\t\t * is one request.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tqueueAutosave() {\n\t\t\tclearTimeout(this.autosaveTimer)\n\t\t\tthis.autosaveTimer = setTimeout(() => {\n\t\t\t\tthis.autosaveTimer = null\n\t\t\t\tif (this.dirty && !this.saving) {\n\t\t\t\t\tthis.save()\n\t\t\t\t}\n\t\t\t}, 600)\n\t\t},\n\n\t\treset() {\n\t\t\tthis.formData = this.cloneInitial()\n\t\t\tthis.lastError = null\n\t\t},\n\n\t\tasync save() {\n\t\t\tthis.saving = true\n\t\t\tthis.lastError = null\n\t\t\ttry {\n\t\t\t\tif (this.saveEndpoint) {\n\t\t\t\t\tawait axios.put(prefixUrl(this.saveEndpoint), this.formData)\n\t\t\t\t}\n\t\t\t\tthis.originalData = JSON.parse(JSON.stringify(this.formData))\n\t\t\t\tthis.$emit('save', this.formData)\n\t\t\t} catch (err) {\n\t\t\t\tthis.lastError = err?.response?.data?.message || err?.message || t('nextcloud-vue', 'Save failed')\n\t\t\t\tthis.$emit('error', err)\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* The section wrapper draws no box; the board look makes it the card grid. */\n.cn-settings-page__sections {\n\tdisplay: contents;\n}\n\n.cn-settings-page__header-buttons {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tmargin-inline-start: auto;\n}\n\n.cn-settings-page {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-settings-page__actions {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n}\n\n/*\n * Tab strip for the orchestration shape (manifest-settings-\n * orchestration REQ-MSO-5). Uses Nextcloud CSS variables only — no\n * hex literals, no rgba overrides on the elements themselves.\n */\n.cn-settings-page__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding-bottom: 0;\n\tmargin-bottom: 8px;\n}\n\n.cn-settings-page__tab {\n\tbackground: transparent;\n\tborder: 0;\n\tborder-bottom: 3px solid transparent;\n\tpadding: 8px 16px;\n\tmargin: 0;\n\tcursor: pointer;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: normal;\n\tborder-radius: var(--border-radius-large) var(--border-radius-large) 0 0;\n\ttransition: background-color 0.1s ease-in-out, color 0.1s ease-in-out, border-color 0.1s ease-in-out;\n}\n\n.cn-settings-page__tab:hover,\n.cn-settings-page__tab:focus-visible {\n\tbackground-color: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\toutline: none;\n}\n\n.cn-settings-page__tab--active {\n\tcolor: var(--color-primary-element);\n\tborder-bottom-color: var(--color-primary-element);\n\tfont-weight: bold;\n}\n\n@media (max-width: 768px) {\n\t.cn-settings-page__tabs {\n\t\tflex-direction: column;\n\t\tgap: 0;\n\t\tborder-bottom: 0;\n\t}\n\n\t.cn-settings-page__tab {\n\t\tborder-bottom: 1px solid var(--color-border);\n\t\tborder-radius: 0;\n\t\ttext-align: left;\n\t}\n\n\t.cn-settings-page__tab--active {\n\t\tborder-bottom-width: 1px;\n\t\tbackground-color: var(--color-background-hover);\n\t}\n}\n\n.cn-settings-page__fields {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-settings-page__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-settings-page__field-help {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-page__save-bar {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-top: 16px;\n}\n\n.cn-settings-page__error {\n\tcolor: var(--color-error);\n\tbackground: var(--color-error-light, var(--color-background-hover));\n\tpadding: 8px 12px;\n\tborder-radius: var(--border-radius);\n}\n</style>\n"],"names":["CnVersionInfoCard","CnRegisterMapping","CnBuildiqEditButton","CnSettingsCard","CnSettingsSection","CnPageHeader","t","axios"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnSettingsPage.vue2.js","sources":["../../../../src/components/CnSettingsPage/CnSettingsPage.vue"],"sourcesContent":["<!--\n CnSettingsPage — Admin / config surface.\n\n Renders manifest-driven config sections. The page MAY declare\n EITHER a flat `sections[]` array (back-compat) OR a `tabs[]` array\n (each tab owns its own `sections[]`) — XOR, never both. See\n manifest-settings-orchestration spec.\n\n Each section is a CnSettingsCard wrapping a CnSettingsSection.\n A section MUST declare exactly one of three body kinds:\n\n 1. `fields[]` — flat form fields (back-compat, default)\n 2. `component` — registry-resolved component as the section body\n 3. `widgets[]` — ordered list of widgets (built-in + customComponents)\n\n Built-in widget types (resolved BEFORE the customComponents registry):\n - `version-info` → CnVersionInfoCard\n - `register-mapping` → CnRegisterMapping\n - `component` → discriminator; `widget.componentName`\n resolves against customComponents\n\n Saves via `axios.put(saveEndpoint, formData)` with the consumer's\n settings controller URL. Widget events bubble up through\n `@widget-event` so consumers wire one page-level handler that\n dispatches by `widgetType` + event `name` (the manifest can't carry\n inline JS).\n\n Supports the same `headerComponent` / `actionsComponent` / generic\n `slots` overrides that the other built-in page types do — the\n CnPageRenderer wires them via the `#header`, `#actions`, and named\n `slots[]` slots exposed here.\n-->\n<template>\n\t<div class=\"cn-settings-page\" data-testid=\"cn-settings-page\">\n\t\t<!-- Header — overridable via #header slot. CnPageHeader renders whenever\n\t\t there is a title: `visuallyHidden` keeps the <h1> in the\n\t\t accessibility tree (and out of the visual layout) when showTitle is\n\t\t false, so <main> is never left with no heading at all\n\t\t (WCAG 2.4.6 / 1.3.1). -->\n\t\t<slot\n\t\t\tname=\"header\"\n\t\t\t:title=\"title\"\n\t\t\t:description=\"description\"\n\t\t\t:icon=\"icon\">\n\t\t\t<CnPageHeader\n\t\t\t\tv-if=\"title\"\n\t\t\t\t:title=\"title\"\n\t\t\t\t:description=\"resolvedDescription\"\n\t\t\t\t:icon=\"icon\"\n\t\t\t\t:visuallyHidden=\"!showTitle\">\n\t\t\t\t<!-- Board look: the buildiq square, then the page Save as the\n\t\t\t\t last header button. -->\n\t\t\t\t<template v-if=\"headerButtonsInHeader\" #extra>\n\t\t\t\t\t<div class=\"cn-settings-page__header-buttons\" data-testid=\"cn-settings-page-header-buttons\">\n\t\t\t\t\t\t<CnBuildiqEditButton v-if=\"isBoard\" />\n\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\tv-if=\"pageSave\"\n\t\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t\t:disabled=\"saving || !dirty\"\n\t\t\t\t\t\t\tdata-testid=\"cn-settings-page-save\"\n\t\t\t\t\t\t\t@click=\"save\">\n\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"saving\" :size=\"20\" />\n\t\t\t\t\t\t\t\t<ContentSave v-else :size=\"20\" />\n\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t{{ saveLabel }}\n\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t</div>\n\t\t\t\t</template>\n\t\t\t</CnPageHeader>\n\t\t</slot>\n\n\t\t<!-- The same buttons when the header itself is hidden or replaced. -->\n\t\t<div\n\t\t\tv-if=\"headerButtonsOutside\"\n\t\t\tclass=\"cn-settings-page__header-buttons\"\n\t\t\tdata-testid=\"cn-settings-page-header-buttons\">\n\t\t\t<CnBuildiqEditButton v-if=\"isBoard\" />\n\t\t\t<NcButton\n\t\t\t\tv-if=\"pageSave\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"saving || !dirty\"\n\t\t\t\tdata-testid=\"cn-settings-page-save\"\n\t\t\t\t@click=\"save\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"saving\" :size=\"20\" />\n\t\t\t\t\t<ContentSave v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ saveLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- The Changes card of a page that saves in its header. -->\n\t\t<div\n\t\t\tv-if=\"pageSave && changedFields.length > 0\"\n\t\t\tclass=\"cn-settings-page__changes\"\n\t\t\tdata-testid=\"cn-settings-page-changes\">\n\t\t\t<h2 class=\"cn-settings-page__changes-title\">\n\t\t\t\t{{ changesLabel }}\n\t\t\t</h2>\n\t\t\t<ul>\n\t\t\t\t<li v-for=\"field in changedFields\" :key=\"field.key\">\n\t\t\t\t\t{{ field.label }}\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t</div>\n\n\t\t<!-- Actions slot for save / discard / reset overrides -->\n\t\t<div v-if=\"$slots.actions || $slots.actions\" class=\"cn-settings-page__actions\">\n\t\t\t<slot name=\"actions\" />\n\t\t</div>\n\n\t\t<!-- Tab strip — only rendered when `tabs[]` is set\n\t\t\t (manifest-settings-orchestration REQ-MSO-5). Built with\n\t\t\t native <button role=\"tab\"> + ARIA wiring; uses Nextcloud\n\t\t\t CSS variables only (no hex literals). -->\n\t\t<div\n\t\t\tv-if=\"hasTabs\"\n\t\t\tclass=\"cn-settings-page__tabs\"\n\t\t\trole=\"tablist\"\n\t\t\tdata-testid=\"cn-settings-page-tabs\">\n\t\t\t<button\n\t\t\t\tv-for=\"(tab, tabIndex) in tabs\"\n\t\t\t\t:key=\"`tab-${tab.id}`\"\n\t\t\t\trole=\"tab\"\n\t\t\t\ttype=\"button\"\n\t\t\t\tclass=\"cn-settings-page__tab\"\n\t\t\t\t:class=\"{ 'cn-settings-page__tab--active': activeTabId === tab.id }\"\n\t\t\t\t:aria-selected=\"activeTabId === tab.id ? 'true' : 'false'\"\n\t\t\t\t:aria-controls=\"`cn-settings-tab-panel-${tab.id}`\"\n\t\t\t\t:data-testid=\"`cn-settings-page-tab-${tab.id}`\"\n\t\t\t\t@click=\"onTabClick(tab, tabIndex)\">\n\t\t\t\t{{ resolveLabel(tab.label) }}\n\t\t\t</button>\n\t\t</div>\n\n\t\t<!-- Sections — rendered for the active tab when `tabs[]` is\n\t\t\t set, otherwise the flat `sections[]` (back-compat). The wrapper\n\t\t\t draws no box of its own (`display: contents`); the board look\n\t\t\t turns it into the card grid. -->\n\t\t<div class=\"cn-settings-page__sections\">\n\t\t\t<CnSettingsCard\n\t\t\t\tv-for=\"(section, sectionIndex) in activeSections\"\n\t\t\t\t:key=\"`section-${activeTabId || 'flat'}-${sectionIndex}`\"\n\t\t\t\t:title=\"resolveLabel(section.title)\"\n\t\t\t\t:icon=\"section.icon || ''\"\n\t\t\t\t:collapsible=\"section.collapsible || false\">\n\t\t\t\t<!--\n\t\t\t\t\tBody resolution — see `sectionBodyKind(section)` in the\n\t\t\t\t\tscript: returns 'fields' (default + back-compat),\n\t\t\t\t\t'component', or 'widgets'.\n\t\t\t\t-->\n\n\t\t\t\t<!-- Body: bare fields[] (back-compat). Wrapped in a\n\t\t\t\t\t CnSettingsSection mirroring the pre-rich-sections layout. -->\n\t\t\t\t<CnSettingsSection\n\t\t\t\t\tv-if=\"sectionBodyKind(section) === 'fields'\"\n\t\t\t\t\t:name=\"resolveLabel(section.title)\"\n\t\t\t\t\t:description=\"resolveLabel(section.description)\"\n\t\t\t\t\t:docUrl=\"section.docUrl || ''\"\n\t\t\t\t\t:wide=\"Boolean(section.wide)\">\n\t\t\t\t\t<div class=\"cn-settings-page__fields\">\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tv-for=\"field in section.fields\"\n\t\t\t\t\t\t\t:key=\"field.key\"\n\t\t\t\t\t\t\tclass=\"cn-settings-page__field\">\n\t\t\t\t\t\t\t<!-- Per-field slot — `field-<key>` lets a consumer override the input entirely. -->\n\t\t\t\t\t\t\t<slot\n\t\t\t\t\t\t\t\t:name=\"`field-${field.key}`\"\n\t\t\t\t\t\t\t\t:field=\"field\"\n\t\t\t\t\t\t\t\t:value=\"formData[field.key]\"\n\t\t\t\t\t\t\t\t:onInput=\"(v) => updateField(field.key, v)\">\n\t\t\t\t\t\t\t\t<NcCheckboxRadioSwitch\n\t\t\t\t\t\t\t\t\tv-if=\"field.type === 'boolean'\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"!!formData[field.key]\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, $event)\">\n\t\t\t\t\t\t\t\t\t{{ resolveLabel(field.label) }}\n\t\t\t\t\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\t\t\tv-else-if=\"field.type === 'number'\"\n\t\t\t\t\t\t\t\t\t:label=\"resolveLabel(field.label)\"\n\t\t\t\t\t\t\t\t\ttype=\"number\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"String(fieldValue(field.key, ''))\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, $event === '' ? null : Number($event))\" />\n\t\t\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\t\t\tv-else-if=\"field.type === 'password'\"\n\t\t\t\t\t\t\t\t\t:label=\"resolveLabel(field.label)\"\n\t\t\t\t\t\t\t\t\ttype=\"password\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"fieldValue(field.key, '')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, $event)\" />\n\t\t\t\t\t\t\t\t<NcSelect\n\t\t\t\t\t\t\t\t\tv-else-if=\"field.type === 'enum' && Array.isArray(field.options)\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"selectedOption(field)\"\n\t\t\t\t\t\t\t\t\t:options=\"field.options\"\n\t\t\t\t\t\t\t\t\t:inputLabel=\"resolveLabel(field.label)\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, optionValue($event))\" />\n\t\t\t\t\t\t\t\t<NcTextField\n\t\t\t\t\t\t\t\t\tv-else\n\t\t\t\t\t\t\t\t\t:label=\"resolveLabel(field.label)\"\n\t\t\t\t\t\t\t\t\t:modelValue=\"fieldValue(field.key, '')\"\n\t\t\t\t\t\t\t\t\t@update:modelValue=\"updateField(field.key, $event)\" />\n\t\t\t\t\t\t\t</slot>\n\t\t\t\t\t\t\t<small\n\t\t\t\t\t\t\t\tv-if=\"field.help\"\n\t\t\t\t\t\t\t\tclass=\"cn-settings-page__field-help\">\n\t\t\t\t\t\t\t\t{{ resolveLabel(field.help) }}\n\t\t\t\t\t\t\t</small>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<template v-if=\"sectionSave\" #footer>\n\t\t\t\t\t\t<div class=\"cn-settings-section__save\" data-testid=\"cn-settings-section-save\">\n\t\t\t\t\t\t\t<NcButton\n\t\t\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t\t\t:disabled=\"saving || !dirty\"\n\t\t\t\t\t\t\t\t@click=\"save\">\n\t\t\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t\t\t<NcLoadingIcon v-if=\"saving\" :size=\"20\" />\n\t\t\t\t\t\t\t\t\t<ContentSave v-else :size=\"20\" />\n\t\t\t\t\t\t\t\t</template>\n\t\t\t\t\t\t\t\t{{ saveLabel }}\n\t\t\t\t\t\t\t</NcButton>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</template>\n\t\t\t\t</CnSettingsSection>\n\n\t\t\t\t<!-- Body: a single registry-resolved component. The\n\t\t\t\t\t component is responsible for its own chrome — we do\n\t\t\t\t\t NOT wrap it in CnSettingsSection because the existing\n\t\t\t\t\t widget shape (CnVersionInfoCard, CnRegisterMapping)\n\t\t\t\t\t already wraps itself. Custom components are expected\n\t\t\t\t\t to do the same OR opt in by adding their own section\n\t\t\t\t\t wrapper.\n\n\t\t\t\t\t Wrapped in CnSettingsWidgetMount so the child's $emit\n\t\t\t\t\t is intercepted and re-emitted as @widget-event on this\n\t\t\t\t\t page (manifests can't carry inline JS). -->\n\t\t\t\t<CnSettingsWidgetMount\n\t\t\t\t\tv-else-if=\"sectionBodyKind(section) === 'component' && resolveSectionComponent(section)\"\n\t\t\t\t\t:component=\"resolveSectionComponent(section)\"\n\t\t\t\t\t:componentProps=\"section.props || {}\"\n\t\t\t\t\t:widgetType=\"section.component\"\n\t\t\t\t\t:sectionIndex=\"sectionIndex\"\n\t\t\t\t\t:widgetIndex=\"0\"\n\t\t\t\t\t@widgetEvent=\"onWidgetEvent\" />\n\n\t\t\t\t<!-- Body: ordered list of widgets. Each widget is its own\n\t\t\t\t\t mounted component with v-bind props + bubbled events\n\t\t\t\t\t via CnSettingsWidgetMount. Built-ins (version-info,\n\t\t\t\t\t register-mapping) wrap themselves in CnSettingsSection;\n\t\t\t\t\t custom widgets are expected to do the same. -->\n\t\t\t\t<template v-else-if=\"sectionBodyKind(section) === 'widgets'\">\n\t\t\t\t\t<CnSettingsWidgetMount\n\t\t\t\t\t\tv-for=\"entry in resolvedWidgetEntries(section, sectionIndex)\"\n\t\t\t\t\t\t:key=\"entry.key\"\n\t\t\t\t\t\t:component=\"entry.component\"\n\t\t\t\t\t\t:componentProps=\"entry.props\"\n\t\t\t\t\t\t:widgetType=\"entry.widgetType\"\n\t\t\t\t\t\t:sectionIndex=\"sectionIndex\"\n\t\t\t\t\t\t:widgetIndex=\"entry.widgetIndex\"\n\t\t\t\t\t\t@widgetEvent=\"onWidgetEvent\" />\n\t\t\t\t</template>\n\t\t\t</CnSettingsCard>\n\t\t</div>\n\n\t\t<!-- Save bar -->\n\t\t<div v-if=\"showSaveBar && !saveMode && !autosave\" class=\"cn-settings-page__save-bar\">\n\t\t\t<NcButton\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"saving || !dirty\"\n\t\t\t\t@click=\"save\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcLoadingIcon v-if=\"saving\" :size=\"20\" />\n\t\t\t\t\t<ContentSave v-else :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ saveLabel }}\n\t\t\t</NcButton>\n\t\t\t<NcButton\n\t\t\t\tv-if=\"dirty\"\n\t\t\t\tvariant=\"tertiary\"\n\t\t\t\t:disabled=\"saving\"\n\t\t\t\t@click=\"reset\">\n\t\t\t\t{{ resetLabel }}\n\t\t\t</NcButton>\n\t\t</div>\n\n\t\t<!-- Error -->\n\t\t<div v-if=\"lastError\" class=\"cn-settings-page__error\">\n\t\t\t{{ lastError }}\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport {\n\tNcButton,\n\tNcCheckboxRadioSwitch,\n\tNcLoadingIcon,\n\tNcSelect,\n\tNcTextField,\n} from '@nextcloud/vue'\nimport ContentSave from 'vue-material-design-icons/ContentSave.vue'\nimport CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'\nimport CnRegisterMapping from '../CnRegisterMapping/CnRegisterMapping.vue'\nimport CnToggleTableWidget from '../CnToggleTableWidget/CnToggleTableWidget.vue'\nimport CnVersionInfoCard from '../CnVersionInfoCard/CnVersionInfoCard.vue'\nimport { useLook } from '../../composables/useLook.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { CnPageHeader } from '../CnPageHeader/index.js'\nimport { CnSettingsCard } from '../CnSettingsCard/index.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\nimport CnSettingsWidgetMount from './CnSettingsWidgetMount.js'\n\n/**\n * Sentinel value used in the built-in widget registry to mark the\n * `'component'` discriminator (manifest-settings-orchestration\n * REQ-MSO-6). The discriminator does NOT resolve to a fixed\n * component — instead, the resolver detects this sentinel and looks\n * up `widget.componentName` in the customComponents registry.\n */\nconst COMPONENT_DISCRIMINATOR = Symbol('cn-settings-component-widget')\n\n/**\n * Built-in widget registry. Used by `CnSettingsPage` to resolve\n * `widgets[].type` to a component BEFORE consulting the\n * consumer-provided customComponents registry.\n *\n * The order matters — built-ins win on collision so consumers can't\n * accidentally shadow `version-info` with their own component. If a\n * consumer needs to truly replace one of these, they can render their\n * own component via `section.component` or\n * `{ type: \"component\", componentName: <name> }` instead of `widgets[]`.\n *\n * Spec:\n * - REQ-MSRS-2 (manifest-settings-rich-sections) — fixed-component\n * built-ins (`version-info`, `register-mapping`).\n * - REQ-MSO-6 (manifest-settings-orchestration) — `'component'`\n * discriminator (sentinel value, resolved via componentName).\n */\nconst BUILTIN_SETTINGS_WIDGETS = Object.freeze({\n\t'version-info': CnVersionInfoCard,\n\t'register-mapping': CnRegisterMapping,\n\t// Rows with a switch: objects (`bind.mode: 'each'`) or a config map (`'map'`).\n\t'toggle-table': CnToggleTableWidget,\n\tcomponent: COMPONENT_DISCRIMINATOR,\n})\n\n/**\n * CnSettingsPage — Manifest-driven settings page.\n *\n * Reads `sections[]` from `pages[].config` and renders one\n * `CnSettingsCard` per section. Each section declares EXACTLY ONE of\n * three body kinds:\n *\n * - `fields[]` — flat form fields (back-compat default).\n * Each field's `type` controls which input renders:\n * - `boolean` → NcCheckboxRadioSwitch\n * - `number` → NcTextField (type=number)\n * - `string` → NcTextField (default)\n * - `password` → NcTextField (type=password)\n * - `enum` → NcSelect (requires `options: string[]`)\n * Per-field `#field-<key>` slots are exposed so consumers can drop\n * in their own widget.\n *\n * - `component` — registry-resolved component as the section body.\n * `section.props` is v-bind'd to it. Useful when a whole section\n * is one bespoke widget the library doesn't know about.\n *\n * - `widgets[]` — ordered list of widgets. Each entry has a `type`\n * string and optional `props`. Built-in widget types resolve\n * first (`version-info` → `CnVersionInfoCard`, `register-mapping`\n * → `CnRegisterMapping`, `toggle-table` → `CnToggleTableWidget`);\n * unknown types fall back to the\n * `customComponents` registry.\n *\n * Widget events (e.g. CnRegisterMapping's `@save`, CnVersionInfoCard's\n * `@update`) bubble up as a single `@widget-event` event on the page,\n * with payload `{ widgetType, widgetIndex, sectionIndex, name, args }`.\n * Consumers wire one handler at the CnAppRoot level and dispatch by\n * `widgetType` / `name` — the manifest can't carry inline JS, so this\n * is the documented event-wiring escape hatch.\n *\n * Saves via `axios.put(saveEndpoint, formData)`. The `saveEndpoint`\n * default is `/index.php/apps/{appId}/api/settings` — consumers should\n * pass a fully-qualified URL via the manifest (or `saveEndpoint` prop)\n * because the library has no knowledge of the consumer's app id at\n * import time.\n *\n * Slots:\n * - `#header` — Replaces the CnPageHeader.\n * - `#actions` — Right-aligned actions area (the renderer fills this\n * via `pages[].actionsComponent`).\n * - `#field-<key>` — Replaces the input for a specific field within\n * a `fields[]` section. Scope: `{ field, value, onInput }`.\n *\n * Events:\n * - `@save` — Emitted on successful save. Payload: the form data.\n * - `@error` — Emitted when save fails. Payload: the error.\n * - `@input` — Emitted on every field change. Payload: `{ key, value }`.\n * - `@widget-event` — Emitted when a widget mounted via `widgets[]`\n * or `component` re-emits one of its own events. Payload:\n * `{ widgetType, widgetIndex, sectionIndex, name, args }`.\n */\nexport default {\n\tname: 'CnSettingsPage',\n\n\tcomponents: {\n\t\tNcButton,\n\t\tNcCheckboxRadioSwitch,\n\t\tNcLoadingIcon,\n\t\tNcSelect,\n\t\tNcTextField,\n\t\tContentSave,\n\t\tCnBuildiqEditButton,\n\t\tCnSettingsCard,\n\t\tCnSettingsSection,\n\t\tCnPageHeader,\n\t\tCnSettingsWidgetMount,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Custom-component registry injected from CnAppRoot. Used to\n\t\t * resolve `section.component` and to fall back when a\n\t\t * `widgets[].type` isn't in the built-in widget map. Defaults\n\t\t * to an empty object when the page is mounted standalone.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tcnCustomComponents: { default: () => ({}) },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The look the page is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot (or the page's `config.look`) provides.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/app-look/spec.md#requirement-an-app-can-take-the-board-look\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Where the page saves (`config.saveMode`): `section` ends each section\n\t\t * that has fields in its own Save button, `page` draws one Save as the\n\t\t * last header button and a Changes card, and empty keeps the save bar\n\t\t * under the last section. Never both a section and a page save.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-a-settings-page-saves-in-one-declared-place\n\t\t * @type {'section'|'page'|''}\n\t\t */\n\t\tsaveMode: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t\tvalidator: (value) => ['', 'section', 'page'].includes(value),\n\t\t},\n\n\t\t/**\n\t\t * The page saves on change (`config.autosave`): no save button at all,\n\t\t * and the description ends with \"Changes are saved automatically.\"\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-a-settings-page-saves-in-one-declared-place\n\t\t */\n\t\tautosave: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Page title. */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Settings'),\n\t\t},\n\n\t\t/** Description shown under the title when `showTitle` is set. */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether to render the inline page header VISIBLY. When false the\n\t\t * `<h1>` is still rendered visually-hidden, so the `<main>` landmark\n\t\t * always has an accessible heading (WCAG 2.4.6 / 1.3.1).\n\t\t */\n\t\tshowTitle: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** MDI icon name for the header. */\n\t\ticon: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Section definitions (flat shape — back-compat). Each section\n\t\t * MUST declare EXACTLY ONE of:\n\t\t * - `fields: Array<Field>` (back-compat flat-field body)\n\t\t * - `component: <registry-name>` + optional `props`\n\t\t * - `widgets: Array<{ type, props?, componentName? }>`\n\t\t *\n\t\t * Common keys: `{ title, description?, icon?, collapsible?, docUrl? }`.\n\t\t *\n\t\t * Mutually exclusive with `tabs[]` (XOR — see\n\t\t * manifest-settings-orchestration REQ-MSO-1).\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\tsections: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Tab definitions (orchestration shape — manifest-settings-\n\t\t * orchestration REQ-MSO-2). When set, CnSettingsPage renders\n\t\t * a tab strip above the section area; the active tab's\n\t\t * `sections[]` flow into the same renderer used by the flat\n\t\t * shape. Mutually exclusive with `sections[]`.\n\t\t *\n\t\t * Each tab MUST be `{ id: string, label: string,\n\t\t * icon?: string, sections: array<Section> }`.\n\t\t *\n\t\t * @type {Array<object>}\n\t\t */\n\t\ttabs: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Optional ID of the tab to activate on mount. When empty AND\n\t\t * `tabs[]` is non-empty, the first tab is active by default.\n\t\t * Unknown IDs fall back to the first tab.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tinitialTab: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Initial values keyed by `field.key`. Defaults to an empty\n\t\t * object; in practice the consumer passes the current\n\t\t * IAppConfig snapshot loaded from their settings controller.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tinitialValues: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Endpoint that receives the PUT on save. Pass a fully-qualified\n\t\t * URL — the library has no knowledge of the consumer's app id.\n\t\t * When empty, no PUT is issued and `@save` is emitted with the\n\t\t * form data so the consumer can persist it themselves.\n\t\t */\n\t\tsaveEndpoint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether to render the built-in save/reset bar. */\n\t\tshowSaveBar: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Label for the save button. */\n\t\tsaveLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Save'),\n\t\t},\n\n\t\t/** Label for the reset (discard) button. */\n\t\tresetLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Discard changes'),\n\t\t},\n\n\t\t/**\n\t\t * Optional translation function. When provided, applied to\n\t\t * section titles, field labels, and other i18n-key strings\n\t\t * declared in the manifest. Defaults to the identity function.\n\t\t *\n\t\t * @type {((key: string) => string)|null}\n\t\t */\n\t\ttranslate: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Optional explicit custom-component registry. When set, takes\n\t\t * precedence over the injected `cnCustomComponents`. Use this\n\t\t * when mounting CnSettingsPage outside a CnAppRoot tree (or\n\t\t * when test-mounting with a stub registry).\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tcustomComponents: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['save', 'error', 'input', 'widget-event', 'tab-change'],\n\n\tsetup(props) {\n\t\tconst { isBoard } = useLook(props)\n\t\treturn { isBoard }\n\t},\n\n\tdata() {\n\t\t// Resolve the initial active-tab id synchronously so the very\n\t\t// first render has the correct tab active (otherwise tests\n\t\t// that mount + assert without an `await tick` see the empty\n\t\t// default). Mirrors the logic in `resolveInitialTabId` (the\n\t\t// watcher path); keep them aligned.\n\t\tlet activeTabId = ''\n\t\tconst tabs = Array.isArray(this.tabs) ? this.tabs : []\n\t\tif (tabs.length > 0) {\n\t\t\tif (typeof this.initialTab === 'string' && this.initialTab.length > 0\n\t\t\t\t&& tabs.some((t) => t && t.id === this.initialTab)) {\n\t\t\t\tactiveTabId = this.initialTab\n\t\t\t} else if (tabs[0] && typeof tabs[0].id === 'string') {\n\t\t\t\tactiveTabId = tabs[0].id\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tformData: this.cloneInitial(),\n\t\t\toriginalData: this.cloneInitial(),\n\t\t\tsaving: false,\n\t\t\tlastError: null,\n\t\t\tactiveTabId,\n\t\t\tautosaveTimer: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {boolean} The page saves from its header (`saveMode: \"page\"`, not autosave). */\n\t\tpageSave() {\n\t\t\treturn this.saveMode === 'page' && !this.autosave\n\t\t},\n\n\t\t/** @return {boolean} Each section with fields saves on its own (`saveMode: \"section\"`). */\n\t\tsectionSave() {\n\t\t\treturn this.saveMode === 'section' && !this.autosave\n\t\t},\n\n\t\t/**\n\t\t * The description, with the autosave note appended when the page saves\n\t\t * on change.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\tresolvedDescription() {\n\t\t\tif (!this.autosave) {\n\t\t\t\treturn this.description\n\t\t\t}\n\t\t\tconst note = t('nextcloud-vue', 'Changes are saved automatically.')\n\t\t\treturn this.description ? `${this.description} ${note}` : note\n\t\t},\n\n\t\t/** @return {boolean} The header buttons render inside the visible page header. */\n\t\theaderButtonsInHeader() {\n\t\t\treturn Boolean(this.title && this.showTitle && !this.$slots.header && (this.isBoard || this.pageSave))\n\t\t},\n\n\t\t/** @return {boolean} The header buttons need a row of their own (header hidden or replaced). */\n\t\theaderButtonsOutside() {\n\t\t\treturn Boolean((this.isBoard || this.pageSave) && !this.headerButtonsInHeader)\n\t\t},\n\n\t\t/** @return {string} Title of the Changes card. */\n\t\tchangesLabel() {\n\t\t\treturn t('nextcloud-vue', 'Changes')\n\t\t},\n\n\t\t/**\n\t\t * The fields that differ from their saved value, across every section,\n\t\t * labelled for the Changes card.\n\t\t *\n\t\t * @return {Array<{key: string, label: string}>}\n\t\t */\n\t\tchangedFields() {\n\t\t\tconst labels = {}\n\t\t\tconst sections = [...(this.sections || [])]\n\t\t\tfor (const tab of this.tabs || []) {\n\t\t\t\tif (tab && Array.isArray(tab.sections)) {\n\t\t\t\t\tsections.push(...tab.sections)\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const section of sections) {\n\t\t\t\tfor (const field of (section && section.fields) || []) {\n\t\t\t\t\tlabels[field.key] = this.resolveLabel(field.label) || field.key\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst keys = new Set([...Object.keys(this.formData), ...Object.keys(this.originalData)])\n\t\t\treturn [...keys]\n\t\t\t\t.filter((key) => JSON.stringify(this.formData[key]) !== JSON.stringify(this.originalData[key]))\n\t\t\t\t.map((key) => ({ key, label: labels[key] || key }))\n\t\t},\n\n\t\t/** Whether any field has changed since load. */\n\t\tdirty() {\n\t\t\treturn JSON.stringify(this.formData) !== JSON.stringify(this.originalData)\n\t\t},\n\n\t\t/**\n\t\t * Effective custom-component registry. Explicit prop wins over\n\t\t * the injected value (mirrors CnPageRenderer's resolution\n\t\t * order).\n\t\t *\n\t\t * @return {object}\n\t\t */\n\t\teffectiveCustomComponents() {\n\t\t\treturn this.customComponents ?? this.cnCustomComponents ?? {}\n\t\t},\n\n\t\t/**\n\t\t * Whether the page is in tabs orchestration mode. True when\n\t\t * `tabs[]` is non-empty — drives the tab-strip render gate\n\t\t * (manifest-settings-orchestration REQ-MSO-5).\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\thasTabs() {\n\t\t\treturn Array.isArray(this.tabs) && this.tabs.length > 0\n\t\t},\n\n\t\t/**\n\t\t * The sections to render right now. In flat mode, this is the\n\t\t * `sections` prop directly. In tabs mode, this is the\n\t\t * `sections[]` array of the currently active tab. Centralising\n\t\t * this in one computed keeps the template's `v-for` simple\n\t\t * and decouples it from the body kind dispatcher (which\n\t\t * applies per-section, not per-mode).\n\t\t *\n\t\t * @return {Array<object>}\n\t\t */\n\t\tactiveSections() {\n\t\t\tif (!this.hasTabs) {\n\t\t\t\treturn this.sections || []\n\t\t\t}\n\t\t\tconst active = this.tabs.find((t) => t && t.id === this.activeTabId)\n\t\t\tif (active && Array.isArray(active.sections)) {\n\t\t\t\treturn active.sections\n\t\t\t}\n\t\t\t// Defensive fallback — should not happen because\n\t\t\t// `resolveInitialTabId` always lands on a known tab.\n\t\t\tconst first = this.tabs[0]\n\t\t\treturn first && Array.isArray(first.sections) ? first.sections : []\n\t\t},\n\t},\n\n\twatch: {\n\t\tinitialValues: {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.formData = this.cloneInitial()\n\t\t\t\tthis.originalData = this.cloneInitial()\n\t\t\t},\n\t\t},\n\n\t\t// When `tabs[]` changes (e.g. consumer swaps manifests at\n\t\t// runtime), re-resolve the active tab so the page doesn't get\n\t\t// stuck on a removed id.\n\t\ttabs: {\n\t\t\thandler() {\n\t\t\t\tthis.activeTabId = this.resolveInitialTabId()\n\t\t\t},\n\t\t},\n\n\t\t// When `initialTab` changes (consumer-controlled tab\n\t\t// activation), follow it.\n\t\tinitialTab(next) {\n\t\t\tif (typeof next === 'string' && next.length > 0) {\n\t\t\t\tconst exists = this.tabs.some((t) => t && t.id === next)\n\t\t\t\tif (exists) {\n\t\t\t\t\tthis.activeTabId = next\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n\n\tbeforeUnmount() {\n\t\tclearTimeout(this.autosaveTimer)\n\t},\n\n\tmethods: {\n\t\t// Coalesce a field value to a fallback when null / undefined.\n\t\t// Used in template bindings instead of `formData[key] ?? ''` because\n\t\t// vue-template-es2015-compiler (the Rollup VuePlugin's parser) does\n\t\t// not accept ES2020 nullish-coalescing inside template expressions.\n\t\tfieldValue(key, fallback) {\n\t\t\tconst v = this.formData[key]\n\t\t\treturn (v === null || v === undefined) ? fallback : v\n\t\t},\n\n\t\t// Resolve the currently-selected option for an enum field.\n\t\t// `field.options` may be an array of strings/numbers OR an array\n\t\t// of `{ label, value }`-shaped objects. NcSelect needs the actual\n\t\t// option entry (not the bare value) to render the selection\n\t\t// correctly, so this resolver looks up the matching object form\n\t\t// when a primitive value is stored. Returns `null` when nothing\n\t\t// is selected so NcSelect renders the empty state instead of\n\t\t// emitting a Vue warning about an undefined `value` prop.\n\t\tselectedOption(field) {\n\t\t\tconst v = this.formData[field.key]\n\t\t\tif (v === null || v === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (!Array.isArray(field.options)) {\n\t\t\t\treturn v\n\t\t\t}\n\t\t\tfor (const opt of field.options) {\n\t\t\t\tif (opt && typeof opt === 'object') {\n\t\t\t\t\tif (opt.value === v) {\n\t\t\t\t\t\treturn opt\n\t\t\t\t\t}\n\t\t\t\t} else if (opt === v) {\n\t\t\t\t\treturn opt\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn v\n\t\t},\n\n\t\t// Inverse of `selectedOption` — extract the storable value from\n\t\t// whatever NcSelect emits. NcSelect emits the full option entry\n\t\t// when options are objects, the primitive when options are\n\t\t// primitives, or `null` on clear.\n\t\toptionValue(emitted) {\n\t\t\tif (emitted === null || emitted === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (typeof emitted === 'object' && 'value' in emitted) {\n\t\t\t\treturn emitted.value\n\t\t\t}\n\t\t\treturn emitted\n\t\t},\n\n\t\tcloneInitial() {\n\t\t\tconst merged = { ...(this.initialValues || {}) }\n\t\t\t// Collect every section across both modes (flat\n\t\t\t// `sections[]` AND `tabs[].sections[]`) so default values\n\t\t\t// are applied regardless of orchestration shape.\n\t\t\t// Only flat-field sections contribute defaults; component\n\t\t\t// and widgets sections own their own state.\n\t\t\tconst allSections = []\n\t\t\tfor (const section of this.sections || []) {\n\t\t\t\tallSections.push(section)\n\t\t\t}\n\t\t\tfor (const tab of this.tabs || []) {\n\t\t\t\tif (tab && Array.isArray(tab.sections)) {\n\t\t\t\t\tfor (const section of tab.sections) {\n\t\t\t\t\t\tallSections.push(section)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const section of allSections) {\n\t\t\t\tif (!section || !Array.isArray(section.fields)) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tfor (const field of section.fields) {\n\t\t\t\t\tif (field.default !== undefined && merged[field.key] === undefined) {\n\t\t\t\t\t\tmerged[field.key] = field.default\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn merged\n\t\t},\n\n\t\tresolveLabel(value) {\n\t\t\tif (!value) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (this.translate) {\n\t\t\t\treturn this.translate(value)\n\t\t\t}\n\t\t\treturn value\n\t\t},\n\n\t\tupdateField(key, value) {\n\t\t\tthis.formData[key] = value\n\t\t\tthis.$emit('input', { key, value })\n\t\t\tif (this.autosave) {\n\t\t\t\tthis.queueAutosave()\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Determine which body kind a section declares. Returns\n\t\t * `'fields'` (default + back-compat), `'component'`, or\n\t\t * `'widgets'`. The validator (`validateManifest`) enforces\n\t\t * exactly-one at parse time; this method is the runtime\n\t\t * equivalent and is permissive when one of the keys is set\n\t\t * (last-defined wins in the rare case of an unvalidated\n\t\t * manifest).\n\t\t *\n\t\t * @param {object} section A section entry from `sections[]`.\n\t\t * @return {'fields' | 'component' | 'widgets'}\n\t\t */\n\t\tsectionBodyKind(section) {\n\t\t\tif (Array.isArray(section.widgets) && section.widgets.length > 0) {\n\t\t\t\treturn 'widgets'\n\t\t\t}\n\t\t\tif (typeof section.component === 'string' && section.component.length > 0) {\n\t\t\t\treturn 'component'\n\t\t\t}\n\t\t\treturn 'fields'\n\t\t},\n\n\t\t/**\n\t\t * Resolve a `section.component` registry name to a Vue\n\t\t * component via `effectiveCustomComponents`. Returns `null`\n\t\t * (and warns) when the registry has no entry.\n\t\t *\n\t\t * @param {object} section A section entry.\n\t\t * @return {object|null} Vue component or null.\n\t\t */\n\t\tresolveSectionComponent(section) {\n\t\t\tconst name = section.component\n\t\t\tif (!name) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst resolved = this.effectiveCustomComponents[name]\n\t\t\tif (!resolved) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnSettingsPage] Section component \"${name}\" not found in customComponents registry. Section body will be empty.`)\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn resolved\n\t\t},\n\n\t\t/**\n\t\t * Resolve a single `widgets[]` entry to a concrete Vue\n\t\t * component. Lookup order:\n\t\t *\n\t\t * 1. Built-in widget map (`version-info`, `register-mapping`).\n\t\t * 2. `'component'` discriminator (REQ-MSO-6) — resolves\n\t\t * `widget.componentName` against `effectiveCustomComponents`.\n\t\t * 3. Legacy fallback — looks up `widget.type` against\n\t\t * `effectiveCustomComponents`. Kept for back-compat with\n\t\t * manifest-settings-rich-sections consumers; flagged as\n\t\t * deprecated in JSDoc — manifest authors should migrate to\n\t\t * the explicit `{ type: \"component\", componentName }` shape.\n\t\t *\n\t\t * Returns `null` (and warns) when nothing resolves. Built-ins\n\t\t * win on collision so consumers can't accidentally shadow them.\n\t\t *\n\t\t * @param {object} widget A `widgets[]` entry, e.g. `{ type, props?, componentName? }`.\n\t\t * @return {object|null} Vue component or null.\n\t\t */\n\t\tresolveWidgetComponent(widget) {\n\t\t\tconst type = widget && typeof widget.type === 'string' ? widget.type : ''\n\t\t\tif (!type) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tif (Object.hasOwn(BUILTIN_SETTINGS_WIDGETS, type)) {\n\t\t\t\tconst builtin = BUILTIN_SETTINGS_WIDGETS[type]\n\t\t\t\tif (builtin === COMPONENT_DISCRIMINATOR) {\n\t\t\t\t\t// REQ-MSO-6: discriminator — look up `componentName`.\n\t\t\t\t\tconst name = widget.componentName\n\t\t\t\t\tif (typeof name !== 'string' || name.length === 0) {\n\t\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\t\tconsole.warn('[CnSettingsPage] Widget {type:\"component\"} requires a non-empty `componentName`. Widget will be skipped.')\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\tconst resolved = this.effectiveCustomComponents[name]\n\t\t\t\t\tif (!resolved) {\n\t\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\t\tconsole.warn(`[CnSettingsPage] Widget component \"${name}\" not found in customComponents registry. Widget will be skipped.`)\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\treturn resolved\n\t\t\t\t}\n\t\t\t\treturn builtin\n\t\t\t}\n\t\t\t// Legacy fallback (manifest-settings-rich-sections REQ-MSRS-2).\n\t\t\t// Deprecated — manifest authors should migrate to\n\t\t\t// `{ type: \"component\", componentName: <X> }`. Kept here so\n\t\t\t// existing consumers continue working unchanged.\n\t\t\tconst resolved = this.effectiveCustomComponents[type]\n\t\t\tif (!resolved) {\n\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\tconsole.warn(`[CnSettingsPage] Widget type \"${type}\" not found in built-in widgets or customComponents registry. Widget will be skipped.`)\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn resolved\n\t\t},\n\n\t\t/**\n\t\t * Build the list of widget mount entries for a `widgets[]`\n\t\t * section. Filters out entries whose `widget.type` doesn't\n\t\t * resolve (built-in OR customComponents) — `resolveWidgetComponent`\n\t\t * has already logged a warn. The filter happens here so the\n\t\t * template can use a clean `v-for` without nested `v-if`.\n\t\t *\n\t\t * The `widgetType` carried on the bubbled `@widget-event`\n\t\t * payload is the widget's `componentName` (when the\n\t\t * discriminator is `'component'`) or `widget.type` otherwise —\n\t\t * giving consumers a stable identifier for the dispatch.\n\t\t *\n\t\t * @param {object} section A section entry with `widgets[]`.\n\t\t * @param {number} sectionIndex Index in `sections[]`.\n\t\t * @return {Array<{key: string, component: object, props: object, widgetType: string, widgetIndex: number}>}\n\t\t */\n\t\tresolvedWidgetEntries(section, sectionIndex) {\n\t\t\tconst entries = []\n\t\t\tconst widgets = Array.isArray(section.widgets) ? section.widgets : []\n\t\t\tfor (let widgetIndex = 0; widgetIndex < widgets.length; widgetIndex++) {\n\t\t\t\tconst widget = widgets[widgetIndex] || {}\n\t\t\t\tconst component = this.resolveWidgetComponent(widget)\n\t\t\t\tif (!component) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst widgetType = widget.type === 'component' && typeof widget.componentName === 'string'\n\t\t\t\t\t? widget.componentName\n\t\t\t\t\t: widget.type\n\t\t\t\tentries.push({\n\t\t\t\t\tkey: `widget-${sectionIndex}-${widgetIndex}`,\n\t\t\t\t\tcomponent,\n\t\t\t\t\tprops: widget.props || {},\n\t\t\t\t\twidgetType,\n\t\t\t\t\twidgetIndex,\n\t\t\t\t})\n\t\t\t}\n\t\t\treturn entries\n\t\t},\n\n\t\t/**\n\t\t * Resolve the active-tab id on mount / when `tabs[]` changes.\n\t\t * Lookup order: explicit `initialTab` prop → first tab in\n\t\t * `tabs[]` → empty string. Unknown `initialTab` values fall\n\t\t * back to the first tab so the page never gets stuck.\n\t\t * (manifest-settings-orchestration REQ-MSO-5.)\n\t\t *\n\t\t * @return {string} The resolved tab id (empty in flat mode).\n\t\t */\n\t\tresolveInitialTabId() {\n\t\t\tif (!this.hasTabs) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (typeof this.initialTab === 'string' && this.initialTab.length > 0) {\n\t\t\t\tconst exists = this.tabs.some((t) => t && t.id === this.initialTab)\n\t\t\t\tif (exists) {\n\t\t\t\t\treturn this.initialTab\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst first = this.tabs[0]\n\t\t\treturn first && typeof first.id === 'string' ? first.id : ''\n\t\t},\n\n\t\t/**\n\t\t * Handle a tab button click. Switches the active tab and\n\t\t * emits `@tab-change` so consumers can react (e.g. persist the\n\t\t * active tab in their preference store, update the URL hash).\n\t\t * (manifest-settings-orchestration REQ-MSO-5.)\n\t\t *\n\t\t * @param {object} tab The clicked tab definition.\n\t\t * @param {number} tabIndex The tab's index in `tabs[]`.\n\t\t */\n\t\tonTabClick(tab, tabIndex) {\n\t\t\tif (!tab || typeof tab.id !== 'string') {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tif (this.activeTabId === tab.id) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.activeTabId = tab.id\n\t\t\tthis.$emit('tab-change', { tabId: tab.id, tabIndex })\n\t\t},\n\n\t\t/**\n\t\t * Re-emit a widget's `widget-event` (caught by the local\n\t\t * CnSettingsWidgetMount helper) as a top-level `widget-event`\n\t\t * on this page. Consumers wire one `@widget-event` handler at\n\t\t * the CnAppRoot mount point and dispatch by `widgetType` /\n\t\t * `name`.\n\t\t *\n\t\t * @param {object} payload `{ widgetType, widgetIndex, sectionIndex, name, args }`\n\t\t */\n\t\tonWidgetEvent(payload) {\n\t\t\tthis.$emit('widget-event', payload)\n\t\t},\n\n\t\t/**\n\t\t * Save shortly after the last change (`autosave`): a burst of typing\n\t\t * is one request.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tqueueAutosave() {\n\t\t\tclearTimeout(this.autosaveTimer)\n\t\t\tthis.autosaveTimer = setTimeout(() => {\n\t\t\t\tthis.autosaveTimer = null\n\t\t\t\tif (this.dirty && !this.saving) {\n\t\t\t\t\tthis.save()\n\t\t\t\t}\n\t\t\t}, 600)\n\t\t},\n\n\t\treset() {\n\t\t\tthis.formData = this.cloneInitial()\n\t\t\tthis.lastError = null\n\t\t},\n\n\t\tasync save() {\n\t\t\tthis.saving = true\n\t\t\tthis.lastError = null\n\t\t\ttry {\n\t\t\t\tif (this.saveEndpoint) {\n\t\t\t\t\tawait axios.put(prefixUrl(this.saveEndpoint), this.formData)\n\t\t\t\t}\n\t\t\t\tthis.originalData = JSON.parse(JSON.stringify(this.formData))\n\t\t\t\tthis.$emit('save', this.formData)\n\t\t\t} catch (err) {\n\t\t\t\tthis.lastError = err?.response?.data?.message || err?.message || t('nextcloud-vue', 'Save failed')\n\t\t\t\tthis.$emit('error', err)\n\t\t\t} finally {\n\t\t\t\tthis.saving = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n/* The section wrapper draws no box; the board look makes it the card grid. */\n.cn-settings-page__sections {\n\tdisplay: contents;\n}\n\n.cn-settings-page__header-buttons {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tmargin-inline-start: auto;\n}\n\n.cn-settings-page {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-settings-page__actions {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n}\n\n/*\n * Tab strip for the orchestration shape (manifest-settings-\n * orchestration REQ-MSO-5). Uses Nextcloud CSS variables only — no\n * hex literals, no rgba overrides on the elements themselves.\n */\n.cn-settings-page__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n\tborder-bottom: 1px solid var(--color-border);\n\tpadding-bottom: 0;\n\tmargin-bottom: 8px;\n}\n\n.cn-settings-page__tab {\n\tbackground: transparent;\n\tborder: 0;\n\tborder-bottom: 3px solid transparent;\n\tpadding: 8px 16px;\n\tmargin: 0;\n\tcursor: pointer;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: normal;\n\tborder-radius: var(--border-radius-large) var(--border-radius-large) 0 0;\n\ttransition: background-color 0.1s ease-in-out, color 0.1s ease-in-out, border-color 0.1s ease-in-out;\n}\n\n.cn-settings-page__tab:hover,\n.cn-settings-page__tab:focus-visible {\n\tbackground-color: var(--color-background-hover);\n\tcolor: var(--color-main-text);\n\toutline: none;\n}\n\n.cn-settings-page__tab--active {\n\tcolor: var(--color-primary-element);\n\tborder-bottom-color: var(--color-primary-element);\n\tfont-weight: bold;\n}\n\n@media (max-width: 768px) {\n\t.cn-settings-page__tabs {\n\t\tflex-direction: column;\n\t\tgap: 0;\n\t\tborder-bottom: 0;\n\t}\n\n\t.cn-settings-page__tab {\n\t\tborder-bottom: 1px solid var(--color-border);\n\t\tborder-radius: 0;\n\t\ttext-align: left;\n\t}\n\n\t.cn-settings-page__tab--active {\n\t\tborder-bottom-width: 1px;\n\t\tbackground-color: var(--color-background-hover);\n\t}\n}\n\n.cn-settings-page__fields {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n}\n\n.cn-settings-page__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-settings-page__field-help {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-page__save-bar {\n\tdisplay: flex;\n\tgap: 8px;\n\tmargin-top: 16px;\n}\n\n.cn-settings-page__error {\n\tcolor: var(--color-error);\n\tbackground: var(--color-error-light, var(--color-background-hover));\n\tpadding: 8px 12px;\n\tborder-radius: var(--border-radius);\n}\n</style>\n"],"names":["CnVersionInfoCard","CnRegisterMapping","CnToggleTableWidget","CnBuildiqEditButton","CnSettingsCard","CnSettingsSection","CnPageHeader","t","axios"],"mappings":";;;;;;;;;;;;;;;AA0TA;;;;;;;AAOA,MAAM,uBAAsB,GAAI,MAAM,CAAC,8BAA8B,EAAA;;AAErE;;;AAGC;AACA;;;;AAIA;AACA;AACA;;;AAGA;;;;AAID,MAAM,wBAAyB,GAAE,MAAM,CAAC,MAAM,CAAC;AAC9C,CAAA,cAAc,EAAEA,YAAiB;AACjC,CAAA,kBAAkB,EAAEC,YAAiB;AACrC;AACA,CAAA,cAAc,EAAEC,YAAmB;AACnC,CAAA,SAAS,EAAE,uBAAuB;AACnC,CAAC,EAAA;;AAED;AACC;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;;;;;;;AAOA;AACA;;;;;AAKA;AACA;;AAEA;;;;AAIA;AACA;AACA;;AAEA;;;AAGA;AACA;;;;;;;;AAQD,aAAe;AACd,CAAA,IAAI,EAAE,gBAAgB;;CAEtB,UAAU,EAAE;AACX,EAAA,QAAQ;AACR,EAAA,qBAAqB;EACrB,aAAa;AACb,EAAA,QAAQ;EACR,WAAW;EACX,WAAW;AACX,uBAAAC,UAAmB;AACnB,kBAAAC,YAAc;AACd,qBAAAC,YAAiB;gBACjBC,YAAY;AACZ,EAAA,qBAAqB;EACrB;;AAED,CAAA,MAAM,EAAE;AACP;;AAEC;;;AAGA;;;AAGD,EAAA,kBAAkB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG;EAC3C;;AAED,CAAA,KAAK,EAAE;AACN;;;AAGC;;;EAGD,IAAI,EAAE;GACL,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;;AAKC;AACA;;;AAGD,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX,SAAS,EAAE,CAAC,KAAK,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;GAC7D;;AAED;;;AAGC;AACA;;AAED,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;AAED;AACA,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,MAAMC,SAAC,CAAC,eAAe,EAAE,UAAU,CAAC;GAC7C;;;EAGD,WAAW,EAAE;GACZ,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;;EAKA,SAAS,EAAE;GACV,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,KAAK;GACd;;;EAGD,IAAI,EAAE;GACL,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;;;AAIC;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAED,EAAA,QAAQ,EAAE;GACT,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;;;AAGC;;AAEA;AACA;AACA;AACA;AACA;AACA;;EAED,IAAI,EAAE;GACL,IAAI,EAAE,KAAK;AACX,GAAA,OAAO,EAAE,MAAM,EAAE;GACjB;;AAED;;;AAGC;AACA;;;EAGD,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;;AAEC;;AAEA;;;AAGD,EAAA,aAAa,EAAE;GACd,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,OAAO,EAAE,CAAC;GACnB;;AAED;;;;AAIC;;EAED,YAAY,EAAE;GACb,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;AAED;EACA,WAAW,EAAE;GACZ,IAAI,EAAE,OAAO;GACb,OAAO,EAAE,IAAI;GACb;;;EAGD,SAAS,EAAE;GACV,IAAI,EAAE,MAAM;AACZ,GAAA,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,MAAM,CAAC;GACzC;;AAED;EACA,UAAU,EAAE;GACX,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,MAAMA,SAAC,CAAC,eAAe,EAAE,iBAAiB,CAAC;GACpD;;AAED;;;;AAIC;AACA;;EAED,SAAS,EAAE;GACV,IAAI,EAAE,QAAQ;GACd,OAAO,EAAE,IAAI;GACb;;AAED;;;;AAIC;AACA;AACA;;AAED,EAAA,gBAAgB,EAAE;GACjB,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,IAAI;GACb;EACD;;CAED,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,YAAY,CAAC;;CAE/D,KAAK,CAAC,KAAK,EAAE;EACZ,MAAM,EAAE,OAAQ,EAAA,GAAI,OAAO,CAAC,KAAK,EAAA;AACjC,EAAA,OAAO,EAAE,OAAQ,EAAA;EACjB;;AAED,CAAA,IAAI,GAAG;;;;;AAKN;AACA,EAAA,IAAI,WAAU,GAAI,GAAC;EACnB,MAAM,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAE,GAAE,IAAI,CAAC,IAAG,GAAI,GAAC;AACrD,EAAA,IAAI,IAAI,CAAC,MAAO,GAAE,CAAC,EAAE;GACpB,IAAI,OAAO,IAAI,CAAC,UAAS,KAAM,QAAO,IAAK,IAAI,CAAC,UAAU,CAAC,MAAK,GAAI,CAAA;AACnE,OAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAE,IAAG,CAAC,CAAC,EAAC,KAAM,IAAI,CAAC,UAAU,CAAC,EAAE;IACpD,WAAU,GAAI,IAAI,CAAC,WAAS;AAC7B,IAAA,MAAO,IAAI,IAAI,CAAC,CAAC,CAAE,IAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,EAAG,KAAI,QAAQ,EAAE;AACrD,IAAA,cAAc,IAAI,CAAC,CAAC,CAAC,CAAC,GAAC;AACxB,IAAA;AACD,GAAA;AACA,EAAA,OAAO;GACN,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE;AAC7B,GAAA,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE;GACjC,MAAM,EAAE,KAAK;AACb,GAAA,SAAS,EAAE,IAAI;GACf,WAAW;AACX,GAAA,aAAa,EAAE,IAAI;AACpB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT;EACA,QAAQ,GAAG;AACV,GAAA,OAAO,IAAI,CAAC,aAAa,MAAO,IAAG,CAAC,IAAI,CAAC,QAAO;GAChD;;AAED;EACA,WAAW,GAAG;GACb,OAAO,IAAI,CAAC,QAAS,KAAI,SAAU,IAAG,CAAC,IAAI,CAAC,QAAO;GACnD;;AAED;;AAEC;AACA;AACA;;AAED,EAAA,mBAAmB,GAAG;AACrB,GAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AACnB,IAAA,OAAO,IAAI,CAAC,WAAU;AACvB,IAAA;GACA,MAAM,IAAK,GAAEA,SAAC,CAAC,eAAe,EAAE,kCAAkC,EAAA;GAClE,OAAO,IAAI,CAAC,WAAY,GAAE,CAAC,EAAE,IAAI,CAAC,WAAW,CAAE,CAAA,EAAE,IAAI,CAAC,CAAE,GAAE,IAAG;GAC7D;;AAED;EACA,qBAAqB,GAAG;AACvB,GAAA,OAAO,OAAO,CAAC,IAAI,CAAC,KAAM,IAAG,IAAI,CAAC,SAAQ,IAAK,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ,CAAC,CAAA;GACrG;;AAED;EACA,oBAAoB,GAAG;AACtB,GAAA,OAAO,OAAO,CAAC,CAAC,IAAI,CAAC,OAAQ,IAAG,IAAI,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAA;GAC7E;;AAED;AACA,EAAA,YAAY,GAAG;AACd,GAAA,OAAOA,SAAC,CAAC,eAAe,EAAE,SAAS,CAAA;GACnC;;AAED;;;AAGC;AACA;;AAED,EAAA,aAAa,GAAG;GACf,MAAM,MAAO,GAAE,GAAC;AAChB,GAAA,MAAM,QAAO,GAAI,CAAC,IAAI,IAAI,CAAC,QAAS,IAAG,EAAE,CAAC,EAAA;GAC1C,KAAK,MAAM,GAAE,IAAK,IAAI,CAAC,IAAG,IAAK,EAAE,EAAE;AAClC,IAAA,IAAI,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;KACvC,QAAQ,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,QAAQ,EAAA;AAC9B,KAAA;AACD,IAAA;GACA,KAAK,MAAM,OAAM,IAAK,QAAQ,EAAE;IAC/B,KAAK,MAAM,KAAI,IAAK,CAAC,WAAW,OAAO,CAAC,MAAM,KAAK,EAAE,EAAE;KACtD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAA,GAAI,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAE,IAAG,KAAK,CAAC,IAAE;AAC/D,KAAA;AACD,IAAA;AACA,GAAA,MAAM,IAAG,GAAI,IAAI,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAA;AACvF,GAAA,OAAO,CAAC,GAAG,IAAI,CAAA;AACd,KAAC,MAAM,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAE,KAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;AAC9F,KAAC,GAAG,CAAC,CAAC,GAAG,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK,GAAE,EAAG,CAAC,CAAA;GACnD;;AAED;AACA,EAAA,KAAK,GAAG;AACP,GAAA,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAA,KAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAA;GACzE;;AAED;;;AAGC;AACA;AACA;;EAED,yBAAyB,GAAG;GAC3B,OAAO,IAAI,CAAC,gBAAe,IAAK,IAAI,CAAC,kBAAiB,IAAK,EAAC;GAC5D;;AAED;;;AAGC;AACA;AACA;;AAED,EAAA,OAAO,GAAG;GACT,OAAO,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA,IAAK,IAAI,CAAC,IAAI,CAAC,MAAK,GAAI,CAAA;GACtD;;AAED;;AAEC;;;AAGA;AACA;AACA;;;AAGD,EAAA,cAAc,GAAG;AAChB,GAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;IAClB,OAAO,IAAI,CAAC,QAAS,IAAG,EAAC;AAC1B,IAAA;GACA,MAAM,MAAO,GAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAE,IAAG,CAAC,CAAC,EAAG,KAAI,IAAI,CAAC,WAAW,EAAA;AACnE,GAAA,IAAI,MAAO,IAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAC7C,IAAA,OAAO,MAAM,CAAC,QAAO;AACtB,IAAA;AACA;AACA;GACA,MAAM,KAAM,GAAE,IAAI,CAAC,IAAI,CAAC,CAAC,EAAA;GACzB,OAAO,KAAM,IAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAA,GAAI,KAAK,CAAC,QAAS,GAAE,EAAC;GAClE;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,aAAa,EAAE;AACd,GAAA,IAAI,EAAE,IAAI;AACV,GAAA,OAAO,GAAG;AACT,IAAA,IAAI,CAAC,QAAO,GAAI,IAAI,CAAC,YAAY,GAAC;AAClC,IAAA,IAAI,CAAC,YAAa,GAAE,IAAI,CAAC,YAAY,GAAC;IACtC;GACD;;;;AAID;EACA,IAAI,EAAE;AACL,GAAA,OAAO,GAAG;AACT,IAAA,IAAI,CAAC,cAAc,IAAI,CAAC,mBAAmB,GAAC;IAC5C;GACD;;;;AAID,EAAA,UAAU,CAAC,IAAI,EAAE;AAChB,GAAA,IAAI,OAAO,IAAK,KAAI,QAAS,IAAG,IAAI,CAAC,MAAO,GAAE,CAAC,EAAE;IAChD,MAAM,MAAK,GAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,IAAI,EAAA;IACvD,IAAI,MAAM,EAAE;AACX,KAAA,IAAI,CAAC,cAAc,KAAG;AACvB,KAAA;AACD,IAAA;GACA;EACD;;AAED,CAAA,aAAa,GAAG;AACf,EAAA,YAAY,CAAC,IAAI,CAAC,aAAa,EAAA;EAC/B;;AAED,CAAA,OAAO,EAAE;;;;;EAKR,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE;GACzB,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAA;AAC3B,GAAA,OAAO,CAAC,CAAE,KAAI,QAAQ,MAAM,SAAS,IAAI,WAAW,CAAA;GACpD;;;;;;;;;;AAUD,EAAA,cAAc,CAAC,KAAK,EAAE;AACrB,GAAA,MAAM,CAAE,GAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAA;GACjC,IAAI,CAAA,KAAM,IAAG,IAAK,MAAM,SAAS,EAAE;AAClC,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;AAClC,IAAA,OAAO,CAAA;AACR,IAAA;GACA,KAAK,MAAM,GAAE,IAAK,KAAK,CAAC,OAAO,EAAE;IAChC,IAAI,GAAE,IAAK,OAAO,GAAI,KAAI,QAAQ,EAAE;AACnC,KAAA,IAAI,GAAG,CAAC,KAAM,KAAI,CAAC,EAAE;AACpB,MAAA,OAAO,GAAE;AACV,MAAA;AACD,KAAA,MAAO,IAAI,GAAI,KAAI,CAAC,EAAE;AACrB,KAAA,OAAO,GAAE;AACV,KAAA;AACD,IAAA;AACA,GAAA,OAAO,CAAA;GACP;;;;;;AAMD,EAAA,WAAW,CAAC,OAAO,EAAE;AACpB,GAAA,IAAI,OAAQ,KAAI,QAAQ,OAAM,KAAM,SAAS,EAAE;AAC9C,IAAA,OAAO,IAAG;AACX,IAAA;GACA,IAAI,OAAO,OAAQ,KAAI,YAAY,WAAW,OAAO,EAAE;AACtD,IAAA,OAAO,OAAO,CAAC,KAAI;AACpB,IAAA;GACA,OAAO,OAAM;GACb;;AAED,EAAA,YAAY,GAAG;AACd,GAAA,MAAM,MAAK,GAAI,EAAE,IAAI,IAAI,CAAC,aAAY,IAAK,EAAE,CAAE,GAAA;AAC/C;;AAEA;;AAEA;AACA,GAAA,MAAM,WAAU,GAAI,GAAC;AACrB,GAAA,KAAK,MAAM,WAAW,IAAI,CAAC,QAAS,IAAG,EAAE,EAAE;IAC1C,WAAW,CAAC,IAAI,CAAC,OAAO,EAAA;AACzB,IAAA;GACA,KAAK,MAAM,GAAE,IAAK,IAAI,CAAC,IAAG,IAAK,EAAE,EAAE;AAClC,IAAA,IAAI,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;AACvC,KAAA,KAAK,MAAM,OAAQ,IAAG,GAAG,CAAC,QAAQ,EAAE;MACnC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAA;AACzB,MAAA;AACD,KAAA;AACD,IAAA;AACA,GAAA,KAAK,MAAM,OAAQ,IAAG,WAAW,EAAE;AAClC,IAAA,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAC/C,KAAA,QAAO;AACR,KAAA;AACA,IAAA,KAAK,MAAM,KAAM,IAAG,OAAO,CAAC,MAAM,EAAE;KACnC,IAAI,KAAK,CAAC,OAAM,KAAM,SAAQ,IAAK,MAAM,CAAC,KAAK,CAAC,GAAG,CAAA,KAAM,SAAS,EAAE;AACnE,MAAA,MAAM,CAAC,KAAK,CAAC,GAAG,CAAA,GAAI,KAAK,CAAC,QAAM;AACjC,MAAA;AACD,KAAA;AACD,IAAA;GACA,OAAO,MAAK;GACZ;;AAED,EAAA,YAAY,CAAC,KAAK,EAAE;GACnB,IAAI,CAAC,KAAK,EAAE;AACX,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,IAAI,IAAI,CAAC,SAAS,EAAE;IACnB,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;AAC5B,IAAA;GACA,OAAO,KAAI;GACX;;EAED,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE;GACvB,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,MAAI;AACzB,GAAA,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,KAAI,EAAG,EAAA;AAClC,GAAA,IAAI,IAAI,CAAC,QAAQ,EAAE;AAClB,IAAA,IAAI,CAAC,aAAa,GAAC;AACpB,IAAA;GACA;;AAED;;;;AAIC;;AAEA;;AAEA;;AAEA;;EAED,eAAe,CAAC,OAAO,EAAE;GACxB,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAA,IAAK,OAAO,CAAC,OAAO,CAAC,MAAK,GAAI,CAAC,EAAE;AACjE,IAAA,OAAO,SAAQ;AAChB,IAAA;AACA,GAAA,IAAI,OAAO,OAAO,CAAC,SAAQ,KAAM,QAAO,IAAK,OAAO,CAAC,SAAS,CAAC,MAAO,GAAE,CAAC,EAAE;AAC1E,IAAA,OAAO,WAAU;AAClB,IAAA;GACA,OAAO,QAAO;GACd;;AAED;AACC;;AAEA;AACA;AACA;AACA;;AAED,EAAA,uBAAuB,CAAC,OAAO,EAAE;GAChC,MAAM,IAAG,GAAI,OAAO,CAAC,UAAQ;AAC7B,GAAA,IAAI,CAAC,IAAI,EAAE;AACV,IAAA,OAAO,IAAG;AACX,IAAA;GACA,MAAM,QAAS,GAAE,IAAI,CAAC,yBAAyB,CAAC,IAAI,EAAA;GACpD,IAAI,CAAC,QAAQ,EAAE;AACd;IACA,OAAO,CAAC,IAAI,CAAC,CAAC,oCAAoC,EAAE,IAAI,CAAC,qEAAqE,CAAC,EAAA;AAC/H,IAAA,OAAO,IAAG;AACX,IAAA;GACA,OAAO,QAAO;GACd;;AAED;AACC;;AAEA;;;;AAIA;;;;;AAKA;;;AAGA;AACA;AACA;;AAED,EAAA,sBAAsB,CAAC,MAAM,EAAE;GAC9B,MAAM,IAAK,GAAE,MAAK,IAAK,OAAO,MAAM,CAAC,IAAG,KAAM,QAAS,GAAE,MAAM,CAAC,IAAK,GAAE,GAAC;AACxE,GAAA,IAAI,CAAC,IAAI,EAAE;AACV,IAAA,OAAO,IAAG;AACX,IAAA;GACA,IAAI,MAAM,CAAC,MAAM,CAAC,wBAAwB,EAAE,IAAI,CAAC,EAAE;AAClD,IAAA,MAAM,OAAM,GAAI,wBAAwB,CAAC,IAAI,EAAA;AAC7C,IAAA,IAAI,OAAM,KAAM,uBAAuB,EAAE;;KAExC,MAAM,IAAK,GAAE,MAAM,CAAC,cAAY;AAChC,KAAA,IAAI,OAAO,SAAS,YAAY,IAAI,CAAC,MAAK,KAAM,CAAC,EAAE;AAClD;MACA,OAAO,CAAC,IAAI,CAAC,0GAA0G,EAAA;AACvH,MAAA,OAAO,IAAG;AACX,MAAA;KACA,MAAM,QAAS,GAAE,IAAI,CAAC,yBAAyB,CAAC,IAAI,EAAA;KACpD,IAAI,CAAC,QAAQ,EAAE;AACd;MACA,OAAO,CAAC,IAAI,CAAC,CAAC,mCAAmC,EAAE,IAAI,CAAC,iEAAiE,CAAC,EAAA;AAC1H,MAAA,OAAO,IAAG;AACX,MAAA;KACA,OAAO,QAAO;AACf,KAAA;IACA,OAAO,OAAM;AACd,IAAA;;AAEA;;AAEA;GACA,MAAM,QAAS,GAAE,IAAI,CAAC,yBAAyB,CAAC,IAAI,EAAA;GACpD,IAAI,CAAC,QAAQ,EAAE;AACd;IACA,OAAO,CAAC,IAAI,CAAC,CAAC,8BAA8B,EAAE,IAAI,CAAC,qFAAqF,CAAC,EAAA;AACzI,IAAA,OAAO,IAAG;AACX,IAAA;GACA,OAAO,QAAO;GACd;;AAED;;;;;;AAMC;;AAEA;;;AAGA;;;;;AAKD,EAAA,qBAAqB,CAAC,OAAO,EAAE,YAAY,EAAE;AAC5C,GAAA,MAAM,OAAQ,GAAE,GAAC;GACjB,MAAM,OAAM,GAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAE,GAAE,OAAO,CAAC,OAAQ,GAAE,GAAC;AACpE,GAAA,KAAK,IAAI,WAAY,GAAE,CAAC,EAAE,WAAY,GAAE,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;AACtE,IAAA,MAAM,MAAO,GAAE,OAAO,CAAC,WAAW,CAAE,IAAG,GAAC;IACxC,MAAM,SAAQ,GAAI,IAAI,CAAC,sBAAsB,CAAC,MAAM,EAAA;AACpD,IAAA,IAAI,CAAC,SAAS,EAAE;AACf,KAAA,QAAO;AACR,KAAA;AACA,IAAA,MAAM,UAAW,GAAE,MAAM,CAAC,SAAS,WAAU,IAAK,OAAO,MAAM,CAAC,aAAY,KAAM,QAAO;AACxF,OAAE,MAAM,CAAC,aAAY;OACnB,MAAM,CAAC,KAAG;IACb,OAAO,CAAC,IAAI,CAAC;AACZ,KAAA,GAAG,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;AAC5C,KAAA,SAAS;KACT,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE;KACzB,UAAU;KACV,WAAW;KACX,EAAA;AACF,IAAA;GACA,OAAO,OAAM;GACb;;AAED;;;;AAIC;AACA;AACA;;;AAGD,EAAA,mBAAmB,GAAG;AACrB,GAAA,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AAClB,IAAA,OAAO,EAAC;AACT,IAAA;AACA,GAAA,IAAI,OAAO,IAAI,CAAC,UAAW,KAAI,QAAO,IAAK,IAAI,CAAC,UAAU,CAAC,MAAK,GAAI,CAAC,EAAE;IACtE,MAAM,MAAK,GAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAA,IAAK,CAAC,CAAC,EAAC,KAAM,IAAI,CAAC,UAAU,EAAA;IAClE,IAAI,MAAM,EAAE;AACX,KAAA,OAAO,IAAI,CAAC,UAAS;AACtB,KAAA;AACD,IAAA;GACA,MAAM,KAAM,GAAE,IAAI,CAAC,IAAI,CAAC,CAAC,EAAA;GACzB,OAAO,KAAI,IAAK,OAAO,KAAK,CAAC,EAAC,KAAM,WAAW,KAAK,CAAC,EAAG,GAAE,EAAC;GAC3D;;AAED;AACC;;;AAGA;AACA;AACA;;;EAGD,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE;AACzB,GAAA,IAAI,CAAC,GAAE,IAAK,OAAO,GAAG,CAAC,EAAG,KAAI,QAAQ,EAAE;IACvC,MAAK;AACN,IAAA;GACA,IAAI,IAAI,CAAC,WAAY,KAAI,GAAG,CAAC,EAAE,EAAE;IAChC,MAAK;AACN,IAAA;GACA,IAAI,CAAC,WAAY,GAAE,GAAG,CAAC,GAAC;GACxB,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,QAAO,EAAG,EAAA;GACpD;;AAED;;;;;AAKC;AACA;AACA;;EAED,aAAa,CAAC,OAAO,EAAE;AACtB,GAAA,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,OAAO,EAAA;GAClC;;AAED;;;AAGC;;;AAGD,EAAA,aAAa,GAAG;AACf,GAAA,YAAY,CAAC,IAAI,CAAC,aAAa,EAAA;AAC/B,GAAA,IAAI,CAAC,aAAc,GAAE,UAAU,CAAC,MAAM;IACrC,IAAI,CAAC,gBAAgB,KAAG;IACxB,IAAI,IAAI,CAAC,KAAM,IAAG,CAAC,IAAI,CAAC,MAAM,EAAE;KAC/B,IAAI,CAAC,IAAI,GAAC;AACX,KAAA;IACA,EAAE,GAAG,EAAA;GACN;;AAED,EAAA,KAAK,GAAG;AACP,GAAA,IAAI,CAAC,QAAO,GAAI,IAAI,CAAC,YAAY,GAAC;AAClC,GAAA,IAAI,CAAC,SAAQ,GAAI,KAAG;GACpB;;EAED,MAAM,IAAI,GAAG;AACZ,GAAA,IAAI,CAAC,MAAK,GAAI,KAAG;AACjB,GAAA,IAAI,CAAC,SAAQ,GAAI,KAAG;AACpB,GAAA,IAAI;AACH,IAAA,IAAI,IAAI,CAAC,YAAY,EAAE;KACtB,MAAMC,cAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAA;AAC5D,KAAA;IACA,IAAI,CAAC,YAAW,GAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAA;AAC5D,IAAA,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAA;IAC/B,CAAA,OAAO,GAAG,EAAE;AACb,IAAA,IAAI,CAAC,SAAU,GAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAQ,IAAG,GAAG,EAAE,OAAQ,IAAGD,SAAC,CAAC,eAAe,EAAE,aAAa,EAAA;IACjG,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAA;AACxB,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,MAAO,GAAE,MAAI;AACnB,IAAA;GACA;EACD;AACF;;;;"}
|