@conduction/nextcloud-vue 2.135.0 → 2.137.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/dist/esm/components/CnActionDialog/CnActionDialog.vue.js +1 -1
  2. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js +2 -1
  3. package/dist/esm/components/CnActionDialog/CnActionDialog.vue2.js.map +1 -1
  4. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js +65 -50
  5. package/dist/esm/components/CnActionDialog/CnActionDialog.vue3.js.map +1 -1
  6. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
  7. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +9 -0
  8. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  9. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +4 -3
  10. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  11. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +4 -1
  12. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  13. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +61 -28
  14. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  15. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
  16. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +6 -0
  17. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  18. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js +9 -1
  19. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  20. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
  21. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
  22. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +4 -11
  23. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +32 -0
  25. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  26. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +34 -26
  27. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  28. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +24 -0
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  30. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +2 -2
  31. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  32. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  33. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  34. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +2 -1
  35. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  36. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +39 -2
  37. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  38. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +6 -5
  39. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  40. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  41. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +11 -0
  42. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  43. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js +10 -2
  44. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  45. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  46. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +18 -0
  47. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  48. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +38 -23
  49. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  50. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
  51. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
  52. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js +1 -0
  53. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
  54. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue.js +1 -1
  55. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue2.js.map +1 -1
  56. package/dist/esm/components/CnRetentionWidget/CnRetentionWidget.vue3.js.map +1 -1
  57. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue.js +1 -1
  58. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js +14 -4
  59. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue2.js.map +1 -1
  60. package/dist/esm/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue3.js.map +1 -1
  61. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue.js +1 -1
  62. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js +10 -0
  63. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue2.js.map +1 -1
  64. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js +29 -13
  65. package/dist/esm/components/CnTimelineWidget/CnTimelineManage.vue3.js.map +1 -1
  66. package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js +3 -1
  67. package/dist/esm/components/CnTimelineWidget/dashboardRegistration.js.map +1 -1
  68. package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue.js +1 -1
  69. package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue2.js.map +1 -1
  70. package/dist/esm/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue3.js.map +1 -1
  71. package/dist/esm/composables/indexSources.js +69 -3
  72. package/dist/esm/composables/indexSources.js.map +1 -1
  73. package/dist/esm/l10n/en.json.js +20 -20
  74. package/dist/esm/l10n/nl.json.js +21 -21
  75. package/dist/esm/library-style.js +1 -1
  76. package/dist/esm/nextcloud-vue.css +580 -324
  77. package/dist/esm/utils/contentHeaderLink.js +7 -1
  78. package/dist/esm/utils/contentHeaderLink.js.map +1 -1
  79. package/dist/esm/utils/savedViewMenu.js +4 -1
  80. package/dist/esm/utils/savedViewMenu.js.map +1 -1
  81. package/dist/esm/utils/savedViewSummary.js +11 -4
  82. package/dist/esm/utils/savedViewSummary.js.map +1 -1
  83. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  84. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  85. package/dist/esm/utils/widgetDispatch.js +3 -1
  86. package/dist/esm/utils/widgetDispatch.js.map +1 -1
  87. package/dist/nextcloud-vue.cjs.js +1159 -812
  88. package/dist/nextcloud-vue.cjs.js.map +2 -2
  89. package/dist/nextcloud-vue.css +580 -324
  90. package/l10n/en.json +20 -20
  91. package/l10n/nl.json +21 -21
  92. package/package.json +1 -1
  93. package/src/components/CnActionDialog/CnActionDialog.vue +45 -4
  94. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +13 -1
  95. package/src/components/CnAppNav/CnAppNav.vue +28 -3
  96. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +15 -0
  97. package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +2 -10
  98. package/src/components/CnDataTable/CnDataTable.md +1 -0
  99. package/src/components/CnDataTable/CnDataTable.vue +38 -1
  100. package/src/components/CnDetailPage/CnDetailPage.md +1 -0
  101. package/src/components/CnDetailPage/CnDetailPage.vue +26 -2
  102. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +1 -0
  103. package/src/components/CnIndexPage/CnIndexPage.vue +44 -6
  104. package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -0
  105. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +21 -0
  106. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +38 -2
  107. package/src/components/CnRegisterMapping/CnRegisterMapping.vue +7 -0
  108. package/src/components/CnRetentionWidget/CnRetentionWidget.vue +13 -0
  109. package/src/components/CnSavedViewMenuSettings/CnSavedViewMenuSettings.vue +14 -4
  110. package/src/components/CnTimelineWidget/CnTimelineManage.vue +23 -0
  111. package/src/components/CnTimelineWidget/dashboardRegistration.js +3 -1
  112. package/src/components/CnWorkingCalendarWidget/CnWorkingCalendarWidget.vue +7 -0
  113. package/src/composables/indexSources.js +69 -3
  114. package/src/css/look-board-detail.css +57 -1
  115. package/src/css/look-board-index.css +76 -1
  116. package/src/css/look-board.css +51 -4
  117. package/src/css/table.css +5 -0
  118. package/src/schemas/app-manifest-v2.schema.json +4 -2
  119. package/src/utils/contentHeaderLink.js +7 -1
  120. package/src/utils/savedViewMenu.js +4 -1
  121. package/src/utils/savedViewSummary.js +11 -4
  122. package/src/utils/validateManifestV2.compiled.js +2 -2
  123. package/src/utils/widgetDispatch.js +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CnActionDialog.vue3.js","sources":["../../../../src/components/CnActionDialog/CnActionDialog.vue?vue&type=template&id=7d4eaf3b&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"text(config.title) || t('nextcloud-vue', 'Confirm')\"\n\t\t:eyebrow=\"eyebrowText\"\n\t\t:subtitle=\"text(config.subtitle)\"\n\t\twidth=\"form\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-action-dialog\"\n\t\t@closing=\"close\">\n\t\t<div v-if=\"!done\" class=\"cn-action-dialog\">\n\t\t\t<!-- The record the action is about: its title, a meta line, a badge. -->\n\t\t\t<div v-if=\"summary\" class=\"cn-action-dialog__summary\" data-testid=\"cn-action-dialog-summary\">\n\t\t\t\t<CnIcon :name=\"config.summary.icon || 'FolderOutline'\" :size=\"20\" class=\"cn-action-dialog__summary-icon\" />\n\t\t\t\t<span class=\"cn-action-dialog__summary-text\">\n\t\t\t\t\t<strong>{{ summary.title }}</strong>\n\t\t\t\t\t<span v-if=\"summary.meta\" class=\"cn-action-dialog__muted\">{{ summary.meta }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span v-if=\"summary.badge\" class=\"cn-action-dialog__badge\">{{ summary.badge }}</span>\n\t\t\t</div>\n\n\t\t\t<!-- Facts about the record, in titled groups (\"Retention under the case type\"). -->\n\t\t\t<section v-for=\"(section, index) in factSections\"\n\t\t\t\t:key=\"`facts-${index}`\"\n\t\t\t\tclass=\"cn-action-dialog__section\"\n\t\t\t\tdata-testid=\"cn-action-dialog-facts\">\n\t\t\t\t<h3 v-if=\"section.title\" class=\"cn-action-dialog__title\">\n\t\t\t\t\t{{ section.title }}\n\t\t\t\t</h3>\n\t\t\t\t<dl class=\"cn-action-dialog__facts\">\n\t\t\t\t\t<div v-for=\"fact in section.facts\" :key=\"fact.label\" class=\"cn-action-dialog__fact\">\n\t\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t\t<dd>{{ fact.value }}</dd>\n\t\t\t\t\t</div>\n\t\t\t\t</dl>\n\t\t\t</section>\n\n\t\t\t<!-- The checklist, read from an endpoint: each item met, not met or\n\t\t\t unknown. Items named in `required` decide whether the action may\n\t\t\t run; the others inform. -->\n\t\t\t<section v-if=\"config.checklist\" class=\"cn-action-dialog__section\" data-testid=\"cn-action-dialog-checklist\">\n\t\t\t\t<h3 v-if=\"config.checklist.title\" class=\"cn-action-dialog__title\">\n\t\t\t\t\t{{ text(config.checklist.title) }}\n\t\t\t\t</h3>\n\t\t\t\t<p v-if=\"checklistError\" class=\"cn-action-dialog__muted\" role=\"status\">\n\t\t\t\t\t{{ checklistError }}\n\t\t\t\t</p>\n\t\t\t\t<ul class=\"cn-action-dialog__checks\">\n\t\t\t\t\t<li v-for=\"item in checklist\"\n\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\tclass=\"cn-action-dialog__check\"\n\t\t\t\t\t\t:data-testid=\"`cn-action-dialog-check-${item.id}`\"\n\t\t\t\t\t\t:data-met=\"String(item.met)\">\n\t\t\t\t\t\t<CheckCircle v-if=\"item.met === true\" :size=\"20\" class=\"cn-action-dialog__check-icon cn-action-dialog__check-icon--met\" />\n\t\t\t\t\t\t<HelpCircleOutline v-else-if=\"item.met === null\" :size=\"20\" class=\"cn-action-dialog__check-icon\" />\n\t\t\t\t\t\t<CircleOutline v-else :size=\"20\" class=\"cn-action-dialog__check-icon\" />\n\t\t\t\t\t\t<strong class=\"cn-action-dialog__check-label\">{{ item.label }}</strong>\n\t\t\t\t\t\t<span v-if=\"item.detail\" class=\"cn-action-dialog__muted\">{{ item.detail }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\n\t\t\t<!-- Fields the action asks for, sent beside the reason. -->\n\t\t\t<div v-for=\"field in fields\"\n\t\t\t\t:key=\"field.field\"\n\t\t\t\tclass=\"cn-action-dialog__field\"\n\t\t\t\t:data-testid=\"`cn-action-dialog-field-${field.field}`\">\n\t\t\t\t<!-- A checkbox field: a tinted box, the label filled from the\n\t\t\t\t record, a hint under it (DqArchiveren \"Sanne de Vries laten\n\t\t\t\t weten...\"). -->\n\t\t\t\t<NcCheckboxRadioSwitch v-if=\"field.type === 'checkbox'\"\n\t\t\t\t\tclass=\"cn-action-dialog__checkbox\"\n\t\t\t\t\t:modelValue=\"checkboxValue(field)\"\n\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t@update:modelValue=\"(on) => setChecked(field.field, on)\">\n\t\t\t\t\t<span class=\"cn-action-dialog__checkbox-text\">\n\t\t\t\t\t\t<strong class=\"cn-action-dialog__checkbox-label\">{{ fill(field.label) || field.field }}</strong>\n\t\t\t\t\t\t<span v-if=\"field.hint\" class=\"cn-action-dialog__muted\">{{ fill(field.hint) }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<!-- A search field: records of `source` found as the reader\n\t\t\t\t types (DqZaakKoppelen \"Zaak koppelen\"). -->\n\t\t\t\t<CnSearchSelect v-else-if=\"field.type === 'search'\"\n\t\t\t\t\t:modelValue=\"values[field.field] || null\"\n\t\t\t\t\t:options=\"searchOptions[field.field] || []\"\n\t\t\t\t\t:inputLabel=\"fill(field.label) || field.field\"\n\t\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t\t:loading=\"searching === field.field\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:placeholder=\"fill(field.placeholder)\"\n\t\t\t\t\t@search=\"(typed) => onSearch(field, typed)\"\n\t\t\t\t\t@update:modelValue=\"(value) => setValue(field.field, value && typeof value === 'object' ? value.id : value)\" />\n\t\t\t\t<!-- An optional select or text field: its label above the control,\n\t\t\t\t \"(optional)\" in grey after it (DqUwWachtrij \"Sjabloon (niet\n\t\t\t\t verplicht)\"). -->\n\t\t\t\t<CnFormField v-if=\"labelsOutside(field)\"\n\t\t\t\t\t:controlId=\"controlId(field)\"\n\t\t\t\t\t:text=\"fill(field.label) || field.field\"\n\t\t\t\t\t:optional=\"true\" />\n\t\t\t\t<NcSelect v-if=\"field.type === 'select'\"\n\t\t\t\t\t:modelValue=\"selectedOption(field)\"\n\t\t\t\t\t:options=\"optionsOf(field)\"\n\t\t\t\t\t:inputId=\"controlId(field)\"\n\t\t\t\t\t:inputLabel=\"fill(field.label) || field.field\"\n\t\t\t\t\t:labelOutside=\"labelsOutside(field)\"\n\t\t\t\t\t:placeholder=\"fill(field.placeholder)\"\n\t\t\t\t\t:clearable=\"field.required === false\"\n\t\t\t\t\t@update:modelValue=\"(option) => pick(field, option)\" />\n\t\t\t\t<NcTextField v-else-if=\"field.type === 'secret'\"\n\t\t\t\t\t:modelValue=\"values[field.field] || ''\"\n\t\t\t\t\ttype=\"password\"\n\t\t\t\t\tautocomplete=\"new-password\"\n\t\t\t\t\t:label=\"text(field.label) || field.field\"\n\t\t\t\t\t:placeholder=\"secretStored(field) ? t('nextcloud-vue', 'Stored. Type a new value to replace it.') : ''\"\n\t\t\t\t\t@update:modelValue=\"(value) => setValue(field.field, value)\" />\n\t\t\t\t<NcTextField v-else-if=\"field.type !== 'checkbox' && field.type !== 'search'\"\n\t\t\t\t\t:id=\"controlId(field)\"\n\t\t\t\t\t:modelValue=\"values[field.field] || ''\"\n\t\t\t\t\t:type=\"field.type === 'datetime' ? 'datetime-local' : (field.type === 'date' ? 'date' : 'text')\"\n\t\t\t\t\t:label=\"fill(field.label) || field.field\"\n\t\t\t\t\t:labelOutside=\"labelsOutside(field)\"\n\t\t\t\t\t@update:modelValue=\"(value) => setValue(field.field, value)\" />\n\t\t\t\t<span v-if=\"field.hint && field.type !== 'checkbox'\" class=\"cn-action-dialog__muted\">{{ fill(field.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-if=\"config.reason\" class=\"cn-action-dialog__field\">\n\t\t\t\t<NcTextArea\n\t\t\t\t\t:id=\"reasonId\"\n\t\t\t\t\tv-model=\"reason\"\n\t\t\t\t\t:label=\"reasonLabel\"\n\t\t\t\t\t:labelOutside=\"false\"\n\t\t\t\t\t:rows=\"config.reason.rows || 2\"\n\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\tdata-testid=\"cn-action-dialog-reason\" />\n\t\t\t\t<span v-if=\"config.reason.hint\" class=\"cn-action-dialog__muted\">{{ text(config.reason.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<NcNoteCard v-if=\"config.note\"\n\t\t\t\t:type=\"noteType\"\n\t\t\t\t:heading=\"text(config.note.title)\"\n\t\t\t\tdata-testid=\"cn-action-dialog-note\">\n\t\t\t\t{{ text(config.note.text) }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"refusal\"\n\t\t\t\tclass=\"cn-action-dialog__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-action-dialog-refusal\">\n\t\t\t\t{{ refusal }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<p v-else role=\"status\" data-testid=\"cn-action-dialog-done\">\n\t\t\t{{ text(config.doneText) || t('nextcloud-vue', 'Done') }}\n\t\t</p>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-action-dialog-cancel\" @click=\"close\">\n\t\t\t\t{{ done ? t('nextcloud-vue', 'Close') : t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton v-if=\"!done\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-action-dialog-confirm\"\n\t\t\t\t@click=\"confirm\">\n\t\t\t\t<template v-if=\"confirmConfig.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"confirmConfig.icon\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(confirmConfig.label) || t('nextcloud-vue', 'Confirm') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcNoteCard, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport CheckCircle from 'vue-material-design-icons/CheckCircle.vue'\nimport CircleOutline from 'vue-material-design-icons/CircleOutline.vue'\nimport HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'\nimport CnFormField from '../CnFormField/CnFormField.vue'\nimport { fetchEndpointSource, interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { CnDialog } from '../CnDialog/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnSearchSelect } from '../CnSearchSelect/index.js'\n\n/** How long typing rests before a search field searches, in ms. */\nconst SEARCH_DELAY = 250\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/** Gives each dialog's reason field its own id. */\nlet reasonSeq = 0\n\n/**\n * CnActionDialog — the generic \"summary, checklist, reason, confirm\" dialog\n * for an act on a record, configured from the manifest (an `open-modal`\n * action's props), so an app does not hand-build each one. dossiq's archive\n * dialog (board DqArchiveren) is the first: the case, what its case type\n * keeps, a readiness checklist read from an endpoint, a reason, a read-only\n * note and Archive it.\n *\n * `config`:\n * - `title`, `subtitle`, `doneText`: texts, through the host translate;\n * `eyebrow` a template filled from the record (\"Close off · {identifier}\").\n * - `summary`: `{ source?, title, meta?, badge?, icon? }`: templates filled from\n * the record (`source` an endpointSource to read it from, else `object`).\n * - `facts`: `[{ title?, items: [{ label, value }] }]`, `value` a template.\n * - `checklist`: `{ title?, source, itemsPath?, labels?, required? }`: items\n * `{ id, met, label?, detail? }` read from `source`; `labels[id]` gives an\n * item's `{ label, detail?, unmetDetail? }`; the ids in `required` must be\n * met before the action can run. `met: null` reads as unknown.\n * - `permission`: `{ source, listPath?, match?, allowedPath, reasonPath? }`:\n * the action runs only while `allowedPath` reads true; `reasonPath` says\n * why not. With `listPath` the paths read the entry of that list whose\n * fields equal `match` (`{ act: \"archive\" }`).\n * - `fields`: `[{ field, type?: \"text\"|\"date\"|\"datetime\"|\"select\"|\"checkbox\", label?,\n * required?, options?: [{ value, label, fills? }], hint?, default? }]`: inputs\n * sent beside the reason, required by default; a select option's `fills`\n * sets other fields that are still empty. A `checkbox` is sent as a boolean,\n * starts at `default` (false), fills its `label` and `hint` from the record,\n * and is optional unless `required: true` (then it must be ticked). A\n * `search` field finds records of `source: { register, schema }` as the\n * reader types, shows each as `optionLabel` with `optionSecondary` under\n * it (templates on the found record), leaves the record in hand out with\n * `excludeSelf`, and sends the chosen record's id. Every field's `label`,\n * `hint` and `placeholder` (search and select) are templates filled from the record.\n * An optional select or text field (`required: false`) draws its label above\n * the control with \"(optional)\" after it.\n * - `reason`: `{ label?, hint?, required?, field?, rows? }`: a text area; required by\n * default; sent as `field` (default `reason`). `rows` is its height in lines\n * (default 2; board DqBesluit draws 4).\n * - `note`: `{ variant?, title?, text }`: a read-only note.\n * - `confirm`: `{ label, icon?, request?: { method?, url, body? }, action? }`.\n * `request` posts itself (`body` templates filled with the record and\n * `{reason}`); `action` dispatches a manifest action through the page.\n *\n * Tokens (`@objectId`, `@object.<field>`) resolve in every url.\n */\nexport default {\n\tname: 'CnActionDialog',\n\n\tcomponents: { CheckCircle, CircleOutline, CnDialog, CnFormField, CnIcon, CnSearchSelect, HelpCircleOutline, NcButton, NcCheckboxRadioSwitch, NcNoteCard, NcSelect, NcTextArea, NcTextField },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `confirm.action`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The dialog's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record, when the host has it: the summary and facts read it.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['close', 'done'],\n\n\tdata() {\n\t\treturn {\n\t\t\trecord: this.object,\n\t\t\titems: [],\n\t\t\tchecklistError: '',\n\t\t\tallowed: true,\n\t\t\treason: '',\n\t\t\tvalues: {},\n\t\t\t/** A search field's found options, by field name. */\n\t\t\tsearchOptions: {},\n\t\t\t/** The search field whose search runs, or ''. */\n\t\t\tsearching: '',\n\t\t\tbusy: false,\n\t\t\trefusal: '',\n\t\t\tdone: false,\n\t\t\treasonId: `cn-action-dialog-reason-${++reasonSeq}`,\n\t\t\tfieldIdPrefix: `cn-action-dialog-field-${reasonSeq}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The token context. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.recordId, object: this.record || {} }\n\t\t},\n\n\t\t/**\n\t\t * The record's id: `objectId`, or the route's `id` when the prop is\n\t\t * empty or a token the opener could not resolve.\n\t\t *\n\t\t * @return {string|number}\n\t\t */\n\t\trecordId() {\n\t\t\tconst given = this.objectId\n\t\t\tif (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {\n\t\t\t\treturn given\n\t\t\t}\n\t\t\treturn (this.$route && this.$route.params && this.$route.params.id) || ''\n\t\t},\n\n\t\t/** @return {object} The confirm config. */\n\t\tconfirmConfig() {\n\t\t\treturn this.config.confirm && typeof this.config.confirm === 'object' ? this.config.confirm : {}\n\t\t},\n\n\t\t/**\n\t\t * The summary row, or null without one or before the record is known.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {{title: string, meta: string, badge: string}|null}\n\t\t */\n\t\tsummary() {\n\t\t\tconst def = this.config.summary\n\t\t\tif (!def || !this.record) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst title = this.fill(def.title)\n\t\t\treturn title ? { title, meta: this.fill(def.meta), badge: this.fill(def.badge) } : null\n\t\t},\n\n\t\t/** @return {Array<{title: string, facts: Array<{label: string, value: string}>}>} The fact groups. */\n\t\tfactSections() {\n\t\t\tif (!Array.isArray(this.config.facts) || !this.record) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst empty = t('nextcloud-vue', 'Not set')\n\t\t\treturn this.config.facts.map((section) => ({\n\t\t\t\ttitle: this.text(section.title),\n\t\t\t\tfacts: (Array.isArray(section.items) ? section.items : []).map((fact) => ({ label: this.text(fact.label), value: this.fill(fact.value) || empty })),\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The checklist rows: label and detail from `labels` by id, else the item's own.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {Array<{id: string, met: (boolean|null), label: string, detail: string}>}\n\t\t */\n\t\tchecklist() {\n\t\t\tconst labels = (this.config.checklist && this.config.checklist.labels) || {}\n\t\t\treturn this.items.map((item) => {\n\t\t\t\tconst met = item.met === null || item.met === undefined ? null : item.met === true\n\t\t\t\tconst own = labels[item.id] || {}\n\t\t\t\tconst detail = met === false && own.unmetDetail ? own.unmetDetail : (own.detail || item.detail || '')\n\t\t\t\treturn {\n\t\t\t\t\tid: String(item.id),\n\t\t\t\t\tmet,\n\t\t\t\t\tlabel: this.fill(own.label || item.label || String(item.id), item),\n\t\t\t\t\tdetail: met === null && !item.detail ? t('nextcloud-vue', 'Could not be read') : this.fill(detail, item),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** @return {boolean} Whether every required item is met. */\n\t\trequiredMet() {\n\t\t\tconst required = (this.config.checklist && Array.isArray(this.config.checklist.required)) ? this.config.checklist.required.map(String) : []\n\t\t\treturn required.every((id) => this.items.some((item) => String(item.id) === id && item.met === true))\n\t\t},\n\n\t\t/** @return {boolean} Whether a reason is asked and needed. */\n\t\treasonNeeded() {\n\t\t\treturn Boolean(this.config.reason) && this.config.reason.required !== false\n\t\t},\n\n\t\t/** @return {string} The reason field's label. */\n\t\treasonLabel() {\n\t\t\treturn this.text(this.config.reason && this.config.reason.label) || t('nextcloud-vue', 'Reason')\n\t\t},\n\n\t\t/** @return {string} The note's NcNoteCard type. */\n\t\tnoteType() {\n\t\t\tconst variant = this.config.note && this.config.note.variant\n\t\t\treturn ['info', 'warning', 'error', 'success'].includes(variant) ? variant : 'info'\n\t\t},\n\n\t\t/**\n\t\t * Whether the action may run: allowed, required items met, a reason\n\t\t * when one is needed, and nothing in flight.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {boolean}\n\t\t */\n\t\tcanConfirm() {\n\t\t\treturn !this.busy && this.allowed && this.requiredMet && this.fieldsFilled && (!this.reasonNeeded || this.reason.trim() !== '')\n\t\t},\n\n\t\t/** @return {string} The eyebrow, filled from the record once it is known. */\n\t\teyebrowText() {\n\t\t\treturn this.record ? this.fill(this.config.eyebrow) || this.text(this.config.eyebrow) : this.text(this.config.eyebrow)\n\t\t},\n\n\t\t/**\n\t\t * The value of every field as sent: a checkbox as a boolean, the\n\t\t * others as entered ('' when empty).\n\t\t *\n\t\t * @return {object} Values by field name.\n\t\t */\n\t\tfieldValues() {\n\t\t\tconst out = { ...this.values }\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tout[field.field] = field.type === 'checkbox' ? this.checkboxValue(field) : (this.values[field.field] ?? '')\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/** @return {Array<object>} The fields with a name. */\n\t\tfields() {\n\t\t\treturn (Array.isArray(this.config.fields) ? this.config.fields : []).filter((f) => f && f.field)\n\t\t},\n\n\t\t/**\n\t\t * Whether every required field has a value.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog-fields-and-acts/specs/action-dialog/spec.md#requirement-an-action-dialog-asks-for-fields-and-reads-a-permission-from-a-list\n\t\t * @return {boolean}\n\t\t */\n\t\tfieldsFilled() {\n\t\t\treturn this.fields.every((f) => {\n\t\t\t\tif (f.type === 'checkbox') {\n\t\t\t\t\treturn f.required !== true || this.checkboxValue(f)\n\t\t\t\t}\n\t\t\t\treturn f.required === false || this.secretStored(f) || String(this.values[f.field] ?? '').trim() !== ''\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\trecord: {\n\t\t\thandler() {\n\t\t\t\tthis.startValues()\n\t\t\t},\n\n\t\t\timmediate: true,\n\t\t},\n\t},\n\n\tasync mounted() {\n\t\tawait Promise.all([this.loadRecord(), this.loadChecklist(), this.loadPermission()])\n\t},\n\n\tbeforeUnmount() {\n\t\tclearTimeout(this.searchTimer)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Whether a field's label sits above its control with \"(optional)\" after\n\t\t * it: a select or a text field the action does not require.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog-optional-fields/specs/action-dialog/spec.md#requirement-an-optional-field-says-so-beside-its-label\n\t\t * @param {object} field The field.\n\t\t * @return {boolean}\n\t\t */\n\t\tlabelsOutside(field) {\n\t\t\treturn field.required === false && !['checkbox', 'search', 'secret'].includes(field.type)\n\t\t},\n\n\t\t/**\n\t\t * The id of a field's control, which its outside label points at.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {string}\n\t\t */\n\t\tcontrolId(field) {\n\t\t\treturn `${this.fieldIdPrefix}-${field.field}`\n\t\t},\n\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate, '' for anything else.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\t/**\n\t\t * Search a search field's records once typing rests.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @param {string} typed What the reader typed.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/action-dialog-search-field/specs/action-dialog-search-field/spec.md#requirement-an-action-dialog-field-can-search-records\n\t\t */\n\t\tonSearch(field, typed) {\n\t\t\tclearTimeout(this.searchTimer)\n\t\t\tthis.searchTimer = setTimeout(() => this.searchRecords(field, String(typed || '').trim()), SEARCH_DELAY)\n\t\t},\n\n\t\t/**\n\t\t * Read the records of a search field's `source` that match the term.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @param {string} term The term.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync searchRecords(field, term) {\n\t\t\tconst source = field.source || {}\n\t\t\tif (!term || !source.register || !source.schema) {\n\t\t\t\tthis.searchOptions = { ...this.searchOptions, [field.field]: [] }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.searching = field.field\n\t\t\ttry {\n\t\t\t\tconst url = generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(source.register)}/${encodeURIComponent(source.schema)}`)\n\t\t\t\tconst { data } = await axios.get(url, { params: { _search: term, _limit: 10 } })\n\t\t\t\tconst rows = Array.isArray(data) ? data : (data && Array.isArray(data.results) ? data.results : [])\n\t\t\t\tconst self = String(this.recordId || '')\n\t\t\t\tconst options = rows\n\t\t\t\t\t.map((row) => ({ row, id: String(row.id || (row['@self'] && row['@self'].id) || '') }))\n\t\t\t\t\t.filter(({ id }) => id !== '' && !(field.excludeSelf && id === self))\n\t\t\t\t\t.map(({ row, id }) => {\n\t\t\t\t\t\tconst option = { id, label: this.fill(field.optionLabel || '{title}', row) || id }\n\t\t\t\t\t\tconst secondary = this.fill(field.optionSecondary, row)\n\t\t\t\t\t\treturn secondary ? { ...option, secondary } : option\n\t\t\t\t\t})\n\t\t\t\tthis.searchOptions = { ...this.searchOptions, [field.field]: options }\n\t\t\t} catch {\n\t\t\t\tthis.searchOptions = { ...this.searchOptions, [field.field]: [] }\n\t\t\t} finally {\n\t\t\t\tthis.searching = ''\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A checkbox field's state: what was ticked, else its `default`.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/action-dialog-checkbox-field/specs/action-dialog-checkbox-field/spec.md#requirement-an-action-dialog-field-can-be-a-checkbox\n\t\t */\n\t\tcheckboxValue(field) {\n\t\t\treturn field.field in this.values ? this.values[field.field] === true : field.default === true\n\t\t},\n\n\t\t/**\n\t\t * Tick or untick a checkbox field.\n\t\t *\n\t\t * @param {string} name The field.\n\t\t * @param {boolean} on Ticked.\n\t\t * @return {void}\n\t\t */\n\t\tsetChecked(name, on) {\n\t\t\tthis.values = { ...this.values, [name]: on === true }\n\t\t},\n\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * A template filled from a row (the record by default), translated first.\n\t\t *\n\t\t * @param {unknown} template The template.\n\t\t * @param {object} [row] The row.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template, row) {\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn fillTemplate(this.cnTranslate(template), row || this.record || {}).trim()\n\t\t},\n\n\t\t/**\n\t\t * Read an endpoint, fresh.\n\t\t *\n\t\t * @param {object} source An endpointSource block.\n\t\t * @return {Promise<unknown>}\n\t\t */\n\t\tread(source) {\n\t\t\treturn fetchEndpointSource(source, this.tokenCtx, { fresh: true })\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadRecord() {\n\t\t\tconst source = this.config.summary && this.config.summary.source\n\t\t\tif (!source || !source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(source)\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : this.record\n\t\t\t} catch {\n\t\t\t\t// The summary stays empty; the checklist and the action still work.\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadChecklist() {\n\t\t\tconst def = this.config.checklist\n\t\t\tif (!def || !def.source || !def.source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(def.source)\n\t\t\t\tconst list = def.itemsPath ? readPath(data, def.itemsPath) : data\n\t\t\t\tthis.items = Array.isArray(list) ? list.filter((item) => item && item.id !== undefined) : []\n\t\t\t} catch {\n\t\t\t\tthis.items = []\n\t\t\t\tthis.checklistError = t('nextcloud-vue', 'Whether this is ready could not be read.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The entry of a list whose fields equal `match`, or null.\n\t\t *\n\t\t * @param {unknown} list The list.\n\t\t * @param {object} [match] The fields to match.\n\t\t * @return {object|null}\n\t\t */\n\t\tmatchIn(list, match) {\n\t\t\tconst wanted = Object.entries(match || {})\n\t\t\treturn (Array.isArray(list) ? list : []).find((entry) => entry && wanted.every(([key, value]) => String(entry[key]) === String(value))) || null\n\t\t},\n\n\t\t/**\n\t\t * A select field's options, labels translated.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {Array<{id: string, label: string, fills?: object}>}\n\t\t */\n\t\toptionsOf(field) {\n\t\t\treturn (Array.isArray(field.options) ? field.options : []).map((o) => ({ id: String(o.value), label: this.text(o.label) || String(o.value), fills: o.fills }))\n\t\t},\n\n\t\t/**\n\t\t * A select field's chosen option.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {object|null}\n\t\t */\n\t\tselectedOption(field) {\n\t\t\treturn this.optionsOf(field).find((o) => o.id === String(this.values[field.field] ?? '')) || null\n\t\t},\n\n\t\t/**\n\t\t * Set a field's value.\n\t\t *\n\t\t * @param {string} name The field.\n\t\t * @param {unknown} value The value.\n\t\t */\n\t\tsetValue(name, value) {\n\t\t\tthis.values = { ...this.values, [name]: value === null || value === undefined ? '' : String(value) }\n\t\t},\n\n\t\t/**\n\t\t * Choose a select option; its `fills` set the fields still empty.\n\t\t *\n\t\t * @param {object} field The select field.\n\t\t * @param {{id: string, fills?: object}|null} option The option.\n\t\t */\n\t\tpick(field, option) {\n\t\t\tthis.setValue(field.field, option ? option.id : '')\n\t\t\tfor (const [name, value] of Object.entries((option && option.fills) || {})) {\n\t\t\t\tif (String(this.values[name] ?? '').trim() === '') {\n\t\t\t\t\tthis.setValue(name, this.text(value) || value)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadPermission() {\n\t\t\tconst def = this.config.permission\n\t\t\tif (!def || !def.source || !def.source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(def.source)\n\t\t\t\tconst entry = def.listPath ? this.matchIn(readPath(data, def.listPath), def.match) : data\n\t\t\t\tthis.allowed = readPath(entry, def.allowedPath || 'allowed') === true\n\t\t\t\tthis.refusal = this.allowed || !def.reasonPath ? '' : String(readPath(entry, def.reasonPath) || '')\n\t\t\t} catch {\n\t\t\t\tthis.allowed = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run the action once: post `confirm.request`, or dispatch\n\t\t * `confirm.action`, then show the done text and refresh the page.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync confirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\tconst reason = this.reason.trim()\n\t\t\ttry {\n\t\t\t\tconst request = this.confirmConfig.request\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst url = interpolateUrlTokens(request.url, this.tokenCtx)\n\t\t\t\t\tconst body = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body || {})) {\n\t\t\t\t\t\tbody[key] = typeof value === 'string' ? fillTemplate(value, { ...(this.record || {}), reason }) : value\n\t\t\t\t\t}\n\t\t\t\t\tif (this.config.reason) {\n\t\t\t\t\t\tbody[this.config.reason.field || 'reason'] = reason\n\t\t\t\t\t}\n\t\t\t\t\tconst values = { ...this.fieldValues }\n\t\t\t\t\tfor (const field of this.fields) {\n\t\t\t\t\t\tif (field.type === 'secret' && String(this.values[field.field] ?? '') === '') {\n\t\t\t\t\t\t\tdelete values[field.field]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tObject.assign(body, values)\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[['post', 'put', 'patch', 'delete'].includes(method) ? method : 'post'](/^https?:\\/\\//i.test(url) ? url : generateUrl(url), body)\n\t\t\t\t} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tawait this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), { ...this.fieldValues, reason }] })\n\t\t\t\t}\n\t\t\t\tthis.done = true\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t\t/** @event done The action ran. Payload: the field values and `reason`. */\n\t\t\t\tthis.$emit('done', { ...this.fieldValues, reason })\n\t\t\t} catch (failure) {\n\t\t\t\tconst data = failure && failure.response && failure.response.data\n\t\t\t\tthis.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'The action could not be completed.'))\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Start each field with `valuePath` from the record, unless it was\n\t\t * already edited.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog-secret-field/specs/action-dialog/spec.md#requirement-a-field-can-start-from-the-record-and-a-secret-is-write-only\n\t\t * @return {void}\n\t\t */\n\t\tstartValues() {\n\t\t\tif (!this.record) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst values = { ...this.values }\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (field.valuePath && field.type !== 'secret' && !(field.field in values)) {\n\t\t\t\t\tconst value = readPath(this.record, field.valuePath)\n\t\t\t\t\tif (value !== null && value !== undefined) {\n\t\t\t\t\t\tvalues[field.field] = String(value)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.values = values\n\t\t},\n\n\t\t/**\n\t\t * Whether a secret field has a value stored: `storedPath` reads true on the record.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {boolean}\n\t\t */\n\t\tsecretStored(field) {\n\t\t\treturn field.type === 'secret' && Boolean(field.storedPath && this.record && readPath(this.record, field.storedPath))\n\t\t},\n\n\t\t/** Close the dialog, unless the action is running. */\n\t\tclose() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/** @event close The dialog was closed. */\n\t\t\tthis.$emit('close')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-action-dialog {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-action-dialog__summary {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 8px);\n}\n\n.cn-action-dialog__summary-text {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-action-dialog__badge {\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n}\n\n.cn-action-dialog__title {\n\tmargin: 0 0 8px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n}\n\n/* Facts in columns of at least 200px, each a label over its value above a\n hairline (DqArchiveren \"Bewaring volgens het zaaktype\"). */\n.cn-action-dialog__facts {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n\tgap: 12px 24px;\n\tmargin: 0;\n}\n\n.cn-action-dialog__fact {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n\tpadding-bottom: 10px;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.cn-action-dialog__facts dt {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-action-dialog__facts dd {\n\tmargin: 0;\n\tfont-size: 15px;\n\tfont-weight: 500;\n}\n\n/* Checklist rows divided by hairlines, the detail at the row's end\n (DqArchiveren \"Klaar om te archiveren\"). */\n.cn-action-dialog__checks {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-action-dialog__check {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 2px 12px;\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--color-border);\n\tfont-size: 15px;\n}\n\n.cn-action-dialog__check-label {\n\tflex: 1 1 auto;\n\tfont-weight: 600;\n}\n\n.cn-action-dialog__check-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-action-dialog__check-icon--met {\n\tcolor: var(--color-success-text, var(--color-success));\n}\n\n.cn-action-dialog__muted {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n/* A checkbox field is a tinted box with a 2px edge, its label bold and its\n hint under it (DqArchiveren). */\n.cn-action-dialog__checkbox {\n\tpadding: 12px 14px;\n\tborder: 2px solid var(--color-primary-element);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-action-dialog__checkbox-text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-action-dialog__checkbox-label {\n\tfont-size: 15px;\n\tfont-weight: 600;\n}\n\n.cn-action-dialog__checkbox .cn-action-dialog__muted {\n\tfont-size: 13px;\n}\n\n.cn-action-dialog__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-action-dialog__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createVNode","_createBlock","_createTextVNode","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_Fragment","_renderList"],"mappings":"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"}
1
+ {"version":3,"file":"CnActionDialog.vue3.js","sources":["../../../../src/components/CnActionDialog/CnActionDialog.vue?vue&type=template&id=a3810b54&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<CnDialog\n\t\t:name=\"text(config.title) || t('nextcloud-vue', 'Confirm')\"\n\t\t:eyebrow=\"eyebrowText\"\n\t\t:subtitle=\"text(config.subtitle)\"\n\t\twidth=\"form\"\n\t\t:noClose=\"busy\"\n\t\tdata-testid=\"cn-action-dialog\"\n\t\t@closing=\"close\">\n\t\t<div v-if=\"!done\" class=\"cn-action-dialog\">\n\t\t\t<!-- The record the action is about: its title, a meta line, a badge. -->\n\t\t\t<div v-if=\"summary\" class=\"cn-action-dialog__summary\" data-testid=\"cn-action-dialog-summary\">\n\t\t\t\t<span class=\"cn-action-dialog__summary-icon\">\n\t\t\t\t\t<CnIcon :name=\"config.summary.icon || 'FolderOutline'\" :size=\"20\" />\n\t\t\t\t</span>\n\t\t\t\t<span class=\"cn-action-dialog__summary-text\">\n\t\t\t\t\t<strong>{{ summary.title }}</strong>\n\t\t\t\t\t<span v-if=\"summary.meta\" class=\"cn-action-dialog__muted\">{{ summary.meta }}</span>\n\t\t\t\t</span>\n\t\t\t\t<span v-if=\"summary.badge\" class=\"cn-action-dialog__badge\">{{ summary.badge }}</span>\n\t\t\t</div>\n\n\t\t\t<!-- Facts about the record, in titled groups (\"Retention under the case type\"). -->\n\t\t\t<section v-for=\"(section, index) in factSections\"\n\t\t\t\t:key=\"`facts-${index}`\"\n\t\t\t\tclass=\"cn-action-dialog__section\"\n\t\t\t\tdata-testid=\"cn-action-dialog-facts\">\n\t\t\t\t<h3 v-if=\"section.title\" class=\"cn-action-dialog__title\">\n\t\t\t\t\t{{ section.title }}\n\t\t\t\t</h3>\n\t\t\t\t<dl class=\"cn-action-dialog__facts\">\n\t\t\t\t\t<div v-for=\"fact in section.facts\" :key=\"fact.label\" class=\"cn-action-dialog__fact\">\n\t\t\t\t\t\t<dt>{{ fact.label }}</dt>\n\t\t\t\t\t\t<dd>{{ fact.value }}</dd>\n\t\t\t\t\t</div>\n\t\t\t\t</dl>\n\t\t\t</section>\n\n\t\t\t<!-- The checklist, read from an endpoint: each item met, not met or\n\t\t\t unknown. Items named in `required` decide whether the action may\n\t\t\t run; the others inform. -->\n\t\t\t<section v-if=\"config.checklist\" class=\"cn-action-dialog__section\" data-testid=\"cn-action-dialog-checklist\">\n\t\t\t\t<h3 v-if=\"config.checklist.title\" class=\"cn-action-dialog__title\">\n\t\t\t\t\t{{ text(config.checklist.title) }}\n\t\t\t\t</h3>\n\t\t\t\t<p v-if=\"checklistError\" class=\"cn-action-dialog__muted\" role=\"status\">\n\t\t\t\t\t{{ checklistError }}\n\t\t\t\t</p>\n\t\t\t\t<ul class=\"cn-action-dialog__checks\">\n\t\t\t\t\t<li v-for=\"item in checklist\"\n\t\t\t\t\t\t:key=\"item.id\"\n\t\t\t\t\t\tclass=\"cn-action-dialog__check\"\n\t\t\t\t\t\t:data-testid=\"`cn-action-dialog-check-${item.id}`\"\n\t\t\t\t\t\t:data-met=\"String(item.met)\">\n\t\t\t\t\t\t<CheckCircle v-if=\"item.met === true\" :size=\"20\" class=\"cn-action-dialog__check-icon cn-action-dialog__check-icon--met\" />\n\t\t\t\t\t\t<HelpCircleOutline v-else-if=\"item.met === null\" :size=\"20\" class=\"cn-action-dialog__check-icon\" />\n\t\t\t\t\t\t<CircleOutline v-else :size=\"20\" class=\"cn-action-dialog__check-icon\" />\n\t\t\t\t\t\t<strong class=\"cn-action-dialog__check-label\">{{ item.label }}</strong>\n\t\t\t\t\t\t<span v-if=\"item.detail\" class=\"cn-action-dialog__muted\">{{ item.detail }}</span>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t</section>\n\n\t\t\t<!-- Fields the action asks for, sent beside the reason. -->\n\t\t\t<div v-for=\"field in fields\"\n\t\t\t\t:key=\"field.field\"\n\t\t\t\tclass=\"cn-action-dialog__field\"\n\t\t\t\t:data-testid=\"`cn-action-dialog-field-${field.field}`\">\n\t\t\t\t<!-- A checkbox field: a tinted box, the label filled from the\n\t\t\t\t record, a hint under it (DqArchiveren \"Sanne de Vries laten\n\t\t\t\t weten...\"). -->\n\t\t\t\t<NcCheckboxRadioSwitch v-if=\"field.type === 'checkbox'\"\n\t\t\t\t\tclass=\"cn-action-dialog__checkbox\"\n\t\t\t\t\t:modelValue=\"checkboxValue(field)\"\n\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t@update:modelValue=\"(on) => setChecked(field.field, on)\">\n\t\t\t\t\t<span class=\"cn-action-dialog__checkbox-text\">\n\t\t\t\t\t\t<strong class=\"cn-action-dialog__checkbox-label\">{{ fill(field.label) || field.field }}</strong>\n\t\t\t\t\t\t<span v-if=\"field.hint\" class=\"cn-action-dialog__muted\">{{ fill(field.hint) }}</span>\n\t\t\t\t\t</span>\n\t\t\t\t</NcCheckboxRadioSwitch>\n\t\t\t\t<!-- A search field: records of `source` found as the reader\n\t\t\t\t types (DqZaakKoppelen \"Zaak koppelen\"). -->\n\t\t\t\t<CnSearchSelect v-else-if=\"field.type === 'search'\"\n\t\t\t\t\t:modelValue=\"values[field.field] || null\"\n\t\t\t\t\t:options=\"searchOptions[field.field] || []\"\n\t\t\t\t\t:inputLabel=\"fill(field.label) || field.field\"\n\t\t\t\t\t:labelOutside=\"true\"\n\t\t\t\t\t:loading=\"searching === field.field\"\n\t\t\t\t\t:filterable=\"false\"\n\t\t\t\t\t:placeholder=\"fill(field.placeholder)\"\n\t\t\t\t\t@search=\"(typed) => onSearch(field, typed)\"\n\t\t\t\t\t@update:modelValue=\"(value) => setValue(field.field, value && typeof value === 'object' ? value.id : value)\" />\n\t\t\t\t<!-- An optional select or text field: its label above the control,\n\t\t\t\t \"(optional)\" in grey after it (DqUwWachtrij \"Sjabloon (niet\n\t\t\t\t verplicht)\"). -->\n\t\t\t\t<CnFormField v-if=\"labelsOutside(field)\"\n\t\t\t\t\t:controlId=\"controlId(field)\"\n\t\t\t\t\t:text=\"fill(field.label) || field.field\"\n\t\t\t\t\t:optional=\"true\" />\n\t\t\t\t<NcSelect v-if=\"field.type === 'select'\"\n\t\t\t\t\t:modelValue=\"selectedOption(field)\"\n\t\t\t\t\t:options=\"optionsOf(field)\"\n\t\t\t\t\t:inputId=\"controlId(field)\"\n\t\t\t\t\t:inputLabel=\"fill(field.label) || field.field\"\n\t\t\t\t\t:labelOutside=\"labelsOutside(field)\"\n\t\t\t\t\t:placeholder=\"fill(field.placeholder)\"\n\t\t\t\t\t:clearable=\"field.required === false\"\n\t\t\t\t\t@update:modelValue=\"(option) => pick(field, option)\" />\n\t\t\t\t<NcTextField v-else-if=\"field.type === 'secret'\"\n\t\t\t\t\t:modelValue=\"values[field.field] || ''\"\n\t\t\t\t\ttype=\"password\"\n\t\t\t\t\tautocomplete=\"new-password\"\n\t\t\t\t\t:label=\"text(field.label) || field.field\"\n\t\t\t\t\t:placeholder=\"secretStored(field) ? t('nextcloud-vue', 'Stored. Type a new value to replace it.') : ''\"\n\t\t\t\t\t@update:modelValue=\"(value) => setValue(field.field, value)\" />\n\t\t\t\t<NcTextField v-else-if=\"field.type !== 'checkbox' && field.type !== 'search'\"\n\t\t\t\t\t:id=\"controlId(field)\"\n\t\t\t\t\t:modelValue=\"values[field.field] || ''\"\n\t\t\t\t\t:type=\"field.type === 'datetime' ? 'datetime-local' : (field.type === 'date' ? 'date' : 'text')\"\n\t\t\t\t\t:label=\"fill(field.label) || field.field\"\n\t\t\t\t\t:labelOutside=\"labelsOutside(field)\"\n\t\t\t\t\t@update:modelValue=\"(value) => setValue(field.field, value)\" />\n\t\t\t\t<span v-if=\"field.hint && field.type !== 'checkbox'\" class=\"cn-action-dialog__muted\">{{ fill(field.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<div v-if=\"config.reason\" class=\"cn-action-dialog__field\">\n\t\t\t\t<NcTextArea\n\t\t\t\t\t:id=\"reasonId\"\n\t\t\t\t\tv-model=\"reason\"\n\t\t\t\t\t:label=\"reasonLabel\"\n\t\t\t\t\t:labelOutside=\"false\"\n\t\t\t\t\t:rows=\"config.reason.rows || 2\"\n\t\t\t\t\tresize=\"vertical\"\n\t\t\t\t\tdata-testid=\"cn-action-dialog-reason\" />\n\t\t\t\t<span v-if=\"config.reason.hint\" class=\"cn-action-dialog__muted\">{{ text(config.reason.hint) }}</span>\n\t\t\t</div>\n\n\t\t\t<NcNoteCard v-if=\"config.note\"\n\t\t\t\t:type=\"noteType\"\n\t\t\t\t:heading=\"text(config.note.title)\"\n\t\t\t\tdata-testid=\"cn-action-dialog-note\">\n\t\t\t\t<template v-if=\"config.note.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"config.note.icon\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(config.note.text) }}\n\t\t\t</NcNoteCard>\n\n\t\t\t<p v-if=\"refusal\"\n\t\t\t\tclass=\"cn-action-dialog__error\"\n\t\t\t\trole=\"alert\"\n\t\t\t\tdata-testid=\"cn-action-dialog-refusal\">\n\t\t\t\t{{ refusal }}\n\t\t\t</p>\n\t\t</div>\n\n\t\t<p v-else role=\"status\" data-testid=\"cn-action-dialog-done\">\n\t\t\t{{ text(config.doneText) || t('nextcloud-vue', 'Done') }}\n\t\t</p>\n\n\t\t<template #actions>\n\t\t\t<NcButton :disabled=\"busy\" data-testid=\"cn-action-dialog-cancel\" @click=\"close\">\n\t\t\t\t{{ done ? t('nextcloud-vue', 'Close') : t('nextcloud-vue', 'Cancel') }}\n\t\t\t</NcButton>\n\t\t\t<NcButton v-if=\"!done\"\n\t\t\t\tvariant=\"primary\"\n\t\t\t\t:disabled=\"!canConfirm\"\n\t\t\t\tdata-testid=\"cn-action-dialog-confirm\"\n\t\t\t\t@click=\"confirm\">\n\t\t\t\t<template v-if=\"confirmConfig.icon\" #icon>\n\t\t\t\t\t<CnIcon :name=\"confirmConfig.icon\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t{{ text(confirmConfig.label) || t('nextcloud-vue', 'Confirm') }}\n\t\t\t</NcButton>\n\t\t</template>\n\t</CnDialog>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { emit } from '@nextcloud/event-bus'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcCheckboxRadioSwitch, NcNoteCard, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport CheckCircle from 'vue-material-design-icons/CheckCircle.vue'\nimport CircleOutline from 'vue-material-design-icons/CircleOutline.vue'\nimport HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'\nimport CnFormField from '../CnFormField/CnFormField.vue'\nimport { fetchEndpointSource, interpolateUrlTokens } from '../../composables/useEndpointSource.js'\nimport { fillTemplate } from '../../utils/fillTemplate.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { CnDialog } from '../CnDialog/index.js'\nimport { CnIcon } from '../CnIcon/index.js'\nimport { CnSearchSelect } from '../CnSearchSelect/index.js'\n\n/** How long typing rests before a search field searches, in ms. */\nconst SEARCH_DELAY = 250\n\n/** The page refresh channel the built-in widgets listen on. */\nconst PAGE_REFRESH = 'cn:page:refresh'\n\n/** Gives each dialog's reason field its own id. */\nlet reasonSeq = 0\n\n/**\n * CnActionDialog — the generic \"summary, checklist, reason, confirm\" dialog\n * for an act on a record, configured from the manifest (an `open-modal`\n * action's props), so an app does not hand-build each one. dossiq's archive\n * dialog (board DqArchiveren) is the first: the case, what its case type\n * keeps, a readiness checklist read from an endpoint, a reason, a read-only\n * note and Archive it.\n *\n * `config`:\n * - `title`, `subtitle`, `doneText`: texts, through the host translate;\n * `eyebrow` a template filled from the record (\"Close off · {identifier}\").\n * - `summary`: `{ source?, title, meta?, badge?, icon? }`: templates filled from\n * the record (`source` an endpointSource to read it from, else `object`).\n * - `facts`: `[{ title?, items: [{ label, value }] }]`, `value` a template.\n * - `checklist`: `{ title?, source, itemsPath?, labels?, required? }`: items\n * `{ id, met, label?, detail? }` read from `source`; `labels[id]` gives an\n * item's `{ label, detail?, unmetDetail? }`; the ids in `required` must be\n * met before the action can run. `met: null` reads as unknown.\n * - `permission`: `{ source, listPath?, match?, allowedPath, reasonPath? }`:\n * the action runs only while `allowedPath` reads true; `reasonPath` says\n * why not. With `listPath` the paths read the entry of that list whose\n * fields equal `match` (`{ act: \"archive\" }`).\n * - `fields`: `[{ field, type?: \"text\"|\"date\"|\"datetime\"|\"select\"|\"checkbox\", label?,\n * required?, options?: [{ value, label, fills? }], hint?, default? }]`: inputs\n * sent beside the reason, required by default; a select option's `fills`\n * sets other fields that are still empty. A `checkbox` is sent as a boolean,\n * starts at `default` (false), fills its `label` and `hint` from the record,\n * and is optional unless `required: true` (then it must be ticked). A\n * `search` field finds records of `source: { register, schema }` as the\n * reader types, shows each as `optionLabel` with `optionSecondary` under\n * it (templates on the found record), leaves the record in hand out with\n * `excludeSelf`, and sends the chosen record's id. Every field's `label`,\n * `hint` and `placeholder` (search and select) are templates filled from the record.\n * An optional select or text field (`required: false`) draws its label above\n * the control with \"(optional)\" after it.\n * - `reason`: `{ label?, hint?, required?, field?, rows? }`: a text area; required by\n * default; sent as `field` (default `reason`). `rows` is its height in lines\n * (default 2; board DqBesluit draws 4).\n * - `note`: `{ variant?, title?, text, icon? }`: a read-only note; `icon` an\n * icon name in place of the variant's own (\"LockOutline\").\n * - `confirm`: `{ label, icon?, request?: { method?, url, body? }, action? }`.\n * `request` posts itself (`body` templates filled with the record and\n * `{reason}`); `action` dispatches a manifest action through the page.\n *\n * Tokens (`@objectId`, `@object.<field>`) resolve in every url.\n */\nexport default {\n\tname: 'CnActionDialog',\n\n\tcomponents: { CheckCircle, CircleOutline, CnDialog, CnFormField, CnIcon, CnSearchSelect, HelpCircleOutline, NcButton, NcCheckboxRadioSwitch, NcNoteCard, NcSelect, NcTextArea, NcTextField },\n\n\tinject: {\n\t\t/** The host app's translate (CnAppRoot `cnTranslate`). */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's pre-bound action dispatcher (CnPageRenderer), for `confirm.action`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The dialog's configuration (see the component docs).\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tconfig: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/** The record's id, for the `@objectId` token. */\n\t\tobjectId: {\n\t\t\ttype: [String, Number],\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * The record, when the host has it: the summary and facts read it.\n\t\t *\n\t\t * @type {object|null}\n\t\t */\n\t\tobject: {\n\t\t\ttype: Object,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['close', 'done'],\n\n\tdata() {\n\t\treturn {\n\t\t\trecord: this.object,\n\t\t\titems: [],\n\t\t\tchecklistError: '',\n\t\t\tallowed: true,\n\t\t\treason: '',\n\t\t\tvalues: {},\n\t\t\t/** A search field's found options, by field name. */\n\t\t\tsearchOptions: {},\n\t\t\t/** The search field whose search runs, or ''. */\n\t\t\tsearching: '',\n\t\t\tbusy: false,\n\t\t\trefusal: '',\n\t\t\tdone: false,\n\t\t\treasonId: `cn-action-dialog-reason-${++reasonSeq}`,\n\t\t\tfieldIdPrefix: `cn-action-dialog-field-${reasonSeq}`,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {object} The token context. */\n\t\ttokenCtx() {\n\t\t\treturn { objectId: this.recordId, object: this.record || {} }\n\t\t},\n\n\t\t/**\n\t\t * The record's id: `objectId`, or the route's `id` when the prop is\n\t\t * empty or a token the opener could not resolve.\n\t\t *\n\t\t * @return {string|number}\n\t\t */\n\t\trecordId() {\n\t\t\tconst given = this.objectId\n\t\t\tif (given !== '' && given !== null && given !== undefined && !String(given).startsWith('@')) {\n\t\t\t\treturn given\n\t\t\t}\n\t\t\treturn (this.$route && this.$route.params && this.$route.params.id) || ''\n\t\t},\n\n\t\t/** @return {object} The confirm config. */\n\t\tconfirmConfig() {\n\t\t\treturn this.config.confirm && typeof this.config.confirm === 'object' ? this.config.confirm : {}\n\t\t},\n\n\t\t/**\n\t\t * The summary row, or null without one or before the record is known.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {{title: string, meta: string, badge: string}|null}\n\t\t */\n\t\tsummary() {\n\t\t\tconst def = this.config.summary\n\t\t\tif (!def || !this.record) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst title = this.fill(def.title)\n\t\t\treturn title ? { title, meta: this.fill(def.meta), badge: this.fill(def.badge) } : null\n\t\t},\n\n\t\t/** @return {Array<{title: string, facts: Array<{label: string, value: string}>}>} The fact groups. */\n\t\tfactSections() {\n\t\t\tif (!Array.isArray(this.config.facts) || !this.record) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst empty = t('nextcloud-vue', 'Not set')\n\t\t\treturn this.config.facts.map((section) => ({\n\t\t\t\ttitle: this.text(section.title),\n\t\t\t\tfacts: (Array.isArray(section.items) ? section.items : []).map((fact) => ({ label: this.text(fact.label), value: this.fill(fact.value) || empty })),\n\t\t\t}))\n\t\t},\n\n\t\t/**\n\t\t * The checklist rows: label and detail from `labels` by id, else the item's own.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {Array<{id: string, met: (boolean|null), label: string, detail: string}>}\n\t\t */\n\t\tchecklist() {\n\t\t\tconst labels = (this.config.checklist && this.config.checklist.labels) || {}\n\t\t\treturn this.items.map((item) => {\n\t\t\t\tconst met = item.met === null || item.met === undefined ? null : item.met === true\n\t\t\t\tconst own = labels[item.id] || {}\n\t\t\t\tconst detail = met === false && own.unmetDetail ? own.unmetDetail : (own.detail || item.detail || '')\n\t\t\t\treturn {\n\t\t\t\t\tid: String(item.id),\n\t\t\t\t\tmet,\n\t\t\t\t\tlabel: this.fill(own.label || item.label || String(item.id), item),\n\t\t\t\t\tdetail: met === null && !item.detail ? t('nextcloud-vue', 'Could not be read') : this.fill(detail, item),\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\n\t\t/** @return {boolean} Whether every required item is met. */\n\t\trequiredMet() {\n\t\t\tconst required = (this.config.checklist && Array.isArray(this.config.checklist.required)) ? this.config.checklist.required.map(String) : []\n\t\t\treturn required.every((id) => this.items.some((item) => String(item.id) === id && item.met === true))\n\t\t},\n\n\t\t/** @return {boolean} Whether a reason is asked and needed. */\n\t\treasonNeeded() {\n\t\t\treturn Boolean(this.config.reason) && this.config.reason.required !== false\n\t\t},\n\n\t\t/** @return {string} The reason field's label. */\n\t\treasonLabel() {\n\t\t\treturn this.text(this.config.reason && this.config.reason.label) || t('nextcloud-vue', 'Reason')\n\t\t},\n\n\t\t/** @return {string} The note's NcNoteCard type. */\n\t\tnoteType() {\n\t\t\tconst variant = this.config.note && this.config.note.variant\n\t\t\treturn ['info', 'warning', 'error', 'success'].includes(variant) ? variant : 'info'\n\t\t},\n\n\t\t/**\n\t\t * Whether the action may run: allowed, required items met, a reason\n\t\t * when one is needed, and nothing in flight.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {boolean}\n\t\t */\n\t\tcanConfirm() {\n\t\t\treturn !this.busy && this.allowed && this.requiredMet && this.fieldsFilled && (!this.reasonNeeded || this.reason.trim() !== '')\n\t\t},\n\n\t\t/** @return {string} The eyebrow, filled from the record once it is known. */\n\t\teyebrowText() {\n\t\t\treturn this.record ? this.fill(this.config.eyebrow) || this.text(this.config.eyebrow) : this.text(this.config.eyebrow)\n\t\t},\n\n\t\t/**\n\t\t * The value of every field as sent: a checkbox as a boolean, the\n\t\t * others as entered ('' when empty).\n\t\t *\n\t\t * @return {object} Values by field name.\n\t\t */\n\t\tfieldValues() {\n\t\t\tconst out = { ...this.values }\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tout[field.field] = field.type === 'checkbox' ? this.checkboxValue(field) : (this.values[field.field] ?? '')\n\t\t\t}\n\t\t\treturn out\n\t\t},\n\n\t\t/** @return {Array<object>} The fields with a name. */\n\t\tfields() {\n\t\t\treturn (Array.isArray(this.config.fields) ? this.config.fields : []).filter((f) => f && f.field)\n\t\t},\n\n\t\t/**\n\t\t * Whether every required field has a value.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog-fields-and-acts/specs/action-dialog/spec.md#requirement-an-action-dialog-asks-for-fields-and-reads-a-permission-from-a-list\n\t\t * @return {boolean}\n\t\t */\n\t\tfieldsFilled() {\n\t\t\treturn this.fields.every((f) => {\n\t\t\t\tif (f.type === 'checkbox') {\n\t\t\t\t\treturn f.required !== true || this.checkboxValue(f)\n\t\t\t\t}\n\t\t\t\treturn f.required === false || this.secretStored(f) || String(this.values[f.field] ?? '').trim() !== ''\n\t\t\t})\n\t\t},\n\t},\n\n\twatch: {\n\t\trecord: {\n\t\t\thandler() {\n\t\t\t\tthis.startValues()\n\t\t\t},\n\n\t\t\timmediate: true,\n\t\t},\n\t},\n\n\tasync mounted() {\n\t\tawait Promise.all([this.loadRecord(), this.loadChecklist(), this.loadPermission()])\n\t},\n\n\tbeforeUnmount() {\n\t\tclearTimeout(this.searchTimer)\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Whether a field's label sits above its control with \"(optional)\" after\n\t\t * it: a select or a text field the action does not require.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog-optional-fields/specs/action-dialog/spec.md#requirement-an-optional-field-says-so-beside-its-label\n\t\t * @param {object} field The field.\n\t\t * @return {boolean}\n\t\t */\n\t\tlabelsOutside(field) {\n\t\t\treturn field.required === false && !['checkbox', 'search', 'secret'].includes(field.type)\n\t\t},\n\n\t\t/**\n\t\t * The id of a field's control, which its outside label points at.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {string}\n\t\t */\n\t\tcontrolId(field) {\n\t\t\treturn `${this.fieldIdPrefix}-${field.field}`\n\t\t},\n\n\t\tt,\n\n\t\t/**\n\t\t * A config text through the host translate, '' for anything else.\n\t\t *\n\t\t * @param {unknown} value The text.\n\t\t * @return {string}\n\t\t */\n\t\t/**\n\t\t * Search a search field's records once typing rests.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @param {string} typed What the reader typed.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/action-dialog-search-field/specs/action-dialog-search-field/spec.md#requirement-an-action-dialog-field-can-search-records\n\t\t */\n\t\tonSearch(field, typed) {\n\t\t\tclearTimeout(this.searchTimer)\n\t\t\tthis.searchTimer = setTimeout(() => this.searchRecords(field, String(typed || '').trim()), SEARCH_DELAY)\n\t\t},\n\n\t\t/**\n\t\t * Read the records of a search field's `source` that match the term.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @param {string} term The term.\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync searchRecords(field, term) {\n\t\t\tconst source = field.source || {}\n\t\t\tif (!term || !source.register || !source.schema) {\n\t\t\t\tthis.searchOptions = { ...this.searchOptions, [field.field]: [] }\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.searching = field.field\n\t\t\ttry {\n\t\t\t\tconst url = generateUrl(`/apps/openregister/api/objects/${encodeURIComponent(source.register)}/${encodeURIComponent(source.schema)}`)\n\t\t\t\tconst { data } = await axios.get(url, { params: { _search: term, _limit: 10 } })\n\t\t\t\tconst rows = Array.isArray(data) ? data : (data && Array.isArray(data.results) ? data.results : [])\n\t\t\t\tconst self = String(this.recordId || '')\n\t\t\t\tconst options = rows\n\t\t\t\t\t.map((row) => ({ row, id: String(row.id || (row['@self'] && row['@self'].id) || '') }))\n\t\t\t\t\t.filter(({ id }) => id !== '' && !(field.excludeSelf && id === self))\n\t\t\t\t\t.map(({ row, id }) => {\n\t\t\t\t\t\tconst option = { id, label: this.fill(field.optionLabel || '{title}', row) || id }\n\t\t\t\t\t\tconst secondary = this.fill(field.optionSecondary, row)\n\t\t\t\t\t\treturn secondary ? { ...option, secondary } : option\n\t\t\t\t\t})\n\t\t\t\tthis.searchOptions = { ...this.searchOptions, [field.field]: options }\n\t\t\t} catch {\n\t\t\t\tthis.searchOptions = { ...this.searchOptions, [field.field]: [] }\n\t\t\t} finally {\n\t\t\t\tthis.searching = ''\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * A checkbox field's state: what was ticked, else its `default`.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/action-dialog-checkbox-field/specs/action-dialog-checkbox-field/spec.md#requirement-an-action-dialog-field-can-be-a-checkbox\n\t\t */\n\t\tcheckboxValue(field) {\n\t\t\treturn field.field in this.values ? this.values[field.field] === true : field.default === true\n\t\t},\n\n\t\t/**\n\t\t * Tick or untick a checkbox field.\n\t\t *\n\t\t * @param {string} name The field.\n\t\t * @param {boolean} on Ticked.\n\t\t * @return {void}\n\t\t */\n\t\tsetChecked(name, on) {\n\t\t\tthis.values = { ...this.values, [name]: on === true }\n\t\t},\n\n\t\ttext(value) {\n\t\t\treturn typeof value === 'string' && value !== '' ? this.cnTranslate(value) : ''\n\t\t},\n\n\t\t/**\n\t\t * A template filled from a row (the record by default), translated first.\n\t\t *\n\t\t * @param {unknown} template The template.\n\t\t * @param {object} [row] The row.\n\t\t * @return {string}\n\t\t */\n\t\tfill(template, row) {\n\t\t\tif (typeof template !== 'string' || template === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn fillTemplate(this.cnTranslate(template), row || this.record || {}).trim()\n\t\t},\n\n\t\t/**\n\t\t * Read an endpoint, fresh.\n\t\t *\n\t\t * @param {object} source An endpointSource block.\n\t\t * @return {Promise<unknown>}\n\t\t */\n\t\tread(source) {\n\t\t\treturn fetchEndpointSource(source, this.tokenCtx, { fresh: true })\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadRecord() {\n\t\t\tconst source = this.config.summary && this.config.summary.source\n\t\t\tif (!source || !source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(source)\n\t\t\t\tthis.record = data && typeof data === 'object' ? data : this.record\n\t\t\t} catch {\n\t\t\t\t// The summary stays empty; the checklist and the action still work.\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadChecklist() {\n\t\t\tconst def = this.config.checklist\n\t\t\tif (!def || !def.source || !def.source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(def.source)\n\t\t\t\tconst list = def.itemsPath ? readPath(data, def.itemsPath) : data\n\t\t\t\tthis.items = Array.isArray(list) ? list.filter((item) => item && item.id !== undefined) : []\n\t\t\t} catch {\n\t\t\t\tthis.items = []\n\t\t\t\tthis.checklistError = t('nextcloud-vue', 'Whether this is ready could not be read.')\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The entry of a list whose fields equal `match`, or null.\n\t\t *\n\t\t * @param {unknown} list The list.\n\t\t * @param {object} [match] The fields to match.\n\t\t * @return {object|null}\n\t\t */\n\t\tmatchIn(list, match) {\n\t\t\tconst wanted = Object.entries(match || {})\n\t\t\treturn (Array.isArray(list) ? list : []).find((entry) => entry && wanted.every(([key, value]) => String(entry[key]) === String(value))) || null\n\t\t},\n\n\t\t/**\n\t\t * A select field's options, labels translated.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {Array<{id: string, label: string, fills?: object}>}\n\t\t */\n\t\toptionsOf(field) {\n\t\t\treturn (Array.isArray(field.options) ? field.options : []).map((o) => ({ id: String(o.value), label: this.text(o.label) || String(o.value), fills: o.fills }))\n\t\t},\n\n\t\t/**\n\t\t * A select field's chosen option.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {object|null}\n\t\t */\n\t\tselectedOption(field) {\n\t\t\treturn this.optionsOf(field).find((o) => o.id === String(this.values[field.field] ?? '')) || null\n\t\t},\n\n\t\t/**\n\t\t * Set a field's value.\n\t\t *\n\t\t * @param {string} name The field.\n\t\t * @param {unknown} value The value.\n\t\t */\n\t\tsetValue(name, value) {\n\t\t\tthis.values = { ...this.values, [name]: value === null || value === undefined ? '' : String(value) }\n\t\t},\n\n\t\t/**\n\t\t * Choose a select option; its `fills` set the fields still empty.\n\t\t *\n\t\t * @param {object} field The select field.\n\t\t * @param {{id: string, fills?: object}|null} option The option.\n\t\t */\n\t\tpick(field, option) {\n\t\t\tthis.setValue(field.field, option ? option.id : '')\n\t\t\tfor (const [name, value] of Object.entries((option && option.fills) || {})) {\n\t\t\t\tif (String(this.values[name] ?? '').trim() === '') {\n\t\t\t\t\tthis.setValue(name, this.text(value) || value)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/** @return {Promise<void>} */\n\t\tasync loadPermission() {\n\t\t\tconst def = this.config.permission\n\t\t\tif (!def || !def.source || !def.source.url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst data = await this.read(def.source)\n\t\t\t\tconst entry = def.listPath ? this.matchIn(readPath(data, def.listPath), def.match) : data\n\t\t\t\tthis.allowed = readPath(entry, def.allowedPath || 'allowed') === true\n\t\t\t\tthis.refusal = this.allowed || !def.reasonPath ? '' : String(readPath(entry, def.reasonPath) || '')\n\t\t\t} catch {\n\t\t\t\tthis.allowed = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Run the action once: post `confirm.request`, or dispatch\n\t\t * `confirm.action`, then show the done text and refresh the page.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog/specs/action-dialog/spec.md#requirement-a-manifest-configures-an-action-dialog\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync confirm() {\n\t\t\tif (!this.canConfirm) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.busy = true\n\t\t\tthis.refusal = ''\n\t\t\tconst reason = this.reason.trim()\n\t\t\ttry {\n\t\t\t\tconst request = this.confirmConfig.request\n\t\t\t\tif (request && request.url) {\n\t\t\t\t\tconst url = interpolateUrlTokens(request.url, this.tokenCtx)\n\t\t\t\t\tconst body = {}\n\t\t\t\t\tfor (const [key, value] of Object.entries(request.body || {})) {\n\t\t\t\t\t\tbody[key] = typeof value === 'string' ? fillTemplate(value, { ...(this.record || {}), reason }) : value\n\t\t\t\t\t}\n\t\t\t\t\tif (this.config.reason) {\n\t\t\t\t\t\tbody[this.config.reason.field || 'reason'] = reason\n\t\t\t\t\t}\n\t\t\t\t\tconst values = { ...this.fieldValues }\n\t\t\t\t\tfor (const field of this.fields) {\n\t\t\t\t\t\tif (field.type === 'secret' && String(this.values[field.field] ?? '') === '') {\n\t\t\t\t\t\t\tdelete values[field.field]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tObject.assign(body, values)\n\t\t\t\t\tconst method = String(request.method || 'POST').toLowerCase()\n\t\t\t\t\tawait axios[['post', 'put', 'patch', 'delete'].includes(method) ? method : 'post'](/^https?:\\/\\//i.test(url) ? url : generateUrl(url), body)\n\t\t\t\t} else if (this.confirmConfig.action && typeof this.cnDispatchAction === 'function') {\n\t\t\t\t\tawait this.cnDispatchAction({ ...this.confirmConfig.action, args: [...(this.confirmConfig.action.args || []), { ...this.fieldValues, reason }] })\n\t\t\t\t}\n\t\t\t\tthis.done = true\n\t\t\t\temit(PAGE_REFRESH, {})\n\t\t\t\t/** @event done The action ran. Payload: the field values and `reason`. */\n\t\t\t\tthis.$emit('done', { ...this.fieldValues, reason })\n\t\t\t} catch (failure) {\n\t\t\t\tconst data = failure && failure.response && failure.response.data\n\t\t\t\tthis.refusal = String((data && (data.message || data.error)) || t('nextcloud-vue', 'The action could not be completed.'))\n\t\t\t} finally {\n\t\t\t\tthis.busy = false\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Start each field with `valuePath` from the record, unless it was\n\t\t * already edited.\n\t\t *\n\t\t * @spec openspec/changes/action-dialog-secret-field/specs/action-dialog/spec.md#requirement-a-field-can-start-from-the-record-and-a-secret-is-write-only\n\t\t * @return {void}\n\t\t */\n\t\tstartValues() {\n\t\t\tif (!this.record) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst values = { ...this.values }\n\t\t\tfor (const field of this.fields) {\n\t\t\t\tif (field.valuePath && field.type !== 'secret' && !(field.field in values)) {\n\t\t\t\t\tconst value = readPath(this.record, field.valuePath)\n\t\t\t\t\tif (value !== null && value !== undefined) {\n\t\t\t\t\t\tvalues[field.field] = String(value)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.values = values\n\t\t},\n\n\t\t/**\n\t\t * Whether a secret field has a value stored: `storedPath` reads true on the record.\n\t\t *\n\t\t * @param {object} field The field.\n\t\t * @return {boolean}\n\t\t */\n\t\tsecretStored(field) {\n\t\t\treturn field.type === 'secret' && Boolean(field.storedPath && this.record && readPath(this.record, field.storedPath))\n\t\t},\n\n\t\t/** Close the dialog, unless the action is running. */\n\t\tclose() {\n\t\t\tif (this.busy) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\t/** @event close The dialog was closed. */\n\t\t\tthis.$emit('close')\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-action-dialog {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 16px;\n}\n\n.cn-action-dialog__summary {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 10px);\n}\n\n/* The record's icon on a tinted tile (DqArchiveren). */\n.cn-action-dialog__summary-icon {\n\tdisplay: flex;\n\tflex: none;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 36px;\n\theight: 36px;\n\tborder-radius: 8px;\n\tbackground: var(--color-primary-element-light);\n\tcolor: var(--color-primary-element-light-text);\n}\n\n.cn-action-dialog__summary-text strong {\n\tfont-size: 15px;\n\tfont-weight: 600;\n}\n\n.cn-action-dialog__summary-text .cn-action-dialog__muted {\n\tfont-size: 13px;\n}\n\n.cn-action-dialog__summary-text {\n\tdisplay: flex;\n\tflex: 1 1 auto;\n\tflex-direction: column;\n\tmin-width: 0;\n}\n\n.cn-action-dialog__badge {\n\tpadding: 3px 10px;\n\tborder-radius: 12px;\n\tbackground: var(--color-background-dark);\n\tfont-size: 13px;\n\tfont-weight: 600;\n\twhite-space: nowrap;\n}\n\n.cn-action-dialog__title {\n\tmargin: 0 0 8px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n}\n\n/* Facts in columns of at least 200px, each a label over its value above a\n hairline (DqArchiveren \"Bewaring volgens het zaaktype\"). */\n.cn-action-dialog__facts {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n\tgap: 12px 24px;\n\tmargin: 0;\n}\n\n.cn-action-dialog__fact {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 3px;\n\tpadding-bottom: 10px;\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n/* The server draws every dt as a 130px right-aligned inline block and pads\n dt and dd 12px; a fact is a label over its value. */\n.cn-action-dialog__facts dt,\n.cn-action-dialog__facts dd {\n\tdisplay: block;\n\twidth: auto;\n\twhite-space: normal;\n\ttext-align: start;\n}\n\n.cn-action-dialog__facts dt {\n\tmargin: 0;\n\tpadding: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-action-dialog__facts dd {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-size: 15px;\n\tfont-weight: 500;\n}\n\n/* Checklist rows divided by hairlines, the detail at the row's end\n (DqArchiveren \"Klaar om te archiveren\"). */\n.cn-action-dialog__checks {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-action-dialog__check {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 2px 12px;\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--color-border);\n\tfont-size: 15px;\n}\n\n.cn-action-dialog__check-label {\n\tflex: 1 1 auto;\n\tfont-weight: 600;\n}\n\n.cn-action-dialog__check-icon {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-action-dialog__check-icon--met {\n\tcolor: var(--color-success-text, var(--color-success));\n}\n\n.cn-action-dialog__muted {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n/* A checkbox field is a tinted box with a 2px edge, its label bold and its\n hint under it (DqArchiveren). */\n.cn-action-dialog__checkbox {\n\tpadding: 12px 14px;\n\tborder: 2px solid var(--color-primary-element);\n\tborder-radius: var(--border-radius-element, 8px);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-action-dialog__checkbox-text {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-action-dialog__checkbox-label {\n\tfont-size: 15px;\n\tfont-weight: 600;\n}\n\n.cn-action-dialog__checkbox .cn-action-dialog__muted {\n\tfont-size: 13px;\n}\n\n.cn-action-dialog__field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n\n.cn-action-dialog__error {\n\tmargin: 0;\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createVNode","_createBlock","_createTextVNode","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_Fragment","_renderList"],"mappings":";;;;AAiBoB,EAAA,KAAK,EAAC,kBAAkB;;;;AAErB,EAAA,KAAK,EAAC,2BAAmB;AAAA,EAAA,aAAA,EAAA,0BAAA;;AACtC,MAAA,UAAA,GAAA,EAAA,KAAM,EAAA,gCAAwB,GAAA;AAG9B,MAAA,UAAA,GAAA,EAAA,KAAK,EAAC,gCAAgC,GAAA;;;;;;;AAIjB,EAAA,KAAK,EAAC,yBAAc;;;;AAQtB,EAAA,KAAK,EAAC,yBAAyB;;AAGpD,MAAA,UAAA,GAAA,EAAA,KAAE,EAAA,yBAAA,GAAA;;;AAW0B,EAAA,KAAK,EAAC,2BAA2B;AAAC,EAAA,aAAI,EAAA,4BAAA;;;;AAClD,EAAA,KAAA,EAAA,yBAAA;;;;AAGK,EAAA,KAAI,EAAA,yBAAA;AAAA,EAAA,IAAA,EAAA,QAAA;;AAGzB,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,0BAA0B,GAAA;;AAS5B,MAAA,WAAA,GAAA,EAAA,KAAA,EAAA,+BAAA,GAAA;;;;;;AAmBD,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,iCAAU,GAAA;AACb,MAAA,WAAA,GAAA,EAAA,KAAK,EAAC,kCAAkC,GAAA;;;AACvB,EAAA,KAAI,EAAE,yBAAc;;;;AA6CrC,EAAA,KAAA,EAAA,yBAAA;;;;AAGU,EAAA,KAAA,EAAA,yBAAA;;;;AASL,EAAA,KAAA,EAAA,yBAAA;;;;AAcf,EAAA,KAAE,EAAA,yBAAA;AACF,EAAA,IAAG,EAAA,OAAA;;;;;AAMK,EAAA,IAAI,EAAC,QAAG;AAAA,EAAA,aAAA,EAAA,uBAAA;;;;;;;;;;;;;;;;;;;AA1JjB,IAAA,IAAI,EAAE,QAAI,CAAA,IAAA,CAAC,aAAE,CAAA,KAAA,KAAA,QAAA,CAAA,CAAA,CAAA,eAAA,EAAA,SAAA,CAAA;AACb,IAAA,OAAO,EAAE,QAAW,CAAA,WAAA;AACpB,IAAA,QAAQ,EAAE,QAAA,CAAA,IAAI,CAAC,MAAA,CAAA,MAAA,CAAA,QAAA,CAAA;AAChB,IAAA,KAAK,EAAC,MAAM;AACX,IAAA,OAAO,EAAE,KAAI,CAAA,IAAA;AACb,IAAA,aAAU,EAAC,kBAAkB;AAC5B,IAAA,SAAM,EAAE,QAAK,CAAA,KAAA;;AAwJJ,IAAA,OAAO,UAChB,MAEU;MAFVA,WAEU,CAAA,mBAAA,EAAA;AAFA,QAAA,QAAM,EAAA,KAAA,CAAA,IAAA;AAAA,QAAA,aAAA,EAAA,yBAAA;AAAA,QAAA,OAAA,EAAA,QAAA,CAAA,KAAA;;yBAChB,MAAsB;0CAAnB,KAAI,CAAA,IAAA,GAAG,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,OAAA,CAAA,GAAW,QAAA,CAAA,CAAA,CAAA,eAAA,EAAA,QAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;QAEN,KAAA,CAAA,IAAA;wBAAhBC;;AACA,YAAA,OAAO,EAAC,SAAS;AAChB,YAAA,QAAQ,GAAG,QAAU,CAAA,UAAA;AACtB,YAAA,aAAU,EAAA,0BAAA;AACT,YAAA,OAAK,EAAE,QAAO,CAAA,OAAA;;6BAGR;AAAA,cAAAC,eAAA,CAAA;;;;AAFE,YAAA,CAAA,QAAA,CAAA,aAAA,CAAA,IAAA;;wBAAA,MAAA;8BACR,MAAO;oBAAPF,WAAO,CAAA,iBAAA,EAAA;sBAAA,IAAA,EAAA,QAAA,CAAA,aAAA,CAAA,IAAA;AAAA,sBAAA,IAAA,EAAA,EAAA;;;;;;;;;qBAjKP,MAiJA;QAjJS,KAAI,CAAA,IAAA;AAAb,WAAAG,SAAA,EAAA,EAAAC,kBAAA,CAiJA,OAjJA,UAiJA,EAAA;aA/IS,QAAO,CAAA,OAAA;AAAjB,iBAAAD,SAAA,EAAA,EAAAC,kBAAA,CASK,OATL,UASK,EAAA;AARJ,kBAAAC,kBAAA,CAEK,QAFL,UAEK,EAAA;oBADLL,WAAoE,CAAA,iBAAA,EAAA;AAA3D,sBAAA,IAAI,EAAE,MAAA,CAAA,MAAM,CAAC,OAAO,CAAC,IAAI,IAAA,eAAA;AAAsB,sBAAA,IAAK,EAAC,EAAE;;;AAEjE,kBAAAK,kBAAA,CAGO,QAHP,UAGO,EAAA;oBAFNA,kBAAG,CAAA,QAAA,EAAA,IAAA,EAAAC,eAAA,CAAA,QAAA,CAAA,OAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;;;;;AAGQ,kBAAA,CAAA,QAAA,CAAA,OAAO,CAAC,KAAK;AAAzB,uBAAAH,SAAA,EAAA,EAAAC,kBAAA,CAA+C,MAA/C,EAAA,UAA+C,EAAAE,eAAA,CAAA,QAAA,CAAA,OAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;;;;iDAiBtCC,QAb0B,EAAA,IAAA,EAAAC,UAAA,CAAA,QAAA,CAAA,YAAY,EAA/B,CAAA,OAAO,EAAE,KAAK,KAAA;qDAarB,CAAA,SAAA,EAAA;AAZR,gBAAA,GAAG,WAAW,KAAI,CAAA,CAAA;AACnB,gBAAA,KAAI,EAAA,2BAAA;AACJ,gBAAA,aAAW,EAAC,wBAAuB;;AACzB,gBAAA,CAAA,OAAQ,CAAA,KAAK;AAAtB,qBAAAL,SAAA,EAAA,EAAAC,kBAAA,CAEI,IAFJ,EAAA,UAEI,EADDE,eAAA,CAAA,OAAO,CAAC,KAAK,CAAA,EAAA,CAAA,YAAA;;mCAOZ,gBAAA,EAAA;AAJJ,mBAAAH,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA,SAAG,EAAA,IAAA,EAAAI,UAAA,CAAA,OAAA,CAAA,KAAA,GAAA,IAAA,KAAA;yCAAHJ;sBAAG,GAAA,EAAA,IAAA,CAAA,KAAA;AAAA,sBAAA,KAAA,EAAA,wBAAA;;sBACFC,kBAAM,CAAA,IAAA,EAAA,IAAA,EAAAC,eAAA,CAAA,IAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;AASM,YAAA,CAAA,MAAA,CAAA,MAAM,CAAC,SAAS;AAA9B,iBAAAH,SAAA,EAAA,EAAAC,kBAAA,CAoBS,WApBT,UAoBS,EAAA;mBAnBC,MAAM,CAAA,MAAA,CAAC,SAAG,CAAA,KAAA;oCAAnBA,kBAEI,CAAA,IAAA,EAFJ,WAEI,EADFE,eAAA,CAAA,QAAA,CAAA,IAAA,CAAA,MAAA,CAAA,MAAA,CAAA,SAAA,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;mBAEM,KAAc,CAAA,cAAA;sDAEnB,CAAA,GAAA,aAAA,EAAAA,eAAA,CADA,KAAW,CAAA,cAAA,CAAA,EAAA,CAAA,YAAA;;qCAcV,iBAAA,EAAA;wDADC,CAAAC,QAAA,EAAA,IAAA,EAAAC,UAAA,CAVc,QAAS,CAAA,SAAA,EAAA,CAAjB,IAAI,KAAA;6DAUV,CAAA,IAAA,EAAA;wBATH,GAAG,EAAE,IAAI,CAAC,EAAE;AACb,wBAAA,KAAK,EAAC,yBAAyB;wBAC9B,aAAW,EAAA,CAAA,uBAAA,EAA4B,IAAI,CAAC,EAAE,CAAA,CAAA;AAC9C,wBAAA,UAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAA;;AACP,wBAAA,CAAA,IAAI,CAAA,GAAI,KAAA,IAAA;0CAA3BP,WAAgF,CAAA,sBAAA,EAAA;;AAAzC,8BAAA,IAAI,EAAE,EAAE;AAAE,8BAAA,KAAK,EAAC,gEAAyB;;AAC7E,4BAAA,CAAA,IAAA,CAAA,GAAA,KAAA,IAAA;4CAAHA,WAAG,CAAA,4BAAA,EAAA;;AAAA,gCAAA,IAAA,EAAA,EAAA;AAAA,gCAAA,KAAA,EAAA,8BAAA;;4CACHA,WAAE,CAAA,wBAAA,EAAA;;AAAA,gCAAA,IAAA,EAAA,EAAA;AAAA,gCAAA,KAAA,EAAA,8BAAA;;AACF,wBAAAI,kBAAA,CAAM,QAAN,EAAA,WAAM,EAAAC,eAAA,CAAA,IAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;;;;;;;;;gDAmEH,CAAAC,QAAA,EAAA,IAAA,EAAAC,UAAA,CA5De,QAAM,CAAA,MAAA,EAAA,CAAf,KAAK,KAAA;qDA4DX,CAAA,KAAA,EAAA;qBA3DC,KAAK,CAAE,KAAI;qBACZ,EAAC,yBAAa;gBAClB,aAAW,EAAA,CAAA,uBAAA,EAA4B,KAAK,CAAC,KAAK,CAAA,CAAA;;AAItB,gBAAA,CAAA,KAAK,CAAC,IAAI,KAAA,UAAA;6CASf,CAAA,gCAAA,EAAA;;AARvB,sBAAA,OAAM,4BAA4B;sBACjC,UAAU,EAAE,QAAa,CAAA,aAAA,CAAC,KAAK,CAAA;AAC/B,sBAAA,IAAG,EAAC,UAAU;sBACd,qBAAK,EAAA,CAAA,EAAA,KAAA,QAAA,CAAA,UAAA,CAAA,KAAA,CAAA,KAAA,EAAA,EAAA,CAAA;;uCACN,MAGO;AAHP,wBAAAH,kBAAA,CAGO,QAHP,WAGO,EAAA;0BAFNA,kBAAyD,CAAA,QAAA,EAAzD,WAAyD,EAAAC,eAAA,CAAL,QAAI,CAAA,IAAA,CAAC,KAAA,CAAA,KAAA,CAAA,IAAA,KAAA,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;AAC7C,0BAAA,CAAA,KAAK,CAAC,IAAI;AAAnB,+BAAAH,SAAA,EAAA,EAAAC,kBAAA,CAA0C,QAA1C,WAA0C,EAAAE,eAAA,CAAA,aAAA,CAAA,KAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;;;AAK3B,oBAAA,CAAA,KAAA,CAAA,IAAA,KAAA,QAAA;oCAAnBL,WASsC,CAAA,yBAAA,EAAA;;AARrC,wBAAA,UAAU,EAAE,KAAA,CAAA,MAAO,CAAA,KAAK,CAAC,KAAK,CAAA,IAAA,IAAA;AAC9B,wBAAA,OAAO,EAAE,KAAA,CAAA,aAAQ,CAAA,KAAA,CAAA,KAAA,CAAA,IAAA,EAAA;wBACjB,UAAU,EAAE,aAAI,CAAC,KAAK,CAAC,KAAK,CAAA,IAAK,KAAG,CAAA,KAAA;AACpC,wBAAA,YAAY,EAAE,IAAK;AACnB,wBAAA,OAAO,EAAE,KAAA,CAAA,SAAS,KAAK,KAAK,CAAA,KAAM;AAClC,wBAAA,UAAU,EAAE,KAAK;mCACN,EAAE,QAAA,CAAA,IAAI,CAAE,KAAG,CAAE,WAAW,CAAA;AAChC,wBAAA,QAAG,GAAG,KAAK,KAAK,iBAAA,CAAA,KAAA,EAAA,KAAA,CAAA;AACnB,wBAAA,qBAAiB,GAAG,KAAK,KAAK,QAAO,CAAA,QAAA,CAAA,KAAA,CAAA,KAAA,EAAA,KAAA,WAAA,KAAA,KAAA,QAAA,GAAA,KAAA,CAAA,EAAA,GAAA,KAAA,CAAA;;;AAIpB,gBAAA,CAAA,QAAA,CAAA,aAAa,CAAC,KAAK,CAAA;kCAAtCA,WAGoB,CAAA,sBAAA,EAAA;;sBAFlB,SAAS,EAAE,QAAS,CAAA,SAAA,CAAC,KAAK,CAAA;sBAC1B,IAAI,EAAE,aAAI,CAAC,KAAK,CAAC,KAAK,CAAA,IAAG,KAAA,CAAA,KAAA;AACzB,sBAAA,QAAQ,EAAE,IAAI;;;AACA,gBAAA,CAAA,KAAK,CAAC,IAAI,KAAA,QAAA;kCAAzBA,WAQ0B,CAAA,mBAAA,EAAA;;sBAPzB,UAAU,EAAE,QAAc,CAAA,cAAA,CAAC,KAAK,CAAA;sBAChC,OAAO,EAAE,QAAS,CAAA,SAAA,CAAC,KAAK,CAAA;sBACxB,OAAO,EAAE,QAAS,CAAA,SAAA,CAAC,KAAK,CAAA;sBACxB,UAAU,EAAE,aAAI,CAAC,KAAK,CAAC,KAAK,CAAA,IAAK,KAAK,CAAC,KAAK;sBAC5C,YAAY,EAAE,QAAa,CAAA,aAAA,CAAC,KAAK,CAAA;AACjC,sBAAA,WAAW,EAAE,QAAA,CAAA,IAAI,CAAC,KAAK,CAAC,WAAW,CAAA;sBACnC,SAAS,EAAE,KAAE,CAAA,QAAA,KAAA,KAAA;AACb,sBAAA,qBAAiB,GAAG,MAAK,KAAA,aAAA,CAAA,KAAA,EAAA,MAAA,CAAA;;AACH,oBAAA,CAAA,MAAM,IAAI,KAAA,QAAA;oCAAjCA,WAM+D,CAAA,sBAAA,EAAA;;AAL9D,wBAAA,UAAU,EAAE,KAAA,CAAA,MAAM,CAAC,KAAK,CAAC,KAAK,CAAA,IAAA,EAAA;AAC/B,wBAAA,IAAI,EAAC,UAAU;AACf,wBAAA,YAAY,EAAC,cAAc;wBAC1B,KAAK,EAAE,aAAI,CAAC,KAAK,CAAC,KAAE,CAAA,IAAA,KAAA,CAAA,KAAA;AACpB,wBAAA,WAAW,EAAE,QAAA,CAAA,YAAY,CAAC,KAAI,IAAK,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,yCAAA,CAAA,GAAA,EAAA;wBACpC,qBAAiB,EAAA,CAAE,KAAM,KAAK,QAAA,CAAA,QAAQ,CAAC,KAAK,CAAC,KAAM,EAAA,KAAM,CAAA;;AACnC,sBAAA,CAAA,MAAM,IAAI,KAAO,UAAA,IAAA,KAAA,CAAA,IAAA,KAAA,QAAA;sCAAxCA,WAMuD,CAAA,sBAAA,EAAA;;0BALtD,EAAE,EAAE,QAAS,CAAA,SAAA,CAAC,KAAK,CAAA;AACnB,0BAAA,UAAU,EAAE,KAAA,CAAA,MAAM,CAAC,KAAK,CAAC,KAAK,CAAA,IAAA,EAAA;AAC9B,0BAAA,IAAI,EAAE,KAAK,CAAC,IAAI,KAAsC,UAAA,GAAA,gBAAA,IAAA,KAAK,CAAC,IAAI,KAAA,MAAA,GAAA,MAAA,GAAA,MAAA,CAAA;0BAChE,KAAE,EAAA,aAAA,CAAA,KAAA,CAAA,KAAA,CAAA,IAAA,KAAA,CAAA,KAAA;;0BAEF,qBAAiB,EAAA,CAAG,KAAK,KAAK,QAAA,CAAA,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,KAAE,CAAA;;;AAC9C,gBAAA,CAAA,KAAA,CAAA,IAAA,IAAA,KAAA,CAAA,IAAA,KAAA,UAAA;AAAV,qBAAAE,SAAA,EAAA,EAAAC,kBAAA,CAAU,QAAV,WAAU,EAAAE,eAAA,CAAA,aAAA,CAAA,KAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;AAGA,YAAA,CAAA,MAAA,CAAA,MAAM,CAAC,MAAG;AAAnB,iBAAAH,SAAA,EAAA,EAAAC,kBAAA,CAUI,OAVJ,WAUI,EAAA;kBATJJ,WAO2B,CAAA,qBAAA,EAAA;AAN1B,oBAAA,EAAE,EAAE,KAAQ,CAAA,QAAA;gCACJ,KAAM,CAAA,MAAA;iFAAN,KAAM,CAAA,MAAA,IAAA,MAAA,CAAA,CAAA;AACd,oBAAA,KAAK,EAAE,QAAW,CAAA,WAAA;AAClB,oBAAA,YAAY,EAAE,KAAK;AACnB,oBAAA,IAAE,EAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,IAAA,IAAA,CAAA;;AAEH,oBAAA,aAAW,EAAC,yBAAe;;mBAChB,MAAG,CAAA,MAAA,CAAA,MAAA,CAAA,IAAA;oCAAfI,kBAAe,CAAA,MAAA,EAAf,WAAe,EAAAE,eAAA,CAAA,QAAA,CAAA,IAAA,CAAA,MAAA,CAAA,MAAA,CAAA,MAAA,CAAA,IAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;AAGE,YAAA,CAAA,MAAA,CAAA,MAAM,CAAC,IAAI;8BAA5BL,WAQW,CAAA,qBAAA,EAAA;;AAPV,kBAAA,IAAI,EAAE,QAAQ,CAAA,QAAA;AACd,kBAAA,OAAO,EAAE,QAAA,CAAA,IAAA,CAAA,aAAA,CAAA,IAAA,CAAA,KAAA,CAAA;AACV,kBAAA,aAAW,EAAC,uBAAe;;mCAGhB,MACX;AADW,oBAAAC,eAAA,CAAA,GACX,mBAAG,QAAI,CAAA,IAAA,CAAC,aAAM,CAAC,IAAI,CAAC,IAAI,CAAA,CAAA,EAAA,CAAA,YAAA;;;;mBAHb,MAAA,CAAA,MAAA,CAAA,IAAA,CAAA,IAAA;;8BAAA,MAAA;;;;;;;;;;;;aAMH,KAAI,CAAA,OAAA;gDAKT,CAAA,GAAA,aAAA,EAAAI,eAAA,CADA,KAAO,CAAA,OAAA,CAAA,EAAA,CAAA,YAAA;;;wBAIZF,kBAEK,CAAA,GAAA,EAFL,WAEK,EADDE,eAAA,CAAA,QAAA,CAAA,IAAI,CAAC,MAAM,CAAA,MAAA,CAAC,QAAQ,CAAA,IAAK,QAAC,CAAA,CAAA,CAAA,eAAA,EAAA,MAAA,CAAA,CAAA,EAAA,CAAA,YAAA,CAAA;;;;;;;;"}
@@ -2,7 +2,7 @@ import script from './CnAdminSettingsShell.vue2.js';
2
2
  import { render } from './CnAdminSettingsShell.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-1c972024";
5
+ script.__scopeId = "data-v-447d33ea";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };
@@ -540,6 +540,15 @@ var script = {
540
540
  type: Object,
541
541
  default: () => ({}),
542
542
  },
543
+
544
+ /**
545
+ * The board look's version card title size in px, when the app's board
546
+ * draws it other than 17px (PqBeheer 19, OcInstellingen 18).
547
+ */
548
+ versionTitleSize: {
549
+ type: Number,
550
+ default: 0,
551
+ },
543
552
  },
544
553
 
545
554
  emits: ['update', 'reimported', 'reimport-error', 'tab-change'],
@@ -1 +1 @@
1
- {"version":3,"file":"CnAdminSettingsShell.vue2.js","sources":["../../../../src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue"],"sourcesContent":["<template>\n\t<div class=\"cn-admin-settings-shell\" :class=\"[ownLookClass, sectionColumns ? `cn-admin-settings-shell--columns-${sectionColumns}` : '']\">\n\t\t<!-- Names a development, test or acceptance environment; cannot be dismissed. Production shows nothing. -->\n\t\t<CnEnvironmentBanner v-if=\"environmentName\" :environment=\"environmentName\" />\n\n\t\t<!-- Page title header — the uniform \"<App> Settings / Configure your <App> installation\" block.\n\t\t Uses NcSettingsSection directly (not CnSettingsSection) so the description subtitle and\n\t\t doc-url icon render — CnSettingsSection repurposes those props and does not forward them. -->\n\t\t<NcSettingsSection\n\t\t\tv-if=\"!isBoard\"\n\t\t\t:name=\"resolvedTitle\"\n\t\t\t:description=\"resolvedDescription\"\n\t\t\t:docUrl=\"docUrl\" />\n\n\t\t<!-- The board header: an h1 and its description, then the labelled\n\t\t Documentation button and the buildiq square. No documentation icon\n\t\t beside the title. -->\n\t\t<div v-else class=\"cn-admin-settings-shell__header\" data-testid=\"cn-admin-settings-header\">\n\t\t\t<div class=\"cn-admin-settings-shell__heading\">\n\t\t\t\t<h1 class=\"cn-admin-settings-shell__title\">\n\t\t\t\t\t{{ resolvedTitle }}\n\t\t\t\t</h1>\n\t\t\t\t<!-- `breadcrumbs`: the board's path line in place of the\n\t\t\t\t description (\"Beheerinstellingen / Launchpad / Algemeen ·\n\t\t\t\t geldt voor de hele organisatie\"). -->\n\t\t\t\t<div v-if=\"crumbs.length > 0\" class=\"cn-admin-settings-shell__crumbs\" data-testid=\"cn-admin-settings-breadcrumbs\">\n\t\t\t\t\t<nav class=\"cn-admin-settings-shell__crumb-list\" :aria-label=\"breadcrumbLabel\">\n\t\t\t\t\t\t<template v-for=\"(crumb, index) in crumbs\" :key=\"index\">\n\t\t\t\t\t\t\t<span v-if=\"index > 0\" aria-hidden=\"true\">/</span>\n\t\t\t\t\t\t\t<a v-if=\"crumb.href\" :href=\"crumb.href\" class=\"cn-admin-settings-shell__crumb-link\">{{ crumb.label }}</a>\n\t\t\t\t\t\t\t<span v-else :aria-current=\"index === crumbs.length - 1 ? 'page' : null\">{{ crumb.label }}</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</nav>\n\t\t\t\t\t<template v-if=\"breadcrumbNote\">\n\t\t\t\t\t\t<span aria-hidden=\"true\">·</span>\n\t\t\t\t\t\t<span>{{ breadcrumbNote }}</span>\n\t\t\t\t\t</template>\n\t\t\t\t</div>\n\t\t\t\t<p v-else class=\"cn-admin-settings-shell__description\">\n\t\t\t\t\t{{ resolvedDescription }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<div class=\"cn-admin-settings-shell__header-buttons\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"docUrl\"\n\t\t\t\t\t:href=\"docUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\tdata-testid=\"cn-admin-settings-documentation\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<BookOpenVariant :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ documentationLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<CnBuildiqEditButton />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- `tabs`: a strip under the header (boards ShInstellingen,\n\t\t LpBeheerAlgemeen). Each tab's panel holds the `tab-<id>` slot; the\n\t\t version card, the credential broker and the default slot below\n\t\t belong to the first tab and show only while it is open. -->\n\t\t<CnTabs\n\t\t\tv-if=\"tabItems.length > 0\"\n\t\t\tclass=\"cn-admin-settings-shell__tabs\"\n\t\t\t:class=\"{ 'cn-admin-settings-shell__tabs--bare': openPanelIsEmpty }\"\n\t\t\t:look=\"isBoard ? 'board' : 'nextcloud'\"\n\t\t\t:variant=\"tabsVariant\"\n\t\t\t:ariaLabel=\"resolvedTitle\"\n\t\t\tdata-testid=\"cn-admin-settings-tabs\"\n\t\t\t@update:activeIndex=\"onTabIndex\">\n\t\t\t<CnTab\n\t\t\t\tv-for=\"tab in tabItems\"\n\t\t\t\t:key=\"tab.id\"\n\t\t\t\t:title=\"tab.label\"\n\t\t\t\t:count=\"tab.count\"\n\t\t\t\t:active=\"tab.id === activeTabId\">\n\t\t\t\t<div class=\"cn-admin-settings-shell__panel\" :data-tab=\"tab.id\">\n\t\t\t\t\t<!-- @slot tab-<id> The panel of the tab with that `id` in `tabs`. -->\n\t\t\t\t\t<slot v-if=\"!lazyTabs || tab.id === activeTabId\" :name=\"`tab-${tab.id}`\" />\n\t\t\t\t</div>\n\t\t\t</CnTab>\n\t\t</CnTabs>\n\n\t\t<!-- `versionCardPosition: \"end\"`: the app's sections come first, and the\n\t\t version card and the credential broker follow them (board DcBeheer\n\t\t starts with the app's own card). The same slot, rendered once. -->\n\t\t<slot v-if=\"versionCardAtEnd && onFirstTab\" />\n\n\t\t<!-- Version information card (version, up-to-date check, re-import, support footer) -->\n\t\t<CnVersionInfoCard\n\t\t\tv-if=\"showVersionCard && onFirstTab\"\n\t\t\t:appName=\"appName\"\n\t\t\t:appVersion=\"resolvedVersion\"\n\t\t\t:configuredVersion=\"resolvedConfiguredVersion\"\n\t\t\t:isUpToDate=\"resolvedIsUpToDate\"\n\t\t\t:showUpdateButton=\"showUpdateButton\"\n\t\t\t:updating=\"updating\"\n\t\t\t:title=\"versionTitle\"\n\t\t\t:description=\"resolvedVersionDescription\"\n\t\t\t:wide=\"versionCardWide\"\n\t\t\t:showAppName=\"showAppName\"\n\t\t\t:actionsDivider=\"actionsDivider\"\n\t\t\t:inlineUpToDate=\"inlineUpToDate\"\n\t\t\t:compact=\"compact\"\n\t\t\t@update=\"onUpdate\">\n\t\t\t<template #actions>\n\t\t\t\t<!-- Canonical \"Re-import configuration\" action (POST /apps/<appId>/api/settings/load) -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showReimport\"\n\t\t\t\t\t:variant=\"compactCard ? 'secondary' : 'primary'\"\n\t\t\t\t\t:disabled=\"reimporting\"\n\t\t\t\t\t@click=\"reimport\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcLoadingIcon v-if=\"reimporting\" :size=\"20\" />\n\t\t\t\t\t\t<Refresh v-else :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ reimporting ? importingLabel : reimportLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- Run the first-time setup wizard on demand (ADR-042). -->\n\t\t\t\t<NcButton v-if=\"showSetup\" data-testid=\"cn-admin-run-setup\" @click=\"setupWizardOpen = true\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<AutoFix :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ setupLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- \"Help us / suggest a feature\" — a direct link to the forge's\n\t\t\t\t feature-request issue form (team decision 2026-09-04: the\n\t\t\t\t in-product suggestion modal is gone; the forge is where\n\t\t\t\t the conversation happens, in English). -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showHelp && helpUrl\"\n\t\t\t\t\t:href=\"helpUrl\"\n\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<HelpCircleOutline :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ helpLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- @slot actions Extra action buttons rendered next to the built-in update / re-import buttons in the version card header. -->\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t</template>\n\n\t\t\t<template #footer>\n\t\t\t\t<!-- @slot footer Replaces the default support/SLA footer inside the version card. -->\n\t\t\t\t<slot name=\"footer\">\n\t\t\t\t\t<div v-if=\"showSupport && !supportAtEnd && !compactCard\" class=\"cn-support-info\">\n\t\t\t\t\t\t<h4>{{ supportTitle }}</h4>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t{{ supportLine }}\n\t\t\t\t\t\t\t<a :href=\"`mailto:${supportEmail}`\">{{ supportEmail }}</a>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"slaEmail\">\n\t\t\t\t\t\t\t{{ slaLine }}\n\t\t\t\t\t\t\t<a :href=\"`mailto:${slaEmail}`\">{{ slaEmail }}</a>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</slot>\n\t\t\t</template>\n\n\t\t\t<template #additional-items>\n\t\t\t\t<!-- The board card: support as one fact row, the SLA address on the same line. -->\n\t\t\t\t<div v-if=\"compactCard && showSupport && !supportAtEnd && !$slots.footer\" class=\"cn-version-info__item\" data-testid=\"cn-admin-settings-support-row\">\n\t\t\t\t\t<span class=\"cn-version-info__label\">{{ supportTitle }}</span>\n\t\t\t\t\t<span class=\"cn-version-info__value\">\n\t\t\t\t\t\t<a :href=\"`mailto:${supportEmail}`\">{{ supportEmail }}</a><template v-if=\"slaEmail\">, {{ slaInline }} <a :href=\"`mailto:${slaEmail}`\">{{ slaEmail }}</a></template>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<!-- @slot version-items Extra key/value rows appended inside the version card details. -->\n\t\t\t\t<slot name=\"version-items\" />\n\t\t\t</template>\n\t\t</CnVersionInfoCard>\n\n\t\t<!--\n\t\t\tOrganisation credential broker (ADR-079 Step 2).\n\n\t\t\tThis is the ONE home for org-wide credentials. It used to live in a\n\t\t\tgeneric modal on CnAppRoot, rendered from `manifest.adminSettings[]`\n\t\t\tand gated on app ownership — but no app ever declared that array, so\n\t\t\tthe surface was unreachable in every app in the fleet. It belongs\n\t\t\there: an org-wide secret store is app-level configuration, and\n\t\t\t/settings/admin/<app> is authorized by Nextcloud server-side rather\n\t\t\tthan by a client-side flag.\n\n\t\t\tOpt-in, because only an app that actually brokers credentials should\n\t\t\tshow it — the manifest `credentials[]` declarations drive the\n\t\t\tinformational \"apps requesting credentials\" list inside.\n\t\t-->\n\t\t<CnCredentials\n\t\t\tv-if=\"showOrganisationCredentials && onFirstTab\"\n\t\t\tscope=\"organisation\"\n\t\t\t:appId=\"appId\"\n\t\t\t:appName=\"appName\"\n\t\t\t:appCredentials=\"appCredentials\"\n\t\t\tdata-testid=\"cn-admin-organisation-credentials\" />\n\n\t\t<!-- @slot default The app's own settings sections, rendered below the version card, or above it with `versionCardPosition: \"end\"`. With `tabs`, only while the first tab is open. -->\n\t\t<slot v-if=\"!versionCardAtEnd && onFirstTab\" />\n\n\t\t<!-- `supportPosition: \"end\"`: the support lines as their own wide card,\n\t\t last on the page (board PqBeheer), not in the version card. -->\n\t\t<CnSettingsSection\n\t\t\tv-if=\"showSupport && supportAtEnd && onFirstTab\"\n\t\t\tclass=\"cn-admin-settings-shell__support\"\n\t\t\t:name=\"supportTitle\"\n\t\t\t:wide=\"true\"\n\t\t\tdata-testid=\"cn-admin-settings-support\">\n\t\t\t<p class=\"cn-admin-settings-shell__support-line\">\n\t\t\t\t{{ supportLine }}\n\t\t\t\t<a :href=\"`mailto:${supportEmail}`\">{{ supportEmail }}</a>\n\t\t\t</p>\n\t\t\t<p v-if=\"slaEmail\" class=\"cn-admin-settings-shell__support-line\">\n\t\t\t\t{{ slaLine }}\n\t\t\t\t<a :href=\"`mailto:${slaEmail}`\">{{ slaEmail }}</a>\n\t\t\t</p>\n\t\t</CnSettingsSection>\n\n\t\t<!-- First-time setup wizard, opened from the admin page (ADR-042). -->\n\t\t<CnSetupWizard\n\t\t\tv-if=\"showSetup && setupWizardOpen\"\n\t\t\t:appId=\"appId\"\n\t\t\t:appName=\"appName\"\n\t\t\t:steps=\"setupSteps\"\n\t\t\t@complete=\"setupWizardOpen = false\"\n\t\t\t@close=\"setupWizardOpen = false\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { showError, showSuccess } from '@nextcloud/dialogs'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcLoadingIcon, NcSettingsSection } from '@nextcloud/vue'\nimport { computed, inject, provide } from 'vue'\nimport AutoFix from 'vue-material-design-icons/AutoFix.vue'\nimport BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'\nimport HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'\nimport CnCredentials from '../CnCredentials/CnCredentials.vue'\nimport CnEnvironmentBanner from '../CnEnvironmentBanner/CnEnvironmentBanner.vue'\nimport CnSetupWizard from '../CnSetupWizard/CnSetupWizard.vue'\nimport { useEnvironment } from '../../composables/useEnvironment.js'\nimport { normalizeLook, useLook } from '../../composables/useLook.js'\nimport { ensureTranslations } from '../../l10n/index.js'\nimport { BUILT_IN_FORMATTERS } from '../../utils/builtInFormatters.js'\nimport { buildFeatureRequestUrl } from '../../utils/forge.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\nimport { CnTab, CnTabs } from '../CnTabs/index.js'\nimport { CnVersionInfoCard } from '../CnVersionInfoCard/index.js'\n\n/**\n * The tab the address names.\n *\n * @param {string} key The query parameter.\n * @return {string} Its value, or ''.\n */\nfunction readTabFromAddress(key) {\n\tif (typeof window === 'undefined' || !key) {\n\t\treturn ''\n\t}\n\treturn new URLSearchParams(window.location.search).get(key) || ''\n}\n\n/**\n * The tab remembered under a storage key, or '' without a key, a value or\n * usable storage (a private window can refuse it).\n *\n * @param {string} key The storage key.\n * @return {string} The remembered tab id.\n */\nfunction readStoredTab(key) {\n\tif (!key) {\n\t\treturn ''\n\t}\n\ttry {\n\t\treturn window.localStorage.getItem(key) || ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * Remember the open tab under a storage key; nothing without a key or\n * usable storage.\n *\n * @param {string} key The storage key.\n * @param {string} id The tab's id.\n * @return {void}\n */\nfunction storeTab(key, id) {\n\tif (!key) {\n\t\treturn\n\t}\n\ttry {\n\t\twindow.localStorage.setItem(key, id)\n\t} catch {\n\t\t// Storage refused (private window): the address still holds the tab.\n\t}\n}\n\n/**\n * Put the open tab in the address without a new history entry.\n *\n * @param {string} key The query parameter.\n * @param {string} id The tab's id.\n * @return {void}\n */\nfunction writeTabToAddress(key, id) {\n\tif (typeof window === 'undefined' || !key || !window.history?.replaceState) {\n\t\treturn\n\t}\n\tconst url = new URL(window.location.href)\n\turl.searchParams.set(key, id)\n\twindow.history.replaceState(window.history.state, '', url.toString())\n}\n\n/**\n * CnAdminSettingsShell — the canonical chrome for a Conduction app's Nextcloud\n * admin settings page.\n *\n * Renders, in fleet-standard order:\n * 1. a page title header (\"<App> Settings\" / \"Configure your <App> installation\" + doc-url),\n * 2. a CnVersionInfoCard (version from `loadState`, up-to-date badge, a\n * \"Re-import configuration\" button wired to the AppHost endpoint\n * `POST /apps/<appId>/api/settings/load`, and a support/SLA footer),\n * 3. the app's own settings sections (default slot).\n *\n * Every app's `AdminRoot.vue` collapses to a thin wrapper so the chrome can\n * never drift between apps again.\n *\n * Basic usage\n * ```vue\n * <CnAdminSettingsShell\n * app-id=\"shillinq\"\n * app-name=\"Shillinq\"\n * doc-url=\"https://shillinq.conduction.nl/docs/intro\">\n * <MyRegisterMapping />\n * <MyFeatureSettings />\n * </CnAdminSettingsShell>\n * ```\n *\n * Real up-to-date check (when the backend exposes it)\n * ```vue\n * <CnAdminSettingsShell\n * app-id=\"opencatalogi\" app-name=\"OpenCatalogi\"\n * :app-version=\"running\" :configured-version=\"configured\"\n * :is-up-to-date=\"running === configured\" />\n * ```\n */\nexport default {\n\tname: 'CnAdminSettingsShell',\n\n\tcomponents: {\n\t\tCnEnvironmentBanner,\n\t\tCnBuildiqEditButton,\n\t\tBookOpenVariant,\n\t\tNcSettingsSection,\n\t\tCnCredentials,\n\t\tCnSettingsSection,\n\t\tCnVersionInfoCard,\n\t\tCnSetupWizard,\n\t\tCnTab,\n\t\tCnTabs,\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tRefresh,\n\t\tAutoFix,\n\t\tHelpCircleOutline,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The environment this instance is: `development`, `test`, `acceptance` or\n\t\t * `production`. Wins over the active organisation's `environment` field.\n\t\t * A non-production environment is named in a banner at the top and the tab\n\t\t * title gets a prefix. Production, an unknown value or no value shows nothing.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tenvironment: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Render the organisation credential broker on this admin page\n\t\t * (ADR-079 Step 2). Opt-in: only an app that actually brokers org-wide\n\t\t * secrets should surface it.\n\t\t *\n\t\t * This replaces the generic `manifest.adminSettings[]` modal that used\n\t\t * to live on CnAppRoot. That modal was gated on app OWNERSHIP and on an\n\t\t * array no app in the fleet ever declared, so the broker was\n\t\t * unreachable everywhere. Here it is reachable and the access decision\n\t\t * is Nextcloud's, made server-side for /settings/admin/<app>.\n\t\t */\n\t\tshowOrganisationCredentials: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * The app's manifest `credentials[]` declarations, forwarded to the\n\t\t * broker to drive its informational \"apps requesting credentials\"\n\t\t * list. Only read when `showOrganisationCredentials` is true.\n\t\t */\n\t\tappCredentials: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * The look the shell is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-admin-settings-shell-takes-the-board-header\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The Nextcloud app id (used for the default re-import endpoint + version loadState). */\n\t\tappId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Human-readable application name shown in the header and version card. */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * Running app version. When empty, read from\n\t\t * `loadState(appId, 'version', 'Unknown')` (provided by AppHost's\n\t\t * GenericAdminSettings::getForm()).\n\t\t */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page title. Defaults to \"<appName> Settings\". */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page description. Defaults to \"Configure your <appName> installation\". */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Board look: the path under the title, in place of the description,\n\t\t * as `[{ label, href? }]` (\"Beheerinstellingen\" linking to the admin\n\t\t * settings, then the app and the section). A crumb without `href` is\n\t\t * text; the last one is the current page.\n\t\t *\n\t\t * @spec openspec/changes/screens-admin-settings-board-header/specs/settings-board-look/spec.md\n\t\t */\n\t\tbreadcrumbs: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Board look: a note after the path, behind a \"·\" (\"geldt voor de\n\t\t * hele organisatie\").\n\t\t *\n\t\t * @spec openspec/changes/screens-admin-settings-board-header/specs/settings-board-look/spec.md\n\t\t */\n\t\tbreadcrumbNote: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Documentation URL (renders the info icon next to the title). */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * A tab strip under the header, as `[{ id, label, count? }]`. Each\n\t\t * tab's panel is the `tab-<id>` slot; the version card, the credential\n\t\t * broker and the default slot show only on the first tab. The open tab\n\t\t * is in the address (`?<tabQueryKey>=<id>`), so a link opens it and a\n\t\t * reload keeps it. The strip is keyboard operable (arrow keys, Home,\n\t\t * End). Empty draws no strip.\n\t\t *\n\t\t * @type {Array<{id: string, label: string, count?: number}>}\n\t\t * @spec openspec/changes/admin-settings-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-a-tab-strip\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 * The query parameter that holds the open tab's `id`.\n\t\t *\n\t\t * @spec openspec/changes/admin-settings-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-a-tab-strip\n\t\t */\n\t\ttabQueryKey: {\n\t\t\ttype: String,\n\t\t\tdefault: 'tab',\n\t\t},\n\n\t\t/**\n\t\t * A browser storage key under which the shell remembers the last\n\t\t * opened tab, so the page opens on it again when the address names no\n\t\t * tab. Empty (the default) remembers nothing. The address still wins.\n\t\t *\n\t\t * @spec openspec/changes/admin-shell-remembers-tab/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-remember-the-last-tab\n\t\t */\n\t\ttabStorageKey: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Mount a tab's `tab-<id>` slot only while that tab is open, and\n\t\t * unmount it when another tab opens, so each visit mounts it afresh\n\t\t * and the page does not load every tab at once. Off (the default),\n\t\t * every panel stays mounted and only the open one shows.\n\t\t *\n\t\t * @spec openspec/changes/admin-settings-lazy-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-mount-only-the-open-tab\n\t\t */\n\t\tlazyTabs: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * How the `tabs` strip is drawn, as CnTabs' `variant`: `line`, the\n\t\t * folder tabs (the default), or `underline`, plain labels on a rule\n\t\t * with the open one underlined (board LpBeheerAlgemeen).\n\t\t *\n\t\t * @type {'line'|'underline'}\n\t\t * @spec openspec/changes/admin-settings-underline-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-an-underline-tab-strip\n\t\t */\n\t\ttabsVariant: {\n\t\t\ttype: String,\n\t\t\tdefault: 'line',\n\t\t\tvalidator: (value) => ['line', 'underline'].includes(value),\n\t\t},\n\n\t\t/** Whether to render the version card. */\n\t\tshowVersionCard: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the version card spans the whole settings grid.\n\t\t * Set to `false` to keep it one card in the grid.\n\t\t *\n\t\t * @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid\n\t\t */\n\t\tversionCardWide: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Where the version card (and the organisation credential broker) sits:\n\t\t * `start`, above the app's sections (the default), or `end`, after them,\n\t\t * for a page whose board starts with the app's own card. The keyboard\n\t\t * order follows, because the slot moves in the markup.\n\t\t *\n\t\t * @spec openspec/changes/screens-admin-settings-version-card-end/specs/settings-board-look/spec.md#requirement-the-version-card-can-follow-the-apps-sections\n\t\t */\n\t\tversionCardPosition: {\n\t\t\ttype: String,\n\t\t\tdefault: 'start',\n\t\t\tvalidator: (value) => ['start', 'end'].includes(value),\n\t\t},\n\n\t\t/**\n\t\t * Board look: how many columns the section cards take, `1` or `2`.\n\t\t * Empty (the default) fits as many 420px columns as the width allows.\n\t\t *\n\t\t * @type {1|2|null}\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-admin-page-can-fix-its-columns\n\t\t */\n\t\tsectionColumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t\tvalidator: (value) => value === null || [1, 2].includes(value),\n\t\t},\n\n\t\t/**\n\t\t * Board look: the version card draws its \"Application name\" row.\n\t\t * Dossiq's boards pass false.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tshowAppName: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the version card draws a rule above its buttons.\n\t\t * Dossiq's boards pass false.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tactionsDivider: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the version card reads the up-to-date state in its\n\t\t * configured version row instead of a disabled button. Dossiq's boards\n\t\t * pass true.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tinlineUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the compact version card of dossiq's boards: \"About this\n\t\t * <App> installation.\", no application name row, the up-to-date state\n\t\t * inline, support as one row, secondary buttons, no rule above them.\n\t\t * The default keeps PqBeheer's card.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Version card heading. */\n\t\tversionTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Version card description. Defaults to \"Information about the current <appName> installation\". */\n\t\tversionDescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Configured version (for apps that track a separate config version).\n\t\t * When omitted, read from `loadState(appId, 'configuredVersion', '')`\n\t\t * (AppHost stamps it on each config import).\n\t\t */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the installation is up to date. Drives the badge/button in the\n\t\t * version card. When left null, the shell reads the REAL value from\n\t\t * `loadState(appId, 'isUpToDate', true)` — AppHost's GenericAdminSettings\n\t\t * provides it by comparing the running version to the imported config\n\t\t * version. Pass an explicit boolean to override; do NOT hardcode true.\n\t\t */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether to show the version card's up-to-date / update button. */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether an app update is in progress (drives the update button spinner). */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the \"Re-import configuration\" action. */\n\t\tshowReimport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Override the re-import endpoint. Defaults to the canonical AppHost\n\t\t * route `/apps/<appId>/api/settings/load`.\n\t\t */\n\t\treimportUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether to render the default support footer. */\n\t\tshowSupport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Where the support lines go: `card`, in the version card's footer (the\n\t\t * default), or `end`, as their own wide card after everything else on\n\t\t * the first tab (board PqBeheer).\n\t\t *\n\t\t * @spec openspec/changes/admin-shell-support-end/specs/settings-board-look/spec.md#requirement-support-can-be-its-own-card-at-the-end\n\t\t */\n\t\tsupportPosition: {\n\t\t\ttype: String,\n\t\t\tdefault: 'card',\n\t\t\tvalidator: (value) => ['card', 'end'].includes(value),\n\t\t},\n\n\t\t/** Support contact email. */\n\t\tsupportEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: 'support@conduction.nl',\n\t\t},\n\n\t\t/** SLA contact email (set to '' to hide the SLA line). */\n\t\tslaEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: 'sales@conduction.nl',\n\t\t},\n\n\t\t/** Show a \"Run setup wizard\" action that opens CnSetupWizard (ADR-042). */\n\t\tshowSetup: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** The `manifest.setup.steps` array passed to CnSetupWizard. */\n\t\tsetupSteps: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Show a \"Help us / suggest a feature\" link to the forge's feature-request form. */\n\t\tshowHelp: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** `<owner>/<repo>` GitHub slug the feature-request link targets. */\n\t\thelpRepo: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Cell formatters by id, as `CnAppRoot`'s `formatters`: a table column\n\t\t * on the admin page names one with `formatter`. Added over the\n\t\t * built-ins and an ancestor's registry.\n\t\t */\n\t\tformatters: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\t},\n\n\temits: ['update', 'reimported', 'reimport-error', 'tab-change'],\n\n\tsetup(props) {\n\t\t// An admin page can be an entry with no other library surface: its\n\t\t// chrome reads in the user's language without the app registering.\n\t\tensureTranslations()\n\t\t// The app's own `environment` setting, else the active organisation's.\n\t\tconst { environment: environmentName } = useEnvironment({ environment: () => props.environment })\n\t\tconst { look, isBoard } = useLook(props)\n\t\t// A shell told `look: \"board\"` itself draws the board look also on an\n\t\t// admin page that no CnAppRoot wraps, as Nextcloud's settings pages are.\n\t\tconst ownLookClass = computed(() => (normalizeLook(props.look) === 'board' ? 'cn-look-board' : ''))\n\t\t// Everything inside the shell, its own version card and the app's\n\t\t// sections alike, follows the shell's look without the app providing it.\n\t\tprovide('cnLook', look)\n\t\t// The setup wizard translates its step titles and bodies through\n\t\t// `cnTranslate`. On an admin page no CnAppRoot provides it, so the\n\t\t// shell hands down the app's own catalog, keyed by its app id.\n\t\tconst hostTranslate = inject('cnTranslate', null)\n\t\tprovide('cnTranslate', hostTranslate || ((text, vars) => t(props.appId, text, vars)))\n\t\t// No CnAppRoot provides the cell formatters on an admin page either.\n\t\tconst hostFormatters = inject('cnFormatters', null)\n\t\tprovide('cnFormatters', { ...BUILT_IN_FORMATTERS, ...(hostFormatters || {}), ...props.formatters })\n\t\treturn { environmentName, isBoard, ownLookClass }\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\treimporting: false,\n\t\t\tsetupWizardOpen: false,\n\t\t\t// The open tab's id; empty until a tab is picked or the address names one.\n\t\t\tchosenTabId: readTabFromAddress(this.tabQueryKey) || readStoredTab(this.tabStorageKey),\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The tabs that have an id and a label.\n\t\t *\n\t\t * @return {Array<{id: string, label: string, count: number|null}>}\n\t\t * @spec openspec/changes/admin-settings-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-a-tab-strip\n\t\t */\n\t\ttabItems() {\n\t\t\treturn (Array.isArray(this.tabs) ? this.tabs : [])\n\t\t\t\t.filter((tab) => tab && typeof tab.id === 'string' && tab.id !== '' && typeof tab.label === 'string' && tab.label !== '')\n\t\t\t\t.map((tab) => ({ id: tab.id, label: tab.label, count: tab.count ?? null }))\n\t\t},\n\n\t\t/**\n\t\t * The open tab: the one picked or named in the address, else the first.\n\t\t *\n\t\t * @return {string} Its id, or '' without tabs.\n\t\t */\n\t\tactiveTabId() {\n\t\t\tconst ids = this.tabItems.map((tab) => tab.id)\n\t\t\treturn ids.includes(this.chosenTabId) ? this.chosenTabId : (ids[0] || '')\n\t\t},\n\n\t\t/**\n\t\t * Whether the shell's own content shows: always without tabs, else on\n\t\t * the first tab.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tonFirstTab() {\n\t\t\treturn this.tabItems.length === 0 || this.activeTabId === this.tabItems[0].id\n\t\t},\n\n\t\t/**\n\t\t * Whether the open tab has no panel of its own: its content is the\n\t\t * default slot, drawn below the strip (the first tab of DqInstellingenAlgemeen).\n\t\t * The strip then keeps no panel spacing, so the first card stands the\n\t\t * page's section gap below the strip.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/admin-shell-empty-tab-gap/specs/admin-shell-empty-tab-gap/spec.md#requirement-a-tab-without-a-panel-adds-no-space-under-the-strip\n\t\t */\n\t\topenPanelIsEmpty() {\n\t\t\treturn !this.$slots[`tab-${this.activeTabId}`]\n\t\t},\n\n\t\t/**\n\t\t * Whether the app's sections come before the version card.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/screens-admin-settings-version-card-end/specs/settings-board-look/spec.md#requirement-the-version-card-can-follow-the-apps-sections\n\t\t */\n\t\tversionCardAtEnd() {\n\t\t\treturn this.versionCardPosition === 'end'\n\t\t},\n\n\t\t/** @return {boolean} Whether the version card is the compact board card. */\n\t\tcompactCard() {\n\t\t\treturn this.isBoard && this.compact\n\t\t},\n\n\t\t/** @return {boolean} Whether the support lines are their own card at the end. */\n\t\tsupportAtEnd() {\n\t\t\treturn this.supportPosition === 'end'\n\t\t},\n\n\t\t/**\n\t\t * The crumbs that have a label.\n\t\t *\n\t\t * @return {Array<{label: string, href?: string}>}\n\t\t * @spec openspec/changes/screens-admin-settings-board-header/specs/settings-board-look/spec.md\n\t\t */\n\t\tcrumbs() {\n\t\t\treturn (Array.isArray(this.breadcrumbs) ? this.breadcrumbs : [])\n\t\t\t\t.filter((crumb) => crumb && typeof crumb.label === 'string' && crumb.label !== '')\n\t\t},\n\n\t\t/** @return {string} The accessible name of the breadcrumb navigation. */\n\t\tbreadcrumbLabel() {\n\t\t\treturn t('nextcloud-vue', 'Breadcrumb')\n\t\t},\n\n\t\t/**\n\t\t * The \"Help us\" link target: the forge's feature-request issue form\n\t\t * for `helpRepo`, on the fleet-default forge. Empty (hiding the\n\t\t * button) when no repo is configured.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\thelpUrl() {\n\t\t\tconst repo = String(this.helpRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn buildFeatureRequestUrl(null, repo)\n\t\t},\n\n\t\t/** @return {string} The running version, falling back to AppHost initial state. */\n\t\tresolvedVersion() {\n\t\t\tif (this.appVersion) {\n\t\t\t\treturn this.appVersion\n\t\t\t}\n\t\t\treturn loadState(this.appId, 'version', 'Unknown')\n\t\t},\n\n\t\t/** @return {string} Configured version, falling back to AppHost initial state. */\n\t\tresolvedConfiguredVersion() {\n\t\t\treturn this.configuredVersion || loadState(this.appId, 'configuredVersion', '')\n\t\t},\n\n\t\t/** @return {boolean} Real up-to-date signal: explicit prop wins, else AppHost initial state. */\n\t\tresolvedIsUpToDate() {\n\t\t\tif (this.isUpToDate !== null) {\n\t\t\t\treturn this.isUpToDate\n\t\t\t}\n\t\t\treturn loadState(this.appId, 'isUpToDate', true)\n\t\t},\n\n\t\t/** @return {string} Page title, defaulting to \"<appName> Settings\". */\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', '{app} Settings', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Page description. */\n\t\tresolvedDescription() {\n\t\t\treturn this.description || t('nextcloud-vue', 'Configure your {app} installation', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Version card description. */\n\t\tresolvedVersionDescription() {\n\t\t\tif (this.versionDescription) {\n\t\t\t\treturn this.versionDescription\n\t\t\t}\n\t\t\treturn this.compactCard\n\t\t\t\t? t('nextcloud-vue', 'About this {app} installation.', { app: this.appName })\n\t\t\t\t: t('nextcloud-vue', 'Information about the current {app} installation', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Re-import endpoint. */\n\t\tresolvedReimportUrl() {\n\t\t\treturn prefixUrl(this.reimportUrl) || generateUrl('/apps/{appId}/api/settings/load', { appId: this.appId })\n\t\t},\n\n\t\t/** @return {string} Re-import button label. */\n\t\treimportLabel() {\n\t\t\treturn t('nextcloud-vue', 'Re-import configuration')\n\t\t},\n\n\t\t/** @return {string} Re-import in-progress label. */\n\t\timportingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Importing…')\n\t\t},\n\n\t\t/** @return {string} Support footer heading. */\n\t\tsupportTitle() {\n\t\t\treturn t('nextcloud-vue', 'Support')\n\t\t},\n\n\t\t/** @return {string} Support footer line. */\n\t\tsupportLine() {\n\t\t\treturn t('nextcloud-vue', 'For support, contact us at')\n\t\t},\n\n\t\t/** @return {string} The words before the SLA address in the board card's support row. */\n\t\tslaInline() {\n\t\t\treturn t('nextcloud-vue', 'for an SLA')\n\t\t},\n\n\t\t/** @return {string} SLA footer line. */\n\t\tslaLine() {\n\t\t\treturn t('nextcloud-vue', 'For a Service Level Agreement (SLA), contact')\n\t\t},\n\n\t\t/** @return {string} Setup-wizard button label. */\n\t\tsetupLabel() {\n\t\t\treturn t('nextcloud-vue', 'Run setup wizard')\n\t\t},\n\n\t\t/** @return {string} Documentation button label (board header). */\n\t\tdocumentationLabel() {\n\t\t\treturn t('nextcloud-vue', 'Documentation')\n\t\t},\n\n\t\t/** @return {string} Help / suggest-feature button label. */\n\t\thelpLabel() {\n\t\t\treturn t('nextcloud-vue', 'Help us')\n\t\t},\n\t},\n\n\t/**\n\t * A page that opens on a tab other than the first (named in the address,\n\t * or remembered) tells the app once, as a click would, so a breadcrumb or\n\t * title that follows the tab is right from the first paint.\n\t *\n\t * @spec openspec/changes/admin-shell-remembers-tab/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-remember-the-last-tab\n\t */\n\tmounted() {\n\t\tif (this.tabItems.length > 0 && this.activeTabId !== this.tabItems[0].id) {\n\t\t\tthis.$emit('tab-change', this.activeTabId)\n\t\t}\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A tab was picked in the strip: remember it, put it in the address\n\t\t * (replacing the entry, so Back leaves the page) and tell the app.\n\t\t *\n\t\t * @param {number} index The picked tab's index.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/admin-settings-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-a-tab-strip\n\t\t */\n\t\tonTabIndex(index) {\n\t\t\tconst tab = this.tabItems[index]\n\t\t\tif (!tab || tab.id === this.chosenTabId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.chosenTabId = tab.id\n\t\t\twriteTabToAddress(this.tabQueryKey, tab.id)\n\t\t\tstoreTab(this.tabStorageKey, tab.id)\n\t\t\t/**\n\t\t\t * @event tab-change Emitted when the reader opens another tab. Payload: its `id`.\n\t\t\t */\n\t\t\tthis.$emit('tab-change', tab.id)\n\t\t},\n\n\t\t/** Forward the version card's update-button click to the parent. */\n\t\tonUpdate() {\n\t\t\t/**\n\t\t\t * @event update Emitted when the version card's update button is clicked.\n\t\t\t */\n\t\t\tthis.$emit('update')\n\t\t},\n\n\t\t/**\n\t\t * Re-import the app's OpenRegister configuration via the canonical\n\t\t * AppHost endpoint, then emit the result so the parent can refresh.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync reimport() {\n\t\t\tif (this.reimporting) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.reimporting = true\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(this.resolvedReimportUrl)\n\t\t\t\tconst data = response?.data ?? {}\n\t\t\t\t// AppHost returns { success, message, ... }; a bare 2xx also counts.\n\t\t\t\tif (data.success === false) {\n\t\t\t\t\tthrow new Error(data.message || t('nextcloud-vue', 'Re-import failed'))\n\t\t\t\t}\n\t\t\t\tshowSuccess(data.message || t('nextcloud-vue', 'Configuration re-imported successfully'))\n\t\t\t\t/**\n\t\t\t\t * @event reimported Emitted after a successful configuration re-import.\n\t\t\t\t * @type {object} The AppHost response payload.\n\t\t\t\t */\n\t\t\t\tthis.$emit('reimported', data)\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error?.response?.data?.message || error?.message || t('nextcloud-vue', 'Re-import failed')\n\t\t\t\tshowError(message)\n\t\t\t\t/**\n\t\t\t\t * @event reimport-error Emitted when a configuration re-import fails.\n\t\t\t\t * @type {Error} The error that caused the failure.\n\t\t\t\t */\n\t\t\t\tthis.$emit('reimport-error', error)\n\t\t\t} finally {\n\t\t\t\tthis.reimporting = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-admin-settings-shell {\n\tmax-width: 900px;\n}\n\n/* The board look lifts the width and lays the header and cards on a grid (look-board.css). */\n\n/* A tab without a panel of its own: the cards below the strip carry the gap. */\n.cn-admin-settings-shell__tabs--bare > :deep(.cn-tabs__content) {\n\tpadding-top: 0;\n}\n\n.cn-support-info {\n\tmargin-top: 16px;\n\tpadding-top: 16px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-support-info h4 {\n\tmargin: 0 0 8px 0;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-support-info p {\n\tmargin: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-support-info a {\n\tcolor: var(--color-primary-element);\n}\n</style>\n"],"names":["CnEnvironmentBanner","CnBuildiqEditButton","CnCredentials","CnSettingsSection","CnVersionInfoCard","CnSetupWizard","CnTab","CnTabs","t","axios"],"mappings":"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"}
1
+ {"version":3,"file":"CnAdminSettingsShell.vue2.js","sources":["../../../../src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue"],"sourcesContent":["<template>\n\t<div\n\t\tclass=\"cn-admin-settings-shell\"\n\t\t:class=\"[ownLookClass, sectionColumns ? `cn-admin-settings-shell--columns-${sectionColumns}` : '']\"\n\t\t:style=\"versionTitleSize ? { '--cn-board-version-title-size': `${versionTitleSize}px` } : null\">\n\t\t<!-- Names a development, test or acceptance environment; cannot be dismissed. Production shows nothing. -->\n\t\t<CnEnvironmentBanner v-if=\"environmentName\" :environment=\"environmentName\" />\n\n\t\t<!-- Page title header — the uniform \"<App> Settings / Configure your <App> installation\" block.\n\t\t Uses NcSettingsSection directly (not CnSettingsSection) so the description subtitle and\n\t\t doc-url icon render — CnSettingsSection repurposes those props and does not forward them. -->\n\t\t<NcSettingsSection\n\t\t\tv-if=\"!isBoard\"\n\t\t\t:name=\"resolvedTitle\"\n\t\t\t:description=\"resolvedDescription\"\n\t\t\t:docUrl=\"docUrl\" />\n\n\t\t<!-- The board header: an h1 and its description, then the labelled\n\t\t Documentation button and the buildiq square. No documentation icon\n\t\t beside the title. -->\n\t\t<div v-else class=\"cn-admin-settings-shell__header\" data-testid=\"cn-admin-settings-header\">\n\t\t\t<div class=\"cn-admin-settings-shell__heading\">\n\t\t\t\t<h1 class=\"cn-admin-settings-shell__title\">\n\t\t\t\t\t{{ resolvedTitle }}\n\t\t\t\t</h1>\n\t\t\t\t<!-- `breadcrumbs`: the board's path line in place of the\n\t\t\t\t description (\"Beheerinstellingen / Launchpad / Algemeen ·\n\t\t\t\t geldt voor de hele organisatie\"). -->\n\t\t\t\t<div v-if=\"crumbs.length > 0\" class=\"cn-admin-settings-shell__crumbs\" data-testid=\"cn-admin-settings-breadcrumbs\">\n\t\t\t\t\t<nav class=\"cn-admin-settings-shell__crumb-list\" :aria-label=\"breadcrumbLabel\">\n\t\t\t\t\t\t<template v-for=\"(crumb, index) in crumbs\" :key=\"index\">\n\t\t\t\t\t\t\t<span v-if=\"index > 0\" aria-hidden=\"true\">/</span>\n\t\t\t\t\t\t\t<a v-if=\"crumb.href\" :href=\"crumb.href\" class=\"cn-admin-settings-shell__crumb-link\">{{ crumb.label }}</a>\n\t\t\t\t\t\t\t<span v-else :aria-current=\"index === crumbs.length - 1 ? 'page' : null\">{{ crumb.label }}</span>\n\t\t\t\t\t\t</template>\n\t\t\t\t\t</nav>\n\t\t\t\t\t<template v-if=\"breadcrumbNote\">\n\t\t\t\t\t\t<span aria-hidden=\"true\">·</span>\n\t\t\t\t\t\t<span>{{ breadcrumbNote }}</span>\n\t\t\t\t\t</template>\n\t\t\t\t</div>\n\t\t\t\t<p v-else class=\"cn-admin-settings-shell__description\">\n\t\t\t\t\t{{ resolvedDescription }}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t\t<div class=\"cn-admin-settings-shell__header-buttons\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"docUrl\"\n\t\t\t\t\t:href=\"docUrl\"\n\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\tdata-testid=\"cn-admin-settings-documentation\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<BookOpenVariant :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ documentationLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<CnBuildiqEditButton />\n\t\t\t</div>\n\t\t</div>\n\n\t\t<!-- `tabs`: a strip under the header (boards ShInstellingen,\n\t\t LpBeheerAlgemeen). Each tab's panel holds the `tab-<id>` slot; the\n\t\t version card, the credential broker and the default slot below\n\t\t belong to the first tab and show only while it is open. -->\n\t\t<CnTabs\n\t\t\tv-if=\"tabItems.length > 0\"\n\t\t\tclass=\"cn-admin-settings-shell__tabs\"\n\t\t\t:class=\"{ 'cn-admin-settings-shell__tabs--bare': openPanelIsEmpty }\"\n\t\t\t:look=\"isBoard ? 'board' : 'nextcloud'\"\n\t\t\t:variant=\"tabsVariant\"\n\t\t\t:ariaLabel=\"resolvedTitle\"\n\t\t\tdata-testid=\"cn-admin-settings-tabs\"\n\t\t\t@update:activeIndex=\"onTabIndex\">\n\t\t\t<CnTab\n\t\t\t\tv-for=\"tab in tabItems\"\n\t\t\t\t:key=\"tab.id\"\n\t\t\t\t:title=\"tab.label\"\n\t\t\t\t:count=\"tab.count\"\n\t\t\t\t:active=\"tab.id === activeTabId\">\n\t\t\t\t<div class=\"cn-admin-settings-shell__panel\" :data-tab=\"tab.id\">\n\t\t\t\t\t<!-- @slot tab-<id> The panel of the tab with that `id` in `tabs`. -->\n\t\t\t\t\t<slot v-if=\"!lazyTabs || tab.id === activeTabId\" :name=\"`tab-${tab.id}`\" />\n\t\t\t\t</div>\n\t\t\t</CnTab>\n\t\t</CnTabs>\n\n\t\t<!-- `versionCardPosition: \"end\"`: the app's sections come first, and the\n\t\t version card and the credential broker follow them (board DcBeheer\n\t\t starts with the app's own card). The same slot, rendered once. -->\n\t\t<slot v-if=\"versionCardAtEnd && onFirstTab\" />\n\n\t\t<!-- Version information card (version, up-to-date check, re-import, support footer) -->\n\t\t<CnVersionInfoCard\n\t\t\tv-if=\"showVersionCard && onFirstTab\"\n\t\t\t:appName=\"appName\"\n\t\t\t:appVersion=\"resolvedVersion\"\n\t\t\t:configuredVersion=\"resolvedConfiguredVersion\"\n\t\t\t:isUpToDate=\"resolvedIsUpToDate\"\n\t\t\t:showUpdateButton=\"showUpdateButton\"\n\t\t\t:updating=\"updating\"\n\t\t\t:title=\"versionTitle\"\n\t\t\t:description=\"resolvedVersionDescription\"\n\t\t\t:wide=\"versionCardWide\"\n\t\t\t:showAppName=\"showAppName\"\n\t\t\t:actionsDivider=\"actionsDivider\"\n\t\t\t:inlineUpToDate=\"inlineUpToDate\"\n\t\t\t:compact=\"compact\"\n\t\t\t@update=\"onUpdate\">\n\t\t\t<template #actions>\n\t\t\t\t<!-- Canonical \"Re-import configuration\" action (POST /apps/<appId>/api/settings/load) -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showReimport\"\n\t\t\t\t\t:variant=\"compactCard ? 'secondary' : 'primary'\"\n\t\t\t\t\t:disabled=\"reimporting\"\n\t\t\t\t\t@click=\"reimport\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcLoadingIcon v-if=\"reimporting\" :size=\"20\" />\n\t\t\t\t\t\t<Refresh v-else :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ reimporting ? importingLabel : reimportLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- Run the first-time setup wizard on demand (ADR-042). -->\n\t\t\t\t<NcButton v-if=\"showSetup\" data-testid=\"cn-admin-run-setup\" @click=\"setupWizardOpen = true\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<AutoFix :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ setupLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- \"Help us / suggest a feature\" — a direct link to the forge's\n\t\t\t\t feature-request issue form (team decision 2026-09-04: the\n\t\t\t\t in-product suggestion modal is gone; the forge is where\n\t\t\t\t the conversation happens, in English). -->\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"showHelp && helpUrl\"\n\t\t\t\t\t:href=\"helpUrl\"\n\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<HelpCircleOutline :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ helpLabel }}\n\t\t\t\t</NcButton>\n\t\t\t\t<!-- @slot actions Extra action buttons rendered next to the built-in update / re-import buttons in the version card header. -->\n\t\t\t\t<slot name=\"actions\" />\n\t\t\t</template>\n\n\t\t\t<template #footer>\n\t\t\t\t<!-- @slot footer Replaces the default support/SLA footer inside the version card. -->\n\t\t\t\t<slot name=\"footer\">\n\t\t\t\t\t<div v-if=\"showSupport && !supportAtEnd && !compactCard\" class=\"cn-support-info\">\n\t\t\t\t\t\t<h4>{{ supportTitle }}</h4>\n\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t{{ supportLine }}\n\t\t\t\t\t\t\t<a :href=\"`mailto:${supportEmail}`\">{{ supportEmail }}</a>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<p v-if=\"slaEmail\">\n\t\t\t\t\t\t\t{{ slaLine }}\n\t\t\t\t\t\t\t<a :href=\"`mailto:${slaEmail}`\">{{ slaEmail }}</a>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</slot>\n\t\t\t</template>\n\n\t\t\t<template #additional-items>\n\t\t\t\t<!-- The board card: support as one fact row, the SLA address on the same line. -->\n\t\t\t\t<div v-if=\"compactCard && showSupport && !supportAtEnd && !$slots.footer\" class=\"cn-version-info__item\" data-testid=\"cn-admin-settings-support-row\">\n\t\t\t\t\t<span class=\"cn-version-info__label\">{{ supportTitle }}</span>\n\t\t\t\t\t<span class=\"cn-version-info__value\">\n\t\t\t\t\t\t<a :href=\"`mailto:${supportEmail}`\">{{ supportEmail }}</a><template v-if=\"slaEmail\">, {{ slaInline }} <a :href=\"`mailto:${slaEmail}`\">{{ slaEmail }}</a></template>\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t\t<!-- @slot version-items Extra key/value rows appended inside the version card details. -->\n\t\t\t\t<slot name=\"version-items\" />\n\t\t\t</template>\n\t\t</CnVersionInfoCard>\n\n\t\t<!--\n\t\t\tOrganisation credential broker (ADR-079 Step 2).\n\n\t\t\tThis is the ONE home for org-wide credentials. It used to live in a\n\t\t\tgeneric modal on CnAppRoot, rendered from `manifest.adminSettings[]`\n\t\t\tand gated on app ownership — but no app ever declared that array, so\n\t\t\tthe surface was unreachable in every app in the fleet. It belongs\n\t\t\there: an org-wide secret store is app-level configuration, and\n\t\t\t/settings/admin/<app> is authorized by Nextcloud server-side rather\n\t\t\tthan by a client-side flag.\n\n\t\t\tOpt-in, because only an app that actually brokers credentials should\n\t\t\tshow it — the manifest `credentials[]` declarations drive the\n\t\t\tinformational \"apps requesting credentials\" list inside.\n\t\t-->\n\t\t<CnCredentials\n\t\t\tv-if=\"showOrganisationCredentials && onFirstTab\"\n\t\t\tscope=\"organisation\"\n\t\t\t:appId=\"appId\"\n\t\t\t:appName=\"appName\"\n\t\t\t:appCredentials=\"appCredentials\"\n\t\t\tdata-testid=\"cn-admin-organisation-credentials\" />\n\n\t\t<!-- @slot default The app's own settings sections, rendered below the version card, or above it with `versionCardPosition: \"end\"`. With `tabs`, only while the first tab is open. -->\n\t\t<slot v-if=\"!versionCardAtEnd && onFirstTab\" />\n\n\t\t<!-- `supportPosition: \"end\"`: the support lines as their own wide card,\n\t\t last on the page (board PqBeheer), not in the version card. -->\n\t\t<CnSettingsSection\n\t\t\tv-if=\"showSupport && supportAtEnd && onFirstTab\"\n\t\t\tclass=\"cn-admin-settings-shell__support\"\n\t\t\t:name=\"supportTitle\"\n\t\t\t:wide=\"true\"\n\t\t\tdata-testid=\"cn-admin-settings-support\">\n\t\t\t<p class=\"cn-admin-settings-shell__support-line\">\n\t\t\t\t{{ supportLine }}\n\t\t\t\t<a :href=\"`mailto:${supportEmail}`\">{{ supportEmail }}</a>\n\t\t\t</p>\n\t\t\t<p v-if=\"slaEmail\" class=\"cn-admin-settings-shell__support-line\">\n\t\t\t\t{{ slaLine }}\n\t\t\t\t<a :href=\"`mailto:${slaEmail}`\">{{ slaEmail }}</a>\n\t\t\t</p>\n\t\t</CnSettingsSection>\n\n\t\t<!-- First-time setup wizard, opened from the admin page (ADR-042). -->\n\t\t<CnSetupWizard\n\t\t\tv-if=\"showSetup && setupWizardOpen\"\n\t\t\t:appId=\"appId\"\n\t\t\t:appName=\"appName\"\n\t\t\t:steps=\"setupSteps\"\n\t\t\t@complete=\"setupWizardOpen = false\"\n\t\t\t@close=\"setupWizardOpen = false\" />\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { showError, showSuccess } from '@nextcloud/dialogs'\nimport { loadState } from '@nextcloud/initial-state'\nimport { translate as t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { NcButton, NcLoadingIcon, NcSettingsSection } from '@nextcloud/vue'\nimport { computed, inject, provide } from 'vue'\nimport AutoFix from 'vue-material-design-icons/AutoFix.vue'\nimport BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'\nimport HelpCircleOutline from 'vue-material-design-icons/HelpCircleOutline.vue'\nimport Refresh from 'vue-material-design-icons/Refresh.vue'\nimport CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'\nimport CnCredentials from '../CnCredentials/CnCredentials.vue'\nimport CnEnvironmentBanner from '../CnEnvironmentBanner/CnEnvironmentBanner.vue'\nimport CnSetupWizard from '../CnSetupWizard/CnSetupWizard.vue'\nimport { useEnvironment } from '../../composables/useEnvironment.js'\nimport { normalizeLook, useLook } from '../../composables/useLook.js'\nimport { ensureTranslations } from '../../l10n/index.js'\nimport { BUILT_IN_FORMATTERS } from '../../utils/builtInFormatters.js'\nimport { buildFeatureRequestUrl } from '../../utils/forge.js'\nimport { prefixUrl } from '../../utils/headers.js'\nimport { CnSettingsSection } from '../CnSettingsSection/index.js'\nimport { CnTab, CnTabs } from '../CnTabs/index.js'\nimport { CnVersionInfoCard } from '../CnVersionInfoCard/index.js'\n\n/**\n * The tab the address names.\n *\n * @param {string} key The query parameter.\n * @return {string} Its value, or ''.\n */\nfunction readTabFromAddress(key) {\n\tif (typeof window === 'undefined' || !key) {\n\t\treturn ''\n\t}\n\treturn new URLSearchParams(window.location.search).get(key) || ''\n}\n\n/**\n * The tab remembered under a storage key, or '' without a key, a value or\n * usable storage (a private window can refuse it).\n *\n * @param {string} key The storage key.\n * @return {string} The remembered tab id.\n */\nfunction readStoredTab(key) {\n\tif (!key) {\n\t\treturn ''\n\t}\n\ttry {\n\t\treturn window.localStorage.getItem(key) || ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * Remember the open tab under a storage key; nothing without a key or\n * usable storage.\n *\n * @param {string} key The storage key.\n * @param {string} id The tab's id.\n * @return {void}\n */\nfunction storeTab(key, id) {\n\tif (!key) {\n\t\treturn\n\t}\n\ttry {\n\t\twindow.localStorage.setItem(key, id)\n\t} catch {\n\t\t// Storage refused (private window): the address still holds the tab.\n\t}\n}\n\n/**\n * Put the open tab in the address without a new history entry.\n *\n * @param {string} key The query parameter.\n * @param {string} id The tab's id.\n * @return {void}\n */\nfunction writeTabToAddress(key, id) {\n\tif (typeof window === 'undefined' || !key || !window.history?.replaceState) {\n\t\treturn\n\t}\n\tconst url = new URL(window.location.href)\n\turl.searchParams.set(key, id)\n\twindow.history.replaceState(window.history.state, '', url.toString())\n}\n\n/**\n * CnAdminSettingsShell — the canonical chrome for a Conduction app's Nextcloud\n * admin settings page.\n *\n * Renders, in fleet-standard order:\n * 1. a page title header (\"<App> Settings\" / \"Configure your <App> installation\" + doc-url),\n * 2. a CnVersionInfoCard (version from `loadState`, up-to-date badge, a\n * \"Re-import configuration\" button wired to the AppHost endpoint\n * `POST /apps/<appId>/api/settings/load`, and a support/SLA footer),\n * 3. the app's own settings sections (default slot).\n *\n * Every app's `AdminRoot.vue` collapses to a thin wrapper so the chrome can\n * never drift between apps again.\n *\n * Basic usage\n * ```vue\n * <CnAdminSettingsShell\n * app-id=\"shillinq\"\n * app-name=\"Shillinq\"\n * doc-url=\"https://shillinq.conduction.nl/docs/intro\">\n * <MyRegisterMapping />\n * <MyFeatureSettings />\n * </CnAdminSettingsShell>\n * ```\n *\n * Real up-to-date check (when the backend exposes it)\n * ```vue\n * <CnAdminSettingsShell\n * app-id=\"opencatalogi\" app-name=\"OpenCatalogi\"\n * :app-version=\"running\" :configured-version=\"configured\"\n * :is-up-to-date=\"running === configured\" />\n * ```\n */\nexport default {\n\tname: 'CnAdminSettingsShell',\n\n\tcomponents: {\n\t\tCnEnvironmentBanner,\n\t\tCnBuildiqEditButton,\n\t\tBookOpenVariant,\n\t\tNcSettingsSection,\n\t\tCnCredentials,\n\t\tCnSettingsSection,\n\t\tCnVersionInfoCard,\n\t\tCnSetupWizard,\n\t\tCnTab,\n\t\tCnTabs,\n\t\tNcButton,\n\t\tNcLoadingIcon,\n\t\tRefresh,\n\t\tAutoFix,\n\t\tHelpCircleOutline,\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The environment this instance is: `development`, `test`, `acceptance` or\n\t\t * `production`. Wins over the active organisation's `environment` field.\n\t\t * A non-production environment is named in a banner at the top and the tab\n\t\t * title gets a prefix. Production, an unknown value or no value shows nothing.\n\t\t *\n\t\t * @type {string}\n\t\t */\n\t\tenvironment: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Render the organisation credential broker on this admin page\n\t\t * (ADR-079 Step 2). Opt-in: only an app that actually brokers org-wide\n\t\t * secrets should surface it.\n\t\t *\n\t\t * This replaces the generic `manifest.adminSettings[]` modal that used\n\t\t * to live on CnAppRoot. That modal was gated on app OWNERSHIP and on an\n\t\t * array no app in the fleet ever declared, so the broker was\n\t\t * unreachable everywhere. Here it is reachable and the access decision\n\t\t * is Nextcloud's, made server-side for /settings/admin/<app>.\n\t\t */\n\t\tshowOrganisationCredentials: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * The app's manifest `credentials[]` declarations, forwarded to the\n\t\t * broker to drive its informational \"apps requesting credentials\"\n\t\t * list. Only read when `showOrganisationCredentials` is true.\n\t\t */\n\t\tappCredentials: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * The look the shell is drawn in: `board` or `nextcloud`. Empty follows\n\t\t * the `cnLook` that CnAppRoot provides.\n\t\t *\n\t\t * @spec openspec/changes/screens-chrome-parity/specs/settings-board-look/spec.md#requirement-the-admin-settings-shell-takes-the-board-header\n\t\t */\n\t\tlook: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** The Nextcloud app id (used for the default re-import endpoint + version loadState). */\n\t\tappId: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/** Human-readable application name shown in the header and version card. */\n\t\tappName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * Running app version. When empty, read from\n\t\t * `loadState(appId, 'version', 'Unknown')` (provided by AppHost's\n\t\t * GenericAdminSettings::getForm()).\n\t\t */\n\t\tappVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page title. Defaults to \"<appName> Settings\". */\n\t\ttitle: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Page description. Defaults to \"Configure your <appName> installation\". */\n\t\tdescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Board look: the path under the title, in place of the description,\n\t\t * as `[{ label, href? }]` (\"Beheerinstellingen\" linking to the admin\n\t\t * settings, then the app and the section). A crumb without `href` is\n\t\t * text; the last one is the current page.\n\t\t *\n\t\t * @spec openspec/changes/screens-admin-settings-board-header/specs/settings-board-look/spec.md\n\t\t */\n\t\tbreadcrumbs: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Board look: a note after the path, behind a \"·\" (\"geldt voor de\n\t\t * hele organisatie\").\n\t\t *\n\t\t * @spec openspec/changes/screens-admin-settings-board-header/specs/settings-board-look/spec.md\n\t\t */\n\t\tbreadcrumbNote: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Documentation URL (renders the info icon next to the title). */\n\t\tdocUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * A tab strip under the header, as `[{ id, label, count? }]`. Each\n\t\t * tab's panel is the `tab-<id>` slot; the version card, the credential\n\t\t * broker and the default slot show only on the first tab. The open tab\n\t\t * is in the address (`?<tabQueryKey>=<id>`), so a link opens it and a\n\t\t * reload keeps it. The strip is keyboard operable (arrow keys, Home,\n\t\t * End). Empty draws no strip.\n\t\t *\n\t\t * @type {Array<{id: string, label: string, count?: number}>}\n\t\t * @spec openspec/changes/admin-settings-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-a-tab-strip\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 * The query parameter that holds the open tab's `id`.\n\t\t *\n\t\t * @spec openspec/changes/admin-settings-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-a-tab-strip\n\t\t */\n\t\ttabQueryKey: {\n\t\t\ttype: String,\n\t\t\tdefault: 'tab',\n\t\t},\n\n\t\t/**\n\t\t * A browser storage key under which the shell remembers the last\n\t\t * opened tab, so the page opens on it again when the address names no\n\t\t * tab. Empty (the default) remembers nothing. The address still wins.\n\t\t *\n\t\t * @spec openspec/changes/admin-shell-remembers-tab/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-remember-the-last-tab\n\t\t */\n\t\ttabStorageKey: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Mount a tab's `tab-<id>` slot only while that tab is open, and\n\t\t * unmount it when another tab opens, so each visit mounts it afresh\n\t\t * and the page does not load every tab at once. Off (the default),\n\t\t * every panel stays mounted and only the open one shows.\n\t\t *\n\t\t * @spec openspec/changes/admin-settings-lazy-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-mount-only-the-open-tab\n\t\t */\n\t\tlazyTabs: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * How the `tabs` strip is drawn, as CnTabs' `variant`: `line`, the\n\t\t * folder tabs (the default), or `underline`, plain labels on a rule\n\t\t * with the open one underlined (board LpBeheerAlgemeen).\n\t\t *\n\t\t * @type {'line'|'underline'}\n\t\t * @spec openspec/changes/admin-settings-underline-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-an-underline-tab-strip\n\t\t */\n\t\ttabsVariant: {\n\t\t\ttype: String,\n\t\t\tdefault: 'line',\n\t\t\tvalidator: (value) => ['line', 'underline'].includes(value),\n\t\t},\n\n\t\t/** Whether to render the version card. */\n\t\tshowVersionCard: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Under the board look the version card spans the whole settings grid.\n\t\t * Set to `false` to keep it one card in the grid.\n\t\t *\n\t\t * @spec openspec/changes/board-version-card-full-width/specs/settings-board-look/spec.md#requirement-the-board-version-card-spans-the-settings-grid\n\t\t */\n\t\tversionCardWide: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Where the version card (and the organisation credential broker) sits:\n\t\t * `start`, above the app's sections (the default), or `end`, after them,\n\t\t * for a page whose board starts with the app's own card. The keyboard\n\t\t * order follows, because the slot moves in the markup.\n\t\t *\n\t\t * @spec openspec/changes/screens-admin-settings-version-card-end/specs/settings-board-look/spec.md#requirement-the-version-card-can-follow-the-apps-sections\n\t\t */\n\t\tversionCardPosition: {\n\t\t\ttype: String,\n\t\t\tdefault: 'start',\n\t\t\tvalidator: (value) => ['start', 'end'].includes(value),\n\t\t},\n\n\t\t/**\n\t\t * Board look: how many columns the section cards take, `1` or `2`.\n\t\t * Empty (the default) fits as many 420px columns as the width allows.\n\t\t *\n\t\t * @type {1|2|null}\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-admin-page-can-fix-its-columns\n\t\t */\n\t\tsectionColumns: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t\tvalidator: (value) => value === null || [1, 2].includes(value),\n\t\t},\n\n\t\t/**\n\t\t * Board look: the version card draws its \"Application name\" row.\n\t\t * Dossiq's boards pass false.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tshowAppName: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the version card draws a rule above its buttons.\n\t\t * Dossiq's boards pass false.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tactionsDivider: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the version card reads the up-to-date state in its\n\t\t * configured version row instead of a disabled button. Dossiq's boards\n\t\t * pass true.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tinlineUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Board look: the compact version card of dossiq's boards: \"About this\n\t\t * <App> installation.\", no application name row, the up-to-date state\n\t\t * inline, support as one row, secondary buttons, no rule above them.\n\t\t * The default keeps PqBeheer's card.\n\t\t *\n\t\t * @spec openspec/changes/version-card-board-compact/specs/settings-board-look/spec.md#requirement-the-board-version-card-is-compact\n\t\t */\n\t\tcompact: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Version card heading. */\n\t\tversionTitle: {\n\t\t\ttype: String,\n\t\t\tdefault: () => t('nextcloud-vue', 'Version information'),\n\t\t},\n\n\t\t/** Version card description. Defaults to \"Information about the current <appName> installation\". */\n\t\tversionDescription: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Configured version (for apps that track a separate config version).\n\t\t * When omitted, read from `loadState(appId, 'configuredVersion', '')`\n\t\t * (AppHost stamps it on each config import).\n\t\t */\n\t\tconfiguredVersion: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Whether the installation is up to date. Drives the badge/button in the\n\t\t * version card. When left null, the shell reads the REAL value from\n\t\t * `loadState(appId, 'isUpToDate', true)` — AppHost's GenericAdminSettings\n\t\t * provides it by comparing the running version to the imported config\n\t\t * version. Pass an explicit boolean to override; do NOT hardcode true.\n\t\t */\n\t\tisUpToDate: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** Whether to show the version card's up-to-date / update button. */\n\t\tshowUpdateButton: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/** Whether an app update is in progress (drives the update button spinner). */\n\t\tupdating: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** Whether to show the \"Re-import configuration\" action. */\n\t\tshowReimport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Override the re-import endpoint. Defaults to the canonical AppHost\n\t\t * route `/apps/<appId>/api/settings/load`.\n\t\t */\n\t\treimportUrl: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** Whether to render the default support footer. */\n\t\tshowSupport: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Where the support lines go: `card`, in the version card's footer (the\n\t\t * default), or `end`, as their own wide card after everything else on\n\t\t * the first tab (board PqBeheer).\n\t\t *\n\t\t * @spec openspec/changes/admin-shell-support-end/specs/settings-board-look/spec.md#requirement-support-can-be-its-own-card-at-the-end\n\t\t */\n\t\tsupportPosition: {\n\t\t\ttype: String,\n\t\t\tdefault: 'card',\n\t\t\tvalidator: (value) => ['card', 'end'].includes(value),\n\t\t},\n\n\t\t/** Support contact email. */\n\t\tsupportEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: 'support@conduction.nl',\n\t\t},\n\n\t\t/** SLA contact email (set to '' to hide the SLA line). */\n\t\tslaEmail: {\n\t\t\ttype: String,\n\t\t\tdefault: 'sales@conduction.nl',\n\t\t},\n\n\t\t/** Show a \"Run setup wizard\" action that opens CnSetupWizard (ADR-042). */\n\t\tshowSetup: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** The `manifest.setup.steps` array passed to CnSetupWizard. */\n\t\tsetupSteps: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/** Show a \"Help us / suggest a feature\" link to the forge's feature-request form. */\n\t\tshowHelp: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/** `<owner>/<repo>` GitHub slug the feature-request link targets. */\n\t\thelpRepo: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Cell formatters by id, as `CnAppRoot`'s `formatters`: a table column\n\t\t * on the admin page names one with `formatter`. Added over the\n\t\t * built-ins and an ancestor's registry.\n\t\t */\n\t\tformatters: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * The board look's version card title size in px, when the app's board\n\t\t * draws it other than 17px (PqBeheer 19, OcInstellingen 18).\n\t\t */\n\t\tversionTitleSize: {\n\t\t\ttype: Number,\n\t\t\tdefault: 0,\n\t\t},\n\t},\n\n\temits: ['update', 'reimported', 'reimport-error', 'tab-change'],\n\n\tsetup(props) {\n\t\t// An admin page can be an entry with no other library surface: its\n\t\t// chrome reads in the user's language without the app registering.\n\t\tensureTranslations()\n\t\t// The app's own `environment` setting, else the active organisation's.\n\t\tconst { environment: environmentName } = useEnvironment({ environment: () => props.environment })\n\t\tconst { look, isBoard } = useLook(props)\n\t\t// A shell told `look: \"board\"` itself draws the board look also on an\n\t\t// admin page that no CnAppRoot wraps, as Nextcloud's settings pages are.\n\t\tconst ownLookClass = computed(() => (normalizeLook(props.look) === 'board' ? 'cn-look-board' : ''))\n\t\t// Everything inside the shell, its own version card and the app's\n\t\t// sections alike, follows the shell's look without the app providing it.\n\t\tprovide('cnLook', look)\n\t\t// The setup wizard translates its step titles and bodies through\n\t\t// `cnTranslate`. On an admin page no CnAppRoot provides it, so the\n\t\t// shell hands down the app's own catalog, keyed by its app id.\n\t\tconst hostTranslate = inject('cnTranslate', null)\n\t\tprovide('cnTranslate', hostTranslate || ((text, vars) => t(props.appId, text, vars)))\n\t\t// No CnAppRoot provides the cell formatters on an admin page either.\n\t\tconst hostFormatters = inject('cnFormatters', null)\n\t\tprovide('cnFormatters', { ...BUILT_IN_FORMATTERS, ...(hostFormatters || {}), ...props.formatters })\n\t\treturn { environmentName, isBoard, ownLookClass }\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\treimporting: false,\n\t\t\tsetupWizardOpen: false,\n\t\t\t// The open tab's id; empty until a tab is picked or the address names one.\n\t\t\tchosenTabId: readTabFromAddress(this.tabQueryKey) || readStoredTab(this.tabStorageKey),\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * The tabs that have an id and a label.\n\t\t *\n\t\t * @return {Array<{id: string, label: string, count: number|null}>}\n\t\t * @spec openspec/changes/admin-settings-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-a-tab-strip\n\t\t */\n\t\ttabItems() {\n\t\t\treturn (Array.isArray(this.tabs) ? this.tabs : [])\n\t\t\t\t.filter((tab) => tab && typeof tab.id === 'string' && tab.id !== '' && typeof tab.label === 'string' && tab.label !== '')\n\t\t\t\t.map((tab) => ({ id: tab.id, label: tab.label, count: tab.count ?? null }))\n\t\t},\n\n\t\t/**\n\t\t * The open tab: the one picked or named in the address, else the first.\n\t\t *\n\t\t * @return {string} Its id, or '' without tabs.\n\t\t */\n\t\tactiveTabId() {\n\t\t\tconst ids = this.tabItems.map((tab) => tab.id)\n\t\t\treturn ids.includes(this.chosenTabId) ? this.chosenTabId : (ids[0] || '')\n\t\t},\n\n\t\t/**\n\t\t * Whether the shell's own content shows: always without tabs, else on\n\t\t * the first tab.\n\t\t *\n\t\t * @return {boolean}\n\t\t */\n\t\tonFirstTab() {\n\t\t\treturn this.tabItems.length === 0 || this.activeTabId === this.tabItems[0].id\n\t\t},\n\n\t\t/**\n\t\t * Whether the open tab has no panel of its own: its content is the\n\t\t * default slot, drawn below the strip (the first tab of DqInstellingenAlgemeen).\n\t\t * The strip then keeps no panel spacing, so the first card stands the\n\t\t * page's section gap below the strip.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/admin-shell-empty-tab-gap/specs/admin-shell-empty-tab-gap/spec.md#requirement-a-tab-without-a-panel-adds-no-space-under-the-strip\n\t\t */\n\t\topenPanelIsEmpty() {\n\t\t\treturn !this.$slots[`tab-${this.activeTabId}`]\n\t\t},\n\n\t\t/**\n\t\t * Whether the app's sections come before the version card.\n\t\t *\n\t\t * @return {boolean}\n\t\t * @spec openspec/changes/screens-admin-settings-version-card-end/specs/settings-board-look/spec.md#requirement-the-version-card-can-follow-the-apps-sections\n\t\t */\n\t\tversionCardAtEnd() {\n\t\t\treturn this.versionCardPosition === 'end'\n\t\t},\n\n\t\t/** @return {boolean} Whether the version card is the compact board card. */\n\t\tcompactCard() {\n\t\t\treturn this.isBoard && this.compact\n\t\t},\n\n\t\t/** @return {boolean} Whether the support lines are their own card at the end. */\n\t\tsupportAtEnd() {\n\t\t\treturn this.supportPosition === 'end'\n\t\t},\n\n\t\t/**\n\t\t * The crumbs that have a label.\n\t\t *\n\t\t * @return {Array<{label: string, href?: string}>}\n\t\t * @spec openspec/changes/screens-admin-settings-board-header/specs/settings-board-look/spec.md\n\t\t */\n\t\tcrumbs() {\n\t\t\treturn (Array.isArray(this.breadcrumbs) ? this.breadcrumbs : [])\n\t\t\t\t.filter((crumb) => crumb && typeof crumb.label === 'string' && crumb.label !== '')\n\t\t},\n\n\t\t/** @return {string} The accessible name of the breadcrumb navigation. */\n\t\tbreadcrumbLabel() {\n\t\t\treturn t('nextcloud-vue', 'Breadcrumb')\n\t\t},\n\n\t\t/**\n\t\t * The \"Help us\" link target: the forge's feature-request issue form\n\t\t * for `helpRepo`, on the fleet-default forge. Empty (hiding the\n\t\t * button) when no repo is configured.\n\t\t *\n\t\t * @return {string}\n\t\t */\n\t\thelpUrl() {\n\t\t\tconst repo = String(this.helpRepo || '').trim()\n\t\t\tif (!repo) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn buildFeatureRequestUrl(null, repo)\n\t\t},\n\n\t\t/** @return {string} The running version, falling back to AppHost initial state. */\n\t\tresolvedVersion() {\n\t\t\tif (this.appVersion) {\n\t\t\t\treturn this.appVersion\n\t\t\t}\n\t\t\treturn loadState(this.appId, 'version', 'Unknown')\n\t\t},\n\n\t\t/** @return {string} Configured version, falling back to AppHost initial state. */\n\t\tresolvedConfiguredVersion() {\n\t\t\treturn this.configuredVersion || loadState(this.appId, 'configuredVersion', '')\n\t\t},\n\n\t\t/** @return {boolean} Real up-to-date signal: explicit prop wins, else AppHost initial state. */\n\t\tresolvedIsUpToDate() {\n\t\t\tif (this.isUpToDate !== null) {\n\t\t\t\treturn this.isUpToDate\n\t\t\t}\n\t\t\treturn loadState(this.appId, 'isUpToDate', true)\n\t\t},\n\n\t\t/** @return {string} Page title, defaulting to \"<appName> Settings\". */\n\t\tresolvedTitle() {\n\t\t\treturn this.title || t('nextcloud-vue', '{app} Settings', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Page description. */\n\t\tresolvedDescription() {\n\t\t\treturn this.description || t('nextcloud-vue', 'Configure your {app} installation', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Version card description. */\n\t\tresolvedVersionDescription() {\n\t\t\tif (this.versionDescription) {\n\t\t\t\treturn this.versionDescription\n\t\t\t}\n\t\t\treturn this.compactCard\n\t\t\t\t? t('nextcloud-vue', 'About this {app} installation.', { app: this.appName })\n\t\t\t\t: t('nextcloud-vue', 'Information about the current {app} installation', { app: this.appName })\n\t\t},\n\n\t\t/** @return {string} Re-import endpoint. */\n\t\tresolvedReimportUrl() {\n\t\t\treturn prefixUrl(this.reimportUrl) || generateUrl('/apps/{appId}/api/settings/load', { appId: this.appId })\n\t\t},\n\n\t\t/** @return {string} Re-import button label. */\n\t\treimportLabel() {\n\t\t\treturn t('nextcloud-vue', 'Re-import configuration')\n\t\t},\n\n\t\t/** @return {string} Re-import in-progress label. */\n\t\timportingLabel() {\n\t\t\treturn t('nextcloud-vue', 'Importing…')\n\t\t},\n\n\t\t/** @return {string} Support footer heading. */\n\t\tsupportTitle() {\n\t\t\treturn t('nextcloud-vue', 'Support')\n\t\t},\n\n\t\t/** @return {string} Support footer line. */\n\t\tsupportLine() {\n\t\t\treturn t('nextcloud-vue', 'For support, contact us at')\n\t\t},\n\n\t\t/** @return {string} The words before the SLA address in the board card's support row. */\n\t\tslaInline() {\n\t\t\treturn t('nextcloud-vue', 'for an SLA')\n\t\t},\n\n\t\t/** @return {string} SLA footer line. */\n\t\tslaLine() {\n\t\t\treturn t('nextcloud-vue', 'For a Service Level Agreement (SLA), contact')\n\t\t},\n\n\t\t/** @return {string} Setup-wizard button label. */\n\t\tsetupLabel() {\n\t\t\treturn t('nextcloud-vue', 'Run setup wizard')\n\t\t},\n\n\t\t/** @return {string} Documentation button label (board header). */\n\t\tdocumentationLabel() {\n\t\t\treturn t('nextcloud-vue', 'Documentation')\n\t\t},\n\n\t\t/** @return {string} Help / suggest-feature button label. */\n\t\thelpLabel() {\n\t\t\treturn t('nextcloud-vue', 'Help us')\n\t\t},\n\t},\n\n\t/**\n\t * A page that opens on a tab other than the first (named in the address,\n\t * or remembered) tells the app once, as a click would, so a breadcrumb or\n\t * title that follows the tab is right from the first paint.\n\t *\n\t * @spec openspec/changes/admin-shell-remembers-tab/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-remember-the-last-tab\n\t */\n\tmounted() {\n\t\tif (this.tabItems.length > 0 && this.activeTabId !== this.tabItems[0].id) {\n\t\t\tthis.$emit('tab-change', this.activeTabId)\n\t\t}\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * A tab was picked in the strip: remember it, put it in the address\n\t\t * (replacing the entry, so Back leaves the page) and tell the app.\n\t\t *\n\t\t * @param {number} index The picked tab's index.\n\t\t * @return {void}\n\t\t * @spec openspec/changes/admin-settings-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-draw-a-tab-strip\n\t\t */\n\t\tonTabIndex(index) {\n\t\t\tconst tab = this.tabItems[index]\n\t\t\tif (!tab || tab.id === this.chosenTabId) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.chosenTabId = tab.id\n\t\t\twriteTabToAddress(this.tabQueryKey, tab.id)\n\t\t\tstoreTab(this.tabStorageKey, tab.id)\n\t\t\t/**\n\t\t\t * @event tab-change Emitted when the reader opens another tab. Payload: its `id`.\n\t\t\t */\n\t\t\tthis.$emit('tab-change', tab.id)\n\t\t},\n\n\t\t/** Forward the version card's update-button click to the parent. */\n\t\tonUpdate() {\n\t\t\t/**\n\t\t\t * @event update Emitted when the version card's update button is clicked.\n\t\t\t */\n\t\t\tthis.$emit('update')\n\t\t},\n\n\t\t/**\n\t\t * Re-import the app's OpenRegister configuration via the canonical\n\t\t * AppHost endpoint, then emit the result so the parent can refresh.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync reimport() {\n\t\t\tif (this.reimporting) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.reimporting = true\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(this.resolvedReimportUrl)\n\t\t\t\tconst data = response?.data ?? {}\n\t\t\t\t// AppHost returns { success, message, ... }; a bare 2xx also counts.\n\t\t\t\tif (data.success === false) {\n\t\t\t\t\tthrow new Error(data.message || t('nextcloud-vue', 'Re-import failed'))\n\t\t\t\t}\n\t\t\t\tshowSuccess(data.message || t('nextcloud-vue', 'Configuration re-imported successfully'))\n\t\t\t\t/**\n\t\t\t\t * @event reimported Emitted after a successful configuration re-import.\n\t\t\t\t * @type {object} The AppHost response payload.\n\t\t\t\t */\n\t\t\t\tthis.$emit('reimported', data)\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error?.response?.data?.message || error?.message || t('nextcloud-vue', 'Re-import failed')\n\t\t\t\tshowError(message)\n\t\t\t\t/**\n\t\t\t\t * @event reimport-error Emitted when a configuration re-import fails.\n\t\t\t\t * @type {Error} The error that caused the failure.\n\t\t\t\t */\n\t\t\t\tthis.$emit('reimport-error', error)\n\t\t\t} finally {\n\t\t\t\tthis.reimporting = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-admin-settings-shell {\n\tmax-width: 900px;\n}\n\n/* The board look lifts the width and lays the header and cards on a grid (look-board.css). */\n\n/* A tab without a panel of its own: the cards below the strip carry the gap. */\n.cn-admin-settings-shell__tabs--bare > :deep(.cn-tabs__content) {\n\tpadding-top: 0;\n}\n\n.cn-support-info {\n\tmargin-top: 16px;\n\tpadding-top: 16px;\n\tborder-top: 1px solid var(--color-border);\n}\n\n.cn-support-info h4 {\n\tmargin: 0 0 8px 0;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcolor: var(--color-main-text);\n}\n\n.cn-support-info p {\n\tmargin: 4px 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 14px;\n}\n\n.cn-support-info a {\n\tcolor: var(--color-primary-element);\n}\n</style>\n"],"names":["CnEnvironmentBanner","CnBuildiqEditButton","CnCredentials","CnSettingsSection","CnVersionInfoCard","CnSetupWizard","CnTab","CnTabs","t","axios"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { resolveComponent, openBlock, createElementBlock, normalizeClass, createBlock, createCommentVNode, createElementVNode, toDisplayString, Fragment, renderList, withCtx, createVNode, createTextVNode, renderSlot } from 'vue';
1
+ import { resolveComponent, openBlock, createElementBlock, normalizeClass, normalizeStyle, createBlock, createCommentVNode, createElementVNode, toDisplayString, Fragment, renderList, withCtx, createVNode, createTextVNode, renderSlot } from 'vue';
2
2
 
3
3
  const _hoisted_1 = {
4
4
  key: 2,
@@ -67,7 +67,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
67
67
  const _component_CnSetupWizard = resolveComponent("CnSetupWizard");
68
68
 
69
69
  return (openBlock(), createElementBlock("div", {
70
- class: normalizeClass(["cn-admin-settings-shell", [$setup.ownLookClass, $props.sectionColumns ? `cn-admin-settings-shell--columns-${$props.sectionColumns}` : '']])
70
+ class: normalizeClass(["cn-admin-settings-shell", [$setup.ownLookClass, $props.sectionColumns ? `cn-admin-settings-shell--columns-${$props.sectionColumns}` : '']]),
71
+ style: normalizeStyle($props.versionTitleSize ? { '--cn-board-version-title-size': `${$props.versionTitleSize}px` } : null)
71
72
  }, [
72
73
  ($setup.environmentName)
73
74
  ? (openBlock(), createBlock(_component_CnEnvironmentBanner, {
@@ -349,7 +350,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
349
350
  onClose: _cache[2] || (_cache[2] = $event => ($data.setupWizardOpen = false))
350
351
  }, null, 8 /* PROPS */, ["appId", "appName", "steps"]))
351
352
  : createCommentVNode("v-if", true)
352
- ], 2 /* CLASS */))
353
+ ], 6 /* CLASS, STYLE */))
353
354
  }
354
355
 
355
356
  export { render };