@conduction/nextcloud-vue 2.104.0 → 2.106.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 (224) hide show
  1. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
  2. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
  4. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  5. package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
  6. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +18 -0
  7. package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
  8. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +3 -1
  9. package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
  10. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
  11. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +18 -0
  12. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  13. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +1 -1
  14. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  15. package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
  16. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +93 -1
  17. package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
  18. package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
  19. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  20. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +6 -3
  21. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  22. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +3 -3
  23. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  24. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +112 -5
  25. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  26. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  27. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +9 -0
  28. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js.map +1 -0
  29. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js +24 -0
  30. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -0
  31. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js +49 -0
  32. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -0
  33. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
  34. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +36 -18
  35. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
  36. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +17 -38
  37. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
  38. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
  39. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  40. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  41. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
  42. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +1 -1
  43. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
  44. package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
  45. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +1 -1
  46. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +2 -0
  47. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -1
  48. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +32 -29
  49. package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -1
  50. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
  51. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +53 -2
  52. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
  53. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +119 -111
  54. package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
  55. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
  56. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +62 -1
  57. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  58. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  59. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
  60. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +73 -4
  61. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
  62. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +74 -27
  63. package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
  64. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +208 -46
  65. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  66. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +121 -98
  67. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  68. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
  69. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +24 -0
  70. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
  71. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +20 -4
  72. package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
  73. package/dist/esm/components/CnIndexPage/useSelfFetchList.js +25 -6
  74. package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
  75. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +112 -1
  76. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
  77. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +100 -44
  78. package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
  79. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
  80. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +67 -4
  81. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
  82. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +1 -1
  83. package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
  84. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js +9 -0
  85. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js.map +1 -0
  86. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js +88 -0
  87. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js.map +1 -0
  88. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js +39 -0
  89. package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js.map +1 -0
  90. package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
  91. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +295 -12
  92. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  93. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +267 -144
  94. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  95. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
  96. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +4 -0
  97. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
  98. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +3 -1
  99. package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
  100. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  101. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +93 -1
  102. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  103. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +322 -246
  104. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  105. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue.js +1 -1
  106. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +122 -7
  107. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
  108. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js +189 -93
  109. package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
  110. package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +1 -1
  111. package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -1
  112. package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +3 -3
  113. package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -1
  114. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
  115. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
  116. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +16 -4
  117. package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
  118. package/dist/esm/components/CnTabs/CnTabs.vue.js +1 -1
  119. package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
  120. package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
  121. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
  122. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +42 -0
  123. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  124. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +38 -19
  125. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  126. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js +9 -0
  127. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js.map +1 -0
  128. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js +258 -0
  129. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js.map +1 -0
  130. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js +69 -0
  131. package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js.map +1 -0
  132. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
  133. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +11 -0
  134. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
  135. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +4 -4
  136. package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
  137. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +16 -14
  138. package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
  139. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
  140. package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
  141. package/dist/esm/index.js +2 -0
  142. package/dist/esm/index.js.map +1 -1
  143. package/dist/esm/l10n/en.json.js +24 -1
  144. package/dist/esm/l10n/en.json.js.map +1 -1
  145. package/dist/esm/l10n/nl.json.js +24 -1
  146. package/dist/esm/l10n/nl.json.js.map +1 -1
  147. package/dist/esm/library-style.js +1 -1
  148. package/dist/esm/nextcloud-vue.css +1369 -748
  149. package/dist/esm/utils/dueText.js +18 -3
  150. package/dist/esm/utils/dueText.js.map +1 -1
  151. package/dist/esm/utils/libraryWidgetKeys.js +2 -0
  152. package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
  153. package/dist/esm/utils/nextcloudApps.js +45 -0
  154. package/dist/esm/utils/nextcloudApps.js.map +1 -0
  155. package/dist/esm/utils/scopeListLayout.js +9 -2
  156. package/dist/esm/utils/scopeListLayout.js.map +1 -1
  157. package/dist/esm/utils/sortOrder.js +11 -1
  158. package/dist/esm/utils/sortOrder.js.map +1 -1
  159. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  160. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  161. package/dist/esm/utils/visibleWhen.js +12 -4
  162. package/dist/esm/utils/visibleWhen.js.map +1 -1
  163. package/dist/nextcloud-vue.cjs.js +8965 -6497
  164. package/dist/nextcloud-vue.cjs.js.map +2 -2
  165. package/dist/nextcloud-vue.css +1369 -748
  166. package/l10n/en.json +24 -1
  167. package/l10n/nl.json +24 -1
  168. package/package.json +1 -1
  169. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -1
  170. package/src/components/CnCardGrid/CnCardGrid.md +2 -0
  171. package/src/components/CnCardGrid/CnCardGrid.vue +20 -0
  172. package/src/components/CnCellRenderer/CnCellRenderer.vue +19 -1
  173. package/src/components/CnChartWidget/CnChartWidget.md +2 -0
  174. package/src/components/CnChartWidget/CnChartWidget.vue +93 -1
  175. package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -6
  176. package/src/components/CnDetailPage/CnDetailPage.md +3 -2
  177. package/src/components/CnDetailPage/CnDetailPage.vue +112 -5
  178. package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +60 -0
  179. package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +36 -29
  180. package/src/components/CnFactsWidget/CnFactsWidget.vue +4 -0
  181. package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -1
  182. package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +4 -1
  183. package/src/components/CnFilesBrowser/CnFilesBrowser.vue +70 -4
  184. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +62 -1
  185. package/src/components/CnFlowsPage/CnFlowBoard.vue +132 -8
  186. package/src/components/CnIndexPage/CnIndexPage.md +8 -5
  187. package/src/components/CnIndexPage/CnIndexPage.vue +236 -54
  188. package/src/components/CnIndexPage/CnIndexPageWidgets.vue +36 -1
  189. package/src/components/CnIndexPage/useSelfFetchList.js +25 -6
  190. package/src/components/CnIndexSidebar/CnIndexSidebar.md +2 -0
  191. package/src/components/CnIndexSidebar/CnIndexSidebar.vue +148 -1
  192. package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +68 -5
  193. package/src/components/CnNoticeWidget/CnNoticeWidget.vue +153 -0
  194. package/src/components/CnNoticeWidget/index.js +12 -0
  195. package/src/components/CnObjectCard/CnObjectCard.md +1 -0
  196. package/src/components/CnObjectCard/CnObjectCard.vue +354 -13
  197. package/src/components/CnObjectSidebar/CnFilesTab.vue +6 -0
  198. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +190 -4
  199. package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +209 -9
  200. package/src/components/CnSettingsField/CnSettingsField.vue +4 -1
  201. package/src/components/CnSetupWizard/CnSetupWizard.vue +9 -1
  202. package/src/components/CnTabs/CnTabs.vue +11 -0
  203. package/src/components/CnTabsWidget/CnTabsWidget.vue +91 -18
  204. package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.md +11 -0
  205. package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue +382 -0
  206. package/src/components/CnTeamWorkloadWidget/index.js +14 -0
  207. package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +15 -4
  208. package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
  209. package/src/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
  210. package/src/components/index.js +2 -0
  211. package/src/css/dialog.css +20 -2
  212. package/src/css/index-page.css +14 -2
  213. package/src/css/look-board-detail.css +125 -8
  214. package/src/css/look-board-index.css +100 -4
  215. package/src/css/look-board.css +122 -14
  216. package/src/index.js +2 -1
  217. package/src/schemas/app-manifest-v2.schema.json +110 -8
  218. package/src/utils/dueText.js +18 -3
  219. package/src/utils/libraryWidgetKeys.js +2 -0
  220. package/src/utils/nextcloudApps.js +50 -0
  221. package/src/utils/scopeListLayout.js +9 -2
  222. package/src/utils/sortOrder.js +10 -0
  223. package/src/utils/validateManifestV2.compiled.js +3 -3
  224. package/src/utils/visibleWhen.js +12 -4
@@ -1 +1 @@
1
- {"version":3,"file":"CnSettingsField.vue2.js","sources":["../../../../src/components/CnSettingsField/CnSettingsField.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-settings-field\" :data-testid=\"`cn-settings-field-${field.key}`\">\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-if=\"kind === 'switch' || kind === 'boolean'\"\n\t\t\t:type=\"kind === 'switch' ? 'switch' : 'checkbox'\"\n\t\t\t:modelValue=\"!!modelValue\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\">\n\t\t\t{{ label }}\n\t\t</NcCheckboxRadioSwitch>\n\t\t<div v-else-if=\"kind === 'image'\"\n\t\t\tclass=\"cn-settings-field__image\"\n\t\t\trole=\"group\"\n\t\t\t:aria-labelledby=\"`${inputId}-label`\">\n\t\t\t<span :id=\"`${inputId}-label`\" class=\"cn-settings-field__image-label\">{{ label }}</span>\n\t\t\t<div class=\"cn-settings-field__image-row\">\n\t\t\t\t<span class=\"cn-settings-field__image-tile\" :data-testid=\"`cn-settings-field-image-${field.key}`\">\n\t\t\t\t\t<img v-if=\"stringValue\" :src=\"stringValue\" :alt=\"t('nextcloud-vue', 'Current {name}', { name: label })\">\n\t\t\t\t\t<span v-else class=\"cn-settings-field__image-initials\" aria-hidden=\"true\">{{ field.initials || '' }}</span>\n\t\t\t\t</span>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tref=\"file\"\n\t\t\t\t\tclass=\"hidden-visually\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t:accept=\"field.accept || 'image/*'\"\n\t\t\t\t\ttabindex=\"-1\"\n\t\t\t\t\t:aria-labelledby=\"`${inputId}-label`\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t@change=\"upload($event.target.files && $event.target.files[0])\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"!field.readOnly && field.uploadUrl\"\n\t\t\t\t\t:disabled=\"uploading\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t:data-testid=\"`cn-settings-field-upload-${field.key}`\"\n\t\t\t\t\t@click=\"$refs.file && $refs.file.click()\">\n\t\t\t\t\t<template v-if=\"uploading\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ field.uploadLabel || t('nextcloud-vue', 'Upload {name}', { name: label }) }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<NcSelect\n\t\t\tv-else-if=\"kind === 'select'\"\n\t\t\t:inputId=\"inputId\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"normalizedOptions\"\n\t\t\t:inputLabel=\"label\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:loading=\"optionsLoading\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:clearable=\"!field.required\"\n\t\t\tlabel=\"label\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue(optionValue($event))\" />\n\t\t<NcTextArea\n\t\t\tv-else-if=\"kind === 'textarea'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:rows=\"field.rows || 4\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'secret'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"password\"\n\t\t\tautocomplete=\"new-password\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.secretSet ? secretSetPlaceholder : (field.placeholder || '')\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'number'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"number\"\n\t\t\t:min=\"field.min\"\n\t\t\t:max=\"field.max\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event === '' ? null : Number($event))\" />\n\t\t<NcTextField\n\t\t\tv-else\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:type=\"kind === 'password' ? 'password' : 'text'\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<p v-if=\"shownError\"\n\t\t\t:id=\"`${inputId}-error`\"\n\t\t\tclass=\"cn-settings-field__error\"\n\t\t\t:data-testid=\"`cn-settings-field-error-${field.key}`\">\n\t\t\t{{ shownError }}\n\t\t</p>\n\t\t<p v-else-if=\"hint\" :id=\"`${inputId}-hint`\" class=\"cn-settings-field__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport { buildHeaders, prefixUrl } from '../../utils/headers.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\nlet fieldUid = 0\n\n/** Field types and the names CnSettingsPage's manifest uses for them. */\nconst KIND_ALIASES = { enum: 'select', string: 'text' }\n\n/**\n * CnSettingsField - one settings field: the control for its type with its\n * label, and under it an error or a hint. Shared by CnSettingsPage and\n * CnSettingsFieldsSection.\n *\n * Types: `text` (default), `textarea`, `number`, `switch`, `boolean` (a checkbox),\n * `select` (`enum`) with static `options` or options read from `optionsUrl`,\n * `password` (a masked input that shows its value back) and `secret`\n * (replace-only: the input stays empty, and with `secretSet` says a value is\n * stored; the host sends it only when something is typed), and `image` (a\n * preview tile, the initials without an image, and an upload button that\n * posts the file to `uploadUrl` at once and emits `uploaded`).\n *\n * ```vue\n * <CnSettingsField\n * :field=\"{ key: 'apiKey', label: 'API key', type: 'secret', secretSet: true }\"\n * v-model=\"form.apiKey\" />\n * ```\n */\nexport default {\n\tname: 'CnSettingsField',\n\n\tcomponents: { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField },\n\n\tprops: {\n\t\t/**\n\t\t * The field: `{ key, label, type?, options?, optionsUrl?, optionsPath?,\n\t\t * optionLabel?, optionValue?, placeholder?, rows?, min?, max?, required?,\n\t\t * readOnly?, secretSet? }`. `label` arrives translated.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tfield: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * The value: text, a number, a boolean or a select value. Any type,\n\t\t * because a Boolean in a type list would read an empty string as true.\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: null,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** A validation message, drawn under the control and tied to it. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A hint under the control (not drawn while there is an error). */\n\t\thint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['update:modelValue', 'uploaded'],\n\n\tdata() {\n\t\tfieldUid += 1\n\t\treturn {\n\t\t\tuid: fieldUid,\n\t\t\tfetchedOptions: null,\n\t\t\toptionsLoading: false,\n\t\t\tuploading: false,\n\t\t\tuploadError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The control kind. */\n\t\tkind() {\n\t\t\tconst type = String(this.field.type || 'text')\n\t\t\treturn KIND_ALIASES[type] || type\n\t\t},\n\n\t\t/** @return {string} The label. */\n\t\tlabel() {\n\t\t\treturn String(this.field.label || this.field.key || '')\n\t\t},\n\n\t\t/** @return {string} The control's id. */\n\t\tinputId() {\n\t\t\treturn `cn-settings-field-${this.uid}-${String(this.field.key).replace(/[^A-Za-z0-9_-]/g, '-')}`\n\t\t},\n\n\t\t/** @return {string} The message shown under the control: an upload failure, else `error`. */\n\t\tshownError() {\n\t\t\treturn this.uploadError || this.error\n\t\t},\n\n\t\t/** @return {string|null} The id of the error or hint the control is described by. */\n\t\tdescribedBy() {\n\t\t\tif (this.shownError) {\n\t\t\t\treturn `${this.inputId}-error`\n\t\t\t}\n\t\t\treturn this.hint ? `${this.inputId}-hint` : null\n\t\t},\n\n\t\t/** @return {string} The value as text for a text control. */\n\t\tstringValue() {\n\t\t\treturn this.modelValue === null || this.modelValue === undefined ? '' : String(this.modelValue)\n\t\t},\n\n\t\t/** @return {string} The placeholder of a secret that is stored. */\n\t\tsecretSetPlaceholder() {\n\t\t\treturn t('nextcloud-vue', 'Stored. Type a new value to replace it.')\n\t\t},\n\n\t\t/**\n\t\t * The select options as `{ label, value }`: the static `options` (strings,\n\t\t * numbers or objects), or those read from `optionsUrl`.\n\t\t *\n\t\t * @return {Array<{label: string, value: (string|number|boolean)}>}\n\t\t */\n\t\tnormalizedOptions() {\n\t\t\tconst raw = Array.isArray(this.field.options) ? this.field.options : (this.fetchedOptions || [])\n\t\t\treturn raw.map((option) => (option && typeof option === 'object'\n\t\t\t\t? { ...option, label: String(option.label ?? option.value ?? ''), value: option.value }\n\t\t\t\t: { label: String(option), value: option }))\n\t\t},\n\n\t\t/** @return {object|null} The option the value selects, for NcSelect. */\n\t\tselectedOption() {\n\t\t\tif (this.modelValue === null || this.modelValue === undefined || this.modelValue === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.normalizedOptions.find((option) => option.value === this.modelValue)\n\t\t\t\t|| { label: String(this.modelValue), value: this.modelValue }\n\t\t},\n\t},\n\n\twatch: {\n\t\t'field.optionsUrl': {\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\n\t\t\timmediate: true,\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Upload a chosen image to `uploadUrl` as multipart form data (the\n\t\t * file under `uploadField`, default `image`, plus `uploadParams`), then\n\t\t * take the new image url from the answer at `uploadValuePath` (or a\n\t\t * cache-busted `previewUrl`).\n\t\t *\n\t\t * @param {File|undefined} file The chosen file.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/settings-fields-section/specs/settings-fields-section/spec.md#requirement-an-image-field-uploads-at-once\n\t\t */\n\t\tasync upload(file) {\n\t\t\tif (!file || !this.field.uploadUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = new FormData()\n\t\t\tfor (const [name, value] of Object.entries(this.field.uploadParams || {})) {\n\t\t\t\tform.append(name, value)\n\t\t\t}\n\t\t\tform.append(this.field.uploadField || 'image', file)\n\t\t\tthis.uploading = true\n\t\t\tthis.uploadError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.field.uploadUrl), form)\n\t\t\t\tconst fromAnswer = this.field.uploadValuePath ? readPath(response?.data, this.field.uploadValuePath) : ''\n\t\t\t\tconst next = fromAnswer || (this.field.previewUrl ? `${prefixUrl(this.field.previewUrl)}${this.field.previewUrl.includes('?') ? '&' : '?'}v=${Date.now()}` : '')\n\t\t\t\t/**\n\t\t\t\t * @event uploaded An image was uploaded. Payload: its new url.\n\t\t\t\t */\n\t\t\t\tthis.$emit('uploaded', next)\n\t\t\t} catch (error) {\n\t\t\t\tthis.uploadError = t('nextcloud-vue', 'The image could not be uploaded: {reason}', { reason: serverErrorMessage(error) })\n\t\t\t} finally {\n\t\t\t\tthis.uploading = false\n\t\t\t\tif (this.$refs.file) {\n\t\t\t\t\tthis.$refs.file.value = ''\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Report a new value.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @return {void}\n\t\t */\n\t\temitValue(value) {\n\t\t\t/**\n\t\t\t * @event update:modelValue The value changed. Payload: the new value.\n\t\t\t */\n\t\t\tthis.$emit('update:modelValue', value)\n\t\t},\n\n\t\t/**\n\t\t * The storable value of what NcSelect emits.\n\t\t *\n\t\t * @param {object|string|number|null} emitted An option, or null on clear.\n\t\t * @return {string|number|boolean|null}\n\t\t */\n\t\toptionValue(emitted) {\n\t\t\tif (emitted === null || emitted === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn typeof emitted === 'object' && 'value' in emitted ? emitted.value : emitted\n\t\t},\n\n\t\t/**\n\t\t * Read a sourced select's options: a list (or the list at\n\t\t * `optionsPath`, or under `results`) mapped through `optionLabel` and\n\t\t * `optionValue` (dotted paths; default `label`/`title`/`name` and `value`/`id`).\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tconst url = this.kind === 'select' && !Array.isArray(this.field.options) ? this.field.optionsUrl : ''\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.optionsLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthis.fetchedOptions = []\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = this.field.optionsPath ? readPath(data, this.field.optionsPath) : (Array.isArray(data) ? data : data?.results)\n\t\t\t\tthis.fetchedOptions = (Array.isArray(list) ? list : []).map((item) => {\n\t\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\t\treturn { label: String(item), value: item }\n\t\t\t\t\t}\n\t\t\t\t\tconst value = this.field.optionValue ? readPath(item, this.field.optionValue) : (item.value ?? item.id)\n\t\t\t\t\tconst label = this.field.optionLabel ? readPath(item, this.field.optionLabel) : (item.label ?? item.title ?? item.name ?? value)\n\t\t\t\t\treturn { label: String(label ?? ''), value }\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.optionsLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-settings-field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-settings-field__hint,\n.cn-settings-field__error {\n\tmargin: 0;\n\tfont-size: 13px;\n\tline-height: 1.4;\n}\n\n.cn-settings-field__image {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-settings-field__image-label {\n\tfont-weight: 600;\n}\n\n.cn-settings-field__image-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px;\n}\n\n.cn-settings-field__image-tile {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 64px;\n\theight: 64px;\n\toverflow: hidden;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-settings-field__image-tile img {\n\tmax-width: 100%;\n\tmax-height: 100%;\n\tobject-fit: contain;\n}\n\n.cn-settings-field__image-initials {\n\tfont-size: 20px;\n\tfont-weight: 700;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n}\n\n.cn-settings-field__hint {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-field__error {\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["t","axios"],"mappings":";;;;;;;AAgIA,IAAI,QAAO,GAAI,EAAA;;AAEf;AACA,MAAM,YAAW,GAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAO,GAAA;;AAEtD;;;;AAIC;AACA;AACA;;AAEA;;;;AAIA;AACA;AACA;AACA;;AAEA;;AAED,aAAe;CACd,IAAI,EAAE,iBAAiB;;AAEvB,CAAA,UAAU,EAAE,EAAE,QAAQ,EAAE,qBAAqB,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa;;AAEjG,CAAA,KAAK,EAAE;AACN;;AAEC;;AAEA;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,QAAQ,EAAE,IAAI;GACd;;AAED;;;;EAIA,UAAU,EAAE;AACX,GAAA,IAAI,EAAE,IAAI;GACV,OAAO,EAAE,IAAI;GACb;;;AAGD,EAAA,KAAK,EAAE;GACN,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;;;EAGD,IAAI,EAAE;GACL,IAAI,EAAE,MAAM;GACZ,OAAO,EAAE,EAAE;GACX;EACD;;AAED,CAAA,KAAK,EAAE,CAAC,mBAAmB,EAAE,UAAU,CAAC;;AAExC,CAAA,IAAI,GAAG;EACN,QAAO,IAAK,EAAA;AACZ,EAAA,OAAO;GACN,GAAG,EAAE,QAAQ;AACb,GAAA,cAAc,EAAE,IAAI;AACpB,GAAA,cAAc,EAAE,KAAK;AACrB,GAAA,SAAS,EAAE,KAAK;AAChB,GAAA,WAAW,EAAE,EAAE;AAChB,GAAA;EACA;;AAED,CAAA,QAAQ,EAAE;AACT;AACA,EAAA,IAAI,GAAG;AACN,GAAA,MAAM,IAAG,GAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAG,IAAK,MAAM,EAAA;GAC7C,OAAO,YAAY,CAAC,IAAI,CAAA,IAAK,IAAG;GAChC;;;AAGD,EAAA,KAAK,GAAG;GACP,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAM,IAAG,IAAI,CAAC,KAAK,CAAC,GAAI,IAAG,EAAE,CAAA;GACtD;;AAED;AACA,EAAA,OAAO,GAAG;AACT,GAAA,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC,CAAA;GAC/F;;AAED;EACA,UAAU,GAAG;AACZ,GAAA,OAAO,IAAI,CAAC,WAAU,IAAK,IAAI,CAAC,KAAI;GACpC;;AAED;EACA,WAAW,GAAG;AACb,GAAA,IAAI,IAAI,CAAC,UAAU,EAAE;IACpB,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAA;AAC9B,IAAA;AACA,GAAA,OAAO,IAAI,CAAC,IAAG,GAAI,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,IAAG;GAC/C;;;EAGD,WAAW,GAAG;AACb,GAAA,OAAO,IAAI,CAAC,UAAW,KAAI,QAAQ,IAAI,CAAC,UAAW,KAAI,YAAY,KAAK,MAAM,CAAC,IAAI,CAAC,UAAU,CAAA;GAC9F;;;EAGD,oBAAoB,GAAG;GACtB,OAAOA,SAAC,CAAC,eAAe,EAAE,yCAAyC,CAAA;GACnE;;AAED;;;AAGC;;;AAGD,EAAA,iBAAiB,GAAG;AACnB,GAAA,MAAM,MAAM,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAE,GAAE,IAAI,CAAC,KAAK,CAAC,OAAQ,IAAG,IAAI,CAAC,kBAAkB,EAAE,EAAA;GAC/F,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,MAAM,MAAO,IAAG,OAAO,MAAO,KAAI,QAAO;AAC9D,MAAE,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAI,IAAK,MAAM,CAAC,KAAI,IAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAM,EAAA;AACtF,MAAE,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,MAAK,EAAG,CAAC,CAAA;GAC5C;;;AAGD,EAAA,cAAc,GAAG;AAChB,GAAA,IAAI,IAAI,CAAC,UAAS,KAAM,IAAG,IAAK,IAAI,CAAC,UAAW,KAAI,SAAU,IAAG,IAAI,CAAC,eAAe,EAAE,EAAE;AACxF,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,KAAI,KAAM,IAAI,CAAC,UAAU,CAAA;OAC3E,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,UAAW,EAAA;GAC7D;EACD;;AAED,CAAA,KAAK,EAAE;AACN,EAAA,kBAAkB,EAAE;AACnB,GAAA,OAAO,GAAG;AACT,IAAA,IAAI,CAAC,WAAW,GAAC;IACjB;;AAED,GAAA,SAAS,EAAE,IAAI;GACf;EACD;;AAED,CAAA,OAAO,EAAE;KACRA,SAAC;;AAED;;AAEC;;;AAGA;AACA;;AAEA;;AAED,EAAA,MAAM,MAAM,CAAC,IAAI,EAAE;AAClB,GAAA,IAAI,CAAC,IAAK,IAAG,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE;IACnC,MAAK;AACN,IAAA;GACA,MAAM,OAAO,IAAI,QAAQ,GAAC;AAC1B,GAAA,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAE,IAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,YAAW,IAAK,EAAE,CAAC,EAAE;IAC1E,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAA;AACxB,IAAA;GACA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,OAAO,EAAE,IAAI,EAAA;AACnD,GAAA,IAAI,CAAC,SAAQ,GAAI,KAAG;AACpB,GAAA,IAAI,CAAC,WAAU,GAAI,GAAC;AACpB,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAMC,cAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAA;IACvE,MAAM,aAAa,IAAI,CAAC,KAAK,CAAC,kBAAkB,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAE,GAAE,GAAC;AACxG,IAAA,MAAM,IAAK,GAAE,UAAW,KAAI,IAAI,CAAC,KAAK,CAAC,UAAW,GAAE,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAE,GAAE,GAAI,GAAE,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAE,GAAE,EAAE,EAAA;AAC/J;;;IAGA,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAA;IAC1B,CAAA,OAAO,KAAK,EAAE;IACf,IAAI,CAAC,WAAY,GAAED,SAAC,CAAC,eAAe,EAAE,2CAA2C,EAAE,EAAE,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAA,EAAG,EAAA;AACzH,IAAA,SAAU;AACT,IAAA,IAAI,CAAC,SAAQ,GAAI,MAAI;AACrB,IAAA,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;KACpB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAM,GAAE,GAAC;AAC1B,KAAA;AACD,IAAA;GACA;;AAED;AACC;AACA;;;;AAID,EAAA,SAAS,CAAC,KAAK,EAAE;AAChB;;;AAGA,GAAA,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,EAAA;GACrC;;AAED;AACC;AACA;AACA;AACA;;AAED,EAAA,WAAW,CAAC,OAAO,EAAE;AACpB,GAAA,IAAI,OAAQ,KAAI,QAAQ,OAAM,KAAM,SAAS,EAAE;AAC9C,IAAA,OAAO,IAAG;AACX,IAAA;AACA,GAAA,OAAO,OAAO,OAAQ,KAAI,QAAS,IAAG,OAAQ,IAAG,OAAQ,GAAE,OAAO,CAAC,KAAM,GAAE,OAAM;GACjF;;AAED;AACC;;AAEA;AACA;;;AAGD,EAAA,MAAM,WAAW,GAAG;AACnB,GAAA,MAAM,MAAM,IAAI,CAAC,IAAG,KAAM,QAAO,IAAK,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,UAAS,GAAI,GAAC;AACpG,GAAA,IAAI,CAAC,GAAG,EAAE;IACT,MAAK;AACN,IAAA;GACA,IAAI,CAAC,cAAe,GAAE,KAAG;AACzB,GAAA,IAAI;AACH,IAAA,MAAM,QAAO,GAAI,MAAM,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,EAAE,YAAY,IAAI,EAAA;AACxE,IAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AACjB,KAAA,IAAI,CAAC,cAAa,GAAI,GAAC;KACvB,MAAK;AACN,KAAA;IACA,MAAM,IAAK,GAAE,MAAM,QAAQ,CAAC,IAAI,GAAC;IACjC,MAAM,IAAG,GAAI,IAAI,CAAC,KAAK,CAAC,WAAU,GAAI,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,OAAO,CAAC,IAAI,IAAI,IAAK,GAAE,IAAI,EAAE,OAAO,EAAA;AAC1H,IAAA,IAAI,CAAC,cAAa,GAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAE,GAAE,IAAG,GAAI,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,KAAK;AACrE,KAAA,IAAI,CAAC,IAAK,IAAG,OAAO,IAAG,KAAM,QAAQ,EAAE;AACtC,MAAA,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAK,EAAA;AAC3C,MAAA;AACA,KAAA,MAAM,KAAI,GAAI,IAAI,CAAC,KAAK,CAAC,WAAY,GAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAE,IAAG,IAAI,CAAC,KAAM,IAAG,IAAI,CAAC,EAAE,EAAA;KACtG,MAAM,KAAM,GAAE,IAAI,CAAC,KAAK,CAAC,WAAY,GAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,KAAI,IAAK,IAAI,CAAC,KAAI,IAAK,IAAI,CAAC,IAAG,IAAK,KAAK,EAAA;AAC/H,KAAA,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,KAAM,EAAA;KAC3C,EAAA;AACF,IAAA,CAAE,MAAM;AACP,IAAA,IAAI,CAAC,cAAa,GAAI,GAAC;AACxB,IAAA,SAAU;IACT,IAAI,CAAC,iBAAiB,MAAI;AAC3B,IAAA;GACA;EACD;AACF;;;;"}
1
+ {"version":3,"file":"CnSettingsField.vue2.js","sources":["../../../../src/components/CnSettingsField/CnSettingsField.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-settings-field\" :data-testid=\"`cn-settings-field-${field.key}`\">\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-if=\"kind === 'switch' || kind === 'boolean'\"\n\t\t\t:type=\"kind === 'switch' ? 'switch' : 'checkbox'\"\n\t\t\t:modelValue=\"!!modelValue\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\">\n\t\t\t{{ label }}\n\t\t</NcCheckboxRadioSwitch>\n\t\t<div v-else-if=\"kind === 'image'\"\n\t\t\tclass=\"cn-settings-field__image\"\n\t\t\trole=\"group\"\n\t\t\t:aria-labelledby=\"`${inputId}-label`\">\n\t\t\t<!-- `hideLabel` keeps the name for a screen reader only. -->\n\t\t\t<span :id=\"`${inputId}-label`\"\n\t\t\t\tclass=\"cn-settings-field__image-label\"\n\t\t\t\t:class=\"{ 'hidden-visually': field.hideLabel === true }\">{{ label }}</span>\n\t\t\t<div class=\"cn-settings-field__image-row\">\n\t\t\t\t<span class=\"cn-settings-field__image-tile\" :data-testid=\"`cn-settings-field-image-${field.key}`\">\n\t\t\t\t\t<img v-if=\"stringValue\" :src=\"stringValue\" :alt=\"t('nextcloud-vue', 'Current {name}', { name: label })\">\n\t\t\t\t\t<span v-else class=\"cn-settings-field__image-initials\" aria-hidden=\"true\">{{ field.initials || '' }}</span>\n\t\t\t\t</span>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tref=\"file\"\n\t\t\t\t\tclass=\"hidden-visually\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t:accept=\"field.accept || 'image/*'\"\n\t\t\t\t\ttabindex=\"-1\"\n\t\t\t\t\t:aria-labelledby=\"`${inputId}-label`\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t@change=\"upload($event.target.files && $event.target.files[0])\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"!field.readOnly && field.uploadUrl\"\n\t\t\t\t\t:disabled=\"uploading\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t:data-testid=\"`cn-settings-field-upload-${field.key}`\"\n\t\t\t\t\t@click=\"$refs.file && $refs.file.click()\">\n\t\t\t\t\t<template v-if=\"uploading\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ field.uploadLabel || t('nextcloud-vue', 'Upload {name}', { name: label }) }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<NcSelect\n\t\t\tv-else-if=\"kind === 'select'\"\n\t\t\t:inputId=\"inputId\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"normalizedOptions\"\n\t\t\t:inputLabel=\"label\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:loading=\"optionsLoading\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:clearable=\"!field.required\"\n\t\t\tlabel=\"label\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue(optionValue($event))\" />\n\t\t<NcTextArea\n\t\t\tv-else-if=\"kind === 'textarea'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:rows=\"field.rows || 4\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'secret'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"password\"\n\t\t\tautocomplete=\"new-password\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.secretSet ? secretSetPlaceholder : (field.placeholder || '')\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'number'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"number\"\n\t\t\t:min=\"field.min\"\n\t\t\t:max=\"field.max\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event === '' ? null : Number($event))\" />\n\t\t<NcTextField\n\t\t\tv-else\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:type=\"kind === 'password' ? 'password' : 'text'\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<p v-if=\"shownError\"\n\t\t\t:id=\"`${inputId}-error`\"\n\t\t\tclass=\"cn-settings-field__error\"\n\t\t\t:data-testid=\"`cn-settings-field-error-${field.key}`\">\n\t\t\t{{ shownError }}\n\t\t</p>\n\t\t<p v-else-if=\"hint\" :id=\"`${inputId}-hint`\" class=\"cn-settings-field__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport { buildHeaders, prefixUrl } from '../../utils/headers.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\nlet fieldUid = 0\n\n/** Field types and the names CnSettingsPage's manifest uses for them. */\nconst KIND_ALIASES = { enum: 'select', string: 'text' }\n\n/**\n * CnSettingsField - one settings field: the control for its type with its\n * label, and under it an error or a hint. Shared by CnSettingsPage and\n * CnSettingsFieldsSection.\n *\n * Types: `text` (default), `textarea`, `number`, `switch`, `boolean` (a checkbox),\n * `select` (`enum`) with static `options` or options read from `optionsUrl`,\n * `password` (a masked input that shows its value back) and `secret`\n * (replace-only: the input stays empty, and with `secretSet` says a value is\n * stored; the host sends it only when something is typed), and `image` (a\n * preview tile, the initials without an image, and an upload button that\n * posts the file to `uploadUrl` at once and emits `uploaded`).\n *\n * ```vue\n * <CnSettingsField\n * :field=\"{ key: 'apiKey', label: 'API key', type: 'secret', secretSet: true }\"\n * v-model=\"form.apiKey\" />\n * ```\n */\nexport default {\n\tname: 'CnSettingsField',\n\n\tcomponents: { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField },\n\n\tprops: {\n\t\t/**\n\t\t * The field: `{ key, label, type?, options?, optionsUrl?, optionsPath?,\n\t\t * optionLabel?, optionValue?, placeholder?, rows?, min?, max?, required?,\n\t\t * readOnly?, secretSet? }`. `label` arrives translated.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tfield: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * The value: text, a number, a boolean or a select value. Any type,\n\t\t * because a Boolean in a type list would read an empty string as true.\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: null,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** A validation message, drawn under the control and tied to it. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A hint under the control (not drawn while there is an error). */\n\t\thint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['update:modelValue', 'uploaded'],\n\n\tdata() {\n\t\tfieldUid += 1\n\t\treturn {\n\t\t\tuid: fieldUid,\n\t\t\tfetchedOptions: null,\n\t\t\toptionsLoading: false,\n\t\t\tuploading: false,\n\t\t\tuploadError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The control kind. */\n\t\tkind() {\n\t\t\tconst type = String(this.field.type || 'text')\n\t\t\treturn KIND_ALIASES[type] || type\n\t\t},\n\n\t\t/** @return {string} The label. */\n\t\tlabel() {\n\t\t\treturn String(this.field.label || this.field.key || '')\n\t\t},\n\n\t\t/** @return {string} The control's id. */\n\t\tinputId() {\n\t\t\treturn `cn-settings-field-${this.uid}-${String(this.field.key).replace(/[^A-Za-z0-9_-]/g, '-')}`\n\t\t},\n\n\t\t/** @return {string} The message shown under the control: an upload failure, else `error`. */\n\t\tshownError() {\n\t\t\treturn this.uploadError || this.error\n\t\t},\n\n\t\t/** @return {string|null} The id of the error or hint the control is described by. */\n\t\tdescribedBy() {\n\t\t\tif (this.shownError) {\n\t\t\t\treturn `${this.inputId}-error`\n\t\t\t}\n\t\t\treturn this.hint ? `${this.inputId}-hint` : null\n\t\t},\n\n\t\t/** @return {string} The value as text for a text control. */\n\t\tstringValue() {\n\t\t\treturn this.modelValue === null || this.modelValue === undefined ? '' : String(this.modelValue)\n\t\t},\n\n\t\t/** @return {string} The placeholder of a secret that is stored. */\n\t\tsecretSetPlaceholder() {\n\t\t\treturn t('nextcloud-vue', 'Stored. Type a new value to replace it.')\n\t\t},\n\n\t\t/**\n\t\t * The select options as `{ label, value }`: the static `options` (strings,\n\t\t * numbers or objects), or those read from `optionsUrl`.\n\t\t *\n\t\t * @return {Array<{label: string, value: (string|number|boolean)}>}\n\t\t */\n\t\tnormalizedOptions() {\n\t\t\tconst raw = Array.isArray(this.field.options) ? this.field.options : (this.fetchedOptions || [])\n\t\t\treturn raw.map((option) => (option && typeof option === 'object'\n\t\t\t\t? { ...option, label: String(option.label ?? option.value ?? ''), value: option.value }\n\t\t\t\t: { label: String(option), value: option }))\n\t\t},\n\n\t\t/** @return {object|null} The option the value selects, for NcSelect. */\n\t\tselectedOption() {\n\t\t\tif (this.modelValue === null || this.modelValue === undefined || this.modelValue === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.normalizedOptions.find((option) => option.value === this.modelValue)\n\t\t\t\t|| { label: String(this.modelValue), value: this.modelValue }\n\t\t},\n\t},\n\n\twatch: {\n\t\t'field.optionsUrl': {\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\n\t\t\timmediate: true,\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Upload a chosen image to `uploadUrl` as multipart form data (the\n\t\t * file under `uploadField`, default `image`, plus `uploadParams`), then\n\t\t * take the new image url from the answer at `uploadValuePath` (or a\n\t\t * cache-busted `previewUrl`).\n\t\t *\n\t\t * @param {File|undefined} file The chosen file.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/settings-fields-section/specs/settings-fields-section/spec.md#requirement-an-image-field-uploads-at-once\n\t\t */\n\t\tasync upload(file) {\n\t\t\tif (!file || !this.field.uploadUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = new FormData()\n\t\t\tfor (const [name, value] of Object.entries(this.field.uploadParams || {})) {\n\t\t\t\tform.append(name, value)\n\t\t\t}\n\t\t\tform.append(this.field.uploadField || 'image', file)\n\t\t\tthis.uploading = true\n\t\t\tthis.uploadError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.field.uploadUrl), form)\n\t\t\t\tconst fromAnswer = this.field.uploadValuePath ? readPath(response?.data, this.field.uploadValuePath) : ''\n\t\t\t\tconst next = fromAnswer || (this.field.previewUrl ? `${prefixUrl(this.field.previewUrl)}${this.field.previewUrl.includes('?') ? '&' : '?'}v=${Date.now()}` : '')\n\t\t\t\t/**\n\t\t\t\t * @event uploaded An image was uploaded. Payload: its new url.\n\t\t\t\t */\n\t\t\t\tthis.$emit('uploaded', next)\n\t\t\t} catch (error) {\n\t\t\t\tthis.uploadError = t('nextcloud-vue', 'The image could not be uploaded: {reason}', { reason: serverErrorMessage(error) })\n\t\t\t} finally {\n\t\t\t\tthis.uploading = false\n\t\t\t\tif (this.$refs.file) {\n\t\t\t\t\tthis.$refs.file.value = ''\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Report a new value.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @return {void}\n\t\t */\n\t\temitValue(value) {\n\t\t\t/**\n\t\t\t * @event update:modelValue The value changed. Payload: the new value.\n\t\t\t */\n\t\t\tthis.$emit('update:modelValue', value)\n\t\t},\n\n\t\t/**\n\t\t * The storable value of what NcSelect emits.\n\t\t *\n\t\t * @param {object|string|number|null} emitted An option, or null on clear.\n\t\t * @return {string|number|boolean|null}\n\t\t */\n\t\toptionValue(emitted) {\n\t\t\tif (emitted === null || emitted === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn typeof emitted === 'object' && 'value' in emitted ? emitted.value : emitted\n\t\t},\n\n\t\t/**\n\t\t * Read a sourced select's options: a list (or the list at\n\t\t * `optionsPath`, or under `results`) mapped through `optionLabel` and\n\t\t * `optionValue` (dotted paths; default `label`/`title`/`name` and `value`/`id`).\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tconst url = this.kind === 'select' && !Array.isArray(this.field.options) ? this.field.optionsUrl : ''\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.optionsLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthis.fetchedOptions = []\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = this.field.optionsPath ? readPath(data, this.field.optionsPath) : (Array.isArray(data) ? data : data?.results)\n\t\t\t\tthis.fetchedOptions = (Array.isArray(list) ? list : []).map((item) => {\n\t\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\t\treturn { label: String(item), value: item }\n\t\t\t\t\t}\n\t\t\t\t\tconst value = this.field.optionValue ? readPath(item, this.field.optionValue) : (item.value ?? item.id)\n\t\t\t\t\tconst label = this.field.optionLabel ? readPath(item, this.field.optionLabel) : (item.label ?? item.title ?? item.name ?? value)\n\t\t\t\t\treturn { label: String(label ?? ''), value }\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.optionsLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-settings-field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-settings-field__hint,\n.cn-settings-field__error {\n\tmargin: 0;\n\tfont-size: 13px;\n\tline-height: 1.4;\n}\n\n.cn-settings-field__image {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-settings-field__image-label {\n\tfont-weight: 600;\n}\n\n.cn-settings-field__image-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px;\n}\n\n.cn-settings-field__image-tile {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 64px;\n\theight: 64px;\n\toverflow: hidden;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-settings-field__image-tile img {\n\tmax-width: 100%;\n\tmax-height: 100%;\n\tobject-fit: contain;\n}\n\n.cn-settings-field__image-initials {\n\tfont-size: 20px;\n\tfont-weight: 700;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n}\n\n.cn-settings-field__hint {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-field__error {\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["t","axios"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { resolveComponent, openBlock, createElementBlock, createBlock, withCtx, createTextVNode, toDisplayString, createElementVNode, createSlots, createVNode, createCommentVNode } from 'vue';
1
+ import { resolveComponent, openBlock, createElementBlock, createBlock, withCtx, createTextVNode, toDisplayString, createElementVNode, normalizeClass, createSlots, createVNode, createCommentVNode } from 'vue';
2
2
 
3
3
  const _hoisted_1 = ["data-testid"];
4
4
  const _hoisted_2 = ["aria-labelledby"];
@@ -50,8 +50,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
50
50
  }, [
51
51
  createElementVNode("span", {
52
52
  id: `${$options.inputId}-label`,
53
- class: "cn-settings-field__image-label"
54
- }, toDisplayString($options.label), 9 /* TEXT, PROPS */, _hoisted_3),
53
+ class: normalizeClass(["cn-settings-field__image-label", { 'hidden-visually': $props.field.hideLabel === true }])
54
+ }, toDisplayString($options.label), 11 /* TEXT, CLASS, PROPS */, _hoisted_3),
55
55
  createElementVNode("div", _hoisted_4, [
56
56
  createElementVNode("span", {
57
57
  class: "cn-settings-field__image-tile",
@@ -1 +1 @@
1
- {"version":3,"file":"CnSettingsField.vue3.js","sources":["../../../../src/components/CnSettingsField/CnSettingsField.vue?vue&type=template&id=d2218996&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-settings-field\" :data-testid=\"`cn-settings-field-${field.key}`\">\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-if=\"kind === 'switch' || kind === 'boolean'\"\n\t\t\t:type=\"kind === 'switch' ? 'switch' : 'checkbox'\"\n\t\t\t:modelValue=\"!!modelValue\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\">\n\t\t\t{{ label }}\n\t\t</NcCheckboxRadioSwitch>\n\t\t<div v-else-if=\"kind === 'image'\"\n\t\t\tclass=\"cn-settings-field__image\"\n\t\t\trole=\"group\"\n\t\t\t:aria-labelledby=\"`${inputId}-label`\">\n\t\t\t<span :id=\"`${inputId}-label`\" class=\"cn-settings-field__image-label\">{{ label }}</span>\n\t\t\t<div class=\"cn-settings-field__image-row\">\n\t\t\t\t<span class=\"cn-settings-field__image-tile\" :data-testid=\"`cn-settings-field-image-${field.key}`\">\n\t\t\t\t\t<img v-if=\"stringValue\" :src=\"stringValue\" :alt=\"t('nextcloud-vue', 'Current {name}', { name: label })\">\n\t\t\t\t\t<span v-else class=\"cn-settings-field__image-initials\" aria-hidden=\"true\">{{ field.initials || '' }}</span>\n\t\t\t\t</span>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tref=\"file\"\n\t\t\t\t\tclass=\"hidden-visually\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t:accept=\"field.accept || 'image/*'\"\n\t\t\t\t\ttabindex=\"-1\"\n\t\t\t\t\t:aria-labelledby=\"`${inputId}-label`\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t@change=\"upload($event.target.files && $event.target.files[0])\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"!field.readOnly && field.uploadUrl\"\n\t\t\t\t\t:disabled=\"uploading\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t:data-testid=\"`cn-settings-field-upload-${field.key}`\"\n\t\t\t\t\t@click=\"$refs.file && $refs.file.click()\">\n\t\t\t\t\t<template v-if=\"uploading\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ field.uploadLabel || t('nextcloud-vue', 'Upload {name}', { name: label }) }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<NcSelect\n\t\t\tv-else-if=\"kind === 'select'\"\n\t\t\t:inputId=\"inputId\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"normalizedOptions\"\n\t\t\t:inputLabel=\"label\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:loading=\"optionsLoading\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:clearable=\"!field.required\"\n\t\t\tlabel=\"label\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue(optionValue($event))\" />\n\t\t<NcTextArea\n\t\t\tv-else-if=\"kind === 'textarea'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:rows=\"field.rows || 4\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'secret'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"password\"\n\t\t\tautocomplete=\"new-password\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.secretSet ? secretSetPlaceholder : (field.placeholder || '')\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'number'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"number\"\n\t\t\t:min=\"field.min\"\n\t\t\t:max=\"field.max\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event === '' ? null : Number($event))\" />\n\t\t<NcTextField\n\t\t\tv-else\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:type=\"kind === 'password' ? 'password' : 'text'\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<p v-if=\"shownError\"\n\t\t\t:id=\"`${inputId}-error`\"\n\t\t\tclass=\"cn-settings-field__error\"\n\t\t\t:data-testid=\"`cn-settings-field-error-${field.key}`\">\n\t\t\t{{ shownError }}\n\t\t</p>\n\t\t<p v-else-if=\"hint\" :id=\"`${inputId}-hint`\" class=\"cn-settings-field__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport { buildHeaders, prefixUrl } from '../../utils/headers.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\nlet fieldUid = 0\n\n/** Field types and the names CnSettingsPage's manifest uses for them. */\nconst KIND_ALIASES = { enum: 'select', string: 'text' }\n\n/**\n * CnSettingsField - one settings field: the control for its type with its\n * label, and under it an error or a hint. Shared by CnSettingsPage and\n * CnSettingsFieldsSection.\n *\n * Types: `text` (default), `textarea`, `number`, `switch`, `boolean` (a checkbox),\n * `select` (`enum`) with static `options` or options read from `optionsUrl`,\n * `password` (a masked input that shows its value back) and `secret`\n * (replace-only: the input stays empty, and with `secretSet` says a value is\n * stored; the host sends it only when something is typed), and `image` (a\n * preview tile, the initials without an image, and an upload button that\n * posts the file to `uploadUrl` at once and emits `uploaded`).\n *\n * ```vue\n * <CnSettingsField\n * :field=\"{ key: 'apiKey', label: 'API key', type: 'secret', secretSet: true }\"\n * v-model=\"form.apiKey\" />\n * ```\n */\nexport default {\n\tname: 'CnSettingsField',\n\n\tcomponents: { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField },\n\n\tprops: {\n\t\t/**\n\t\t * The field: `{ key, label, type?, options?, optionsUrl?, optionsPath?,\n\t\t * optionLabel?, optionValue?, placeholder?, rows?, min?, max?, required?,\n\t\t * readOnly?, secretSet? }`. `label` arrives translated.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tfield: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * The value: text, a number, a boolean or a select value. Any type,\n\t\t * because a Boolean in a type list would read an empty string as true.\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: null,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** A validation message, drawn under the control and tied to it. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A hint under the control (not drawn while there is an error). */\n\t\thint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['update:modelValue', 'uploaded'],\n\n\tdata() {\n\t\tfieldUid += 1\n\t\treturn {\n\t\t\tuid: fieldUid,\n\t\t\tfetchedOptions: null,\n\t\t\toptionsLoading: false,\n\t\t\tuploading: false,\n\t\t\tuploadError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The control kind. */\n\t\tkind() {\n\t\t\tconst type = String(this.field.type || 'text')\n\t\t\treturn KIND_ALIASES[type] || type\n\t\t},\n\n\t\t/** @return {string} The label. */\n\t\tlabel() {\n\t\t\treturn String(this.field.label || this.field.key || '')\n\t\t},\n\n\t\t/** @return {string} The control's id. */\n\t\tinputId() {\n\t\t\treturn `cn-settings-field-${this.uid}-${String(this.field.key).replace(/[^A-Za-z0-9_-]/g, '-')}`\n\t\t},\n\n\t\t/** @return {string} The message shown under the control: an upload failure, else `error`. */\n\t\tshownError() {\n\t\t\treturn this.uploadError || this.error\n\t\t},\n\n\t\t/** @return {string|null} The id of the error or hint the control is described by. */\n\t\tdescribedBy() {\n\t\t\tif (this.shownError) {\n\t\t\t\treturn `${this.inputId}-error`\n\t\t\t}\n\t\t\treturn this.hint ? `${this.inputId}-hint` : null\n\t\t},\n\n\t\t/** @return {string} The value as text for a text control. */\n\t\tstringValue() {\n\t\t\treturn this.modelValue === null || this.modelValue === undefined ? '' : String(this.modelValue)\n\t\t},\n\n\t\t/** @return {string} The placeholder of a secret that is stored. */\n\t\tsecretSetPlaceholder() {\n\t\t\treturn t('nextcloud-vue', 'Stored. Type a new value to replace it.')\n\t\t},\n\n\t\t/**\n\t\t * The select options as `{ label, value }`: the static `options` (strings,\n\t\t * numbers or objects), or those read from `optionsUrl`.\n\t\t *\n\t\t * @return {Array<{label: string, value: (string|number|boolean)}>}\n\t\t */\n\t\tnormalizedOptions() {\n\t\t\tconst raw = Array.isArray(this.field.options) ? this.field.options : (this.fetchedOptions || [])\n\t\t\treturn raw.map((option) => (option && typeof option === 'object'\n\t\t\t\t? { ...option, label: String(option.label ?? option.value ?? ''), value: option.value }\n\t\t\t\t: { label: String(option), value: option }))\n\t\t},\n\n\t\t/** @return {object|null} The option the value selects, for NcSelect. */\n\t\tselectedOption() {\n\t\t\tif (this.modelValue === null || this.modelValue === undefined || this.modelValue === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.normalizedOptions.find((option) => option.value === this.modelValue)\n\t\t\t\t|| { label: String(this.modelValue), value: this.modelValue }\n\t\t},\n\t},\n\n\twatch: {\n\t\t'field.optionsUrl': {\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\n\t\t\timmediate: true,\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Upload a chosen image to `uploadUrl` as multipart form data (the\n\t\t * file under `uploadField`, default `image`, plus `uploadParams`), then\n\t\t * take the new image url from the answer at `uploadValuePath` (or a\n\t\t * cache-busted `previewUrl`).\n\t\t *\n\t\t * @param {File|undefined} file The chosen file.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/settings-fields-section/specs/settings-fields-section/spec.md#requirement-an-image-field-uploads-at-once\n\t\t */\n\t\tasync upload(file) {\n\t\t\tif (!file || !this.field.uploadUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = new FormData()\n\t\t\tfor (const [name, value] of Object.entries(this.field.uploadParams || {})) {\n\t\t\t\tform.append(name, value)\n\t\t\t}\n\t\t\tform.append(this.field.uploadField || 'image', file)\n\t\t\tthis.uploading = true\n\t\t\tthis.uploadError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.field.uploadUrl), form)\n\t\t\t\tconst fromAnswer = this.field.uploadValuePath ? readPath(response?.data, this.field.uploadValuePath) : ''\n\t\t\t\tconst next = fromAnswer || (this.field.previewUrl ? `${prefixUrl(this.field.previewUrl)}${this.field.previewUrl.includes('?') ? '&' : '?'}v=${Date.now()}` : '')\n\t\t\t\t/**\n\t\t\t\t * @event uploaded An image was uploaded. Payload: its new url.\n\t\t\t\t */\n\t\t\t\tthis.$emit('uploaded', next)\n\t\t\t} catch (error) {\n\t\t\t\tthis.uploadError = t('nextcloud-vue', 'The image could not be uploaded: {reason}', { reason: serverErrorMessage(error) })\n\t\t\t} finally {\n\t\t\t\tthis.uploading = false\n\t\t\t\tif (this.$refs.file) {\n\t\t\t\t\tthis.$refs.file.value = ''\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Report a new value.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @return {void}\n\t\t */\n\t\temitValue(value) {\n\t\t\t/**\n\t\t\t * @event update:modelValue The value changed. Payload: the new value.\n\t\t\t */\n\t\t\tthis.$emit('update:modelValue', value)\n\t\t},\n\n\t\t/**\n\t\t * The storable value of what NcSelect emits.\n\t\t *\n\t\t * @param {object|string|number|null} emitted An option, or null on clear.\n\t\t * @return {string|number|boolean|null}\n\t\t */\n\t\toptionValue(emitted) {\n\t\t\tif (emitted === null || emitted === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn typeof emitted === 'object' && 'value' in emitted ? emitted.value : emitted\n\t\t},\n\n\t\t/**\n\t\t * Read a sourced select's options: a list (or the list at\n\t\t * `optionsPath`, or under `results`) mapped through `optionLabel` and\n\t\t * `optionValue` (dotted paths; default `label`/`title`/`name` and `value`/`id`).\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tconst url = this.kind === 'select' && !Array.isArray(this.field.options) ? this.field.optionsUrl : ''\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.optionsLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthis.fetchedOptions = []\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = this.field.optionsPath ? readPath(data, this.field.optionsPath) : (Array.isArray(data) ? data : data?.results)\n\t\t\t\tthis.fetchedOptions = (Array.isArray(list) ? list : []).map((item) => {\n\t\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\t\treturn { label: String(item), value: item }\n\t\t\t\t\t}\n\t\t\t\t\tconst value = this.field.optionValue ? readPath(item, this.field.optionValue) : (item.value ?? item.id)\n\t\t\t\t\tconst label = this.field.optionLabel ? readPath(item, this.field.optionLabel) : (item.label ?? item.title ?? item.name ?? value)\n\t\t\t\t\treturn { label: String(label ?? ''), value }\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.optionsLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-settings-field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-settings-field__hint,\n.cn-settings-field__error {\n\tmargin: 0;\n\tfont-size: 13px;\n\tline-height: 1.4;\n}\n\n.cn-settings-field__image {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-settings-field__image-label {\n\tfont-weight: 600;\n}\n\n.cn-settings-field__image-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px;\n}\n\n.cn-settings-field__image-tile {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 64px;\n\theight: 64px;\n\toverflow: hidden;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-settings-field__image-tile img {\n\tmax-width: 100%;\n\tmax-height: 100%;\n\tobject-fit: contain;\n}\n\n.cn-settings-field__image-initials {\n\tfont-size: 20px;\n\tfont-weight: 700;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n}\n\n.cn-settings-field__hint {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-field__error {\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createBlock","_createElementBlock","_createElementVNode","_openBlock","_toDisplayString","_createTextVNode","_createVNode"],"mappings":"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"}
1
+ {"version":3,"file":"CnSettingsField.vue3.js","sources":["../../../../src/components/CnSettingsField/CnSettingsField.vue?vue&type=template&id=7acf5300&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n\n<template>\n\t<div class=\"cn-settings-field\" :data-testid=\"`cn-settings-field-${field.key}`\">\n\t\t<NcCheckboxRadioSwitch\n\t\t\tv-if=\"kind === 'switch' || kind === 'boolean'\"\n\t\t\t:type=\"kind === 'switch' ? 'switch' : 'checkbox'\"\n\t\t\t:modelValue=\"!!modelValue\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\">\n\t\t\t{{ label }}\n\t\t</NcCheckboxRadioSwitch>\n\t\t<div v-else-if=\"kind === 'image'\"\n\t\t\tclass=\"cn-settings-field__image\"\n\t\t\trole=\"group\"\n\t\t\t:aria-labelledby=\"`${inputId}-label`\">\n\t\t\t<!-- `hideLabel` keeps the name for a screen reader only. -->\n\t\t\t<span :id=\"`${inputId}-label`\"\n\t\t\t\tclass=\"cn-settings-field__image-label\"\n\t\t\t\t:class=\"{ 'hidden-visually': field.hideLabel === true }\">{{ label }}</span>\n\t\t\t<div class=\"cn-settings-field__image-row\">\n\t\t\t\t<span class=\"cn-settings-field__image-tile\" :data-testid=\"`cn-settings-field-image-${field.key}`\">\n\t\t\t\t\t<img v-if=\"stringValue\" :src=\"stringValue\" :alt=\"t('nextcloud-vue', 'Current {name}', { name: label })\">\n\t\t\t\t\t<span v-else class=\"cn-settings-field__image-initials\" aria-hidden=\"true\">{{ field.initials || '' }}</span>\n\t\t\t\t</span>\n\t\t\t\t<input\n\t\t\t\t\t:id=\"inputId\"\n\t\t\t\t\tref=\"file\"\n\t\t\t\t\tclass=\"hidden-visually\"\n\t\t\t\t\ttype=\"file\"\n\t\t\t\t\t:accept=\"field.accept || 'image/*'\"\n\t\t\t\t\ttabindex=\"-1\"\n\t\t\t\t\t:aria-labelledby=\"`${inputId}-label`\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t@change=\"upload($event.target.files && $event.target.files[0])\">\n\t\t\t\t<NcButton\n\t\t\t\t\tv-if=\"!field.readOnly && field.uploadUrl\"\n\t\t\t\t\t:disabled=\"uploading\"\n\t\t\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t\t\t:data-testid=\"`cn-settings-field-upload-${field.key}`\"\n\t\t\t\t\t@click=\"$refs.file && $refs.file.click()\">\n\t\t\t\t\t<template v-if=\"uploading\" #icon>\n\t\t\t\t\t\t<NcLoadingIcon :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ field.uploadLabel || t('nextcloud-vue', 'Upload {name}', { name: label }) }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</div>\n\t\t<NcSelect\n\t\t\tv-else-if=\"kind === 'select'\"\n\t\t\t:inputId=\"inputId\"\n\t\t\t:modelValue=\"selectedOption\"\n\t\t\t:options=\"normalizedOptions\"\n\t\t\t:inputLabel=\"label\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:loading=\"optionsLoading\"\n\t\t\t:disabled=\"field.readOnly\"\n\t\t\t:clearable=\"!field.required\"\n\t\t\tlabel=\"label\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue(optionValue($event))\" />\n\t\t<NcTextArea\n\t\t\tv-else-if=\"kind === 'textarea'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:rows=\"field.rows || 4\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'secret'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"password\"\n\t\t\tautocomplete=\"new-password\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.secretSet ? secretSetPlaceholder : (field.placeholder || '')\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<NcTextField\n\t\t\tv-else-if=\"kind === 'number'\"\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\ttype=\"number\"\n\t\t\t:min=\"field.min\"\n\t\t\t:max=\"field.max\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event === '' ? null : Number($event))\" />\n\t\t<NcTextField\n\t\t\tv-else\n\t\t\t:id=\"inputId\"\n\t\t\t:label=\"label\"\n\t\t\t:type=\"kind === 'password' ? 'password' : 'text'\"\n\t\t\t:modelValue=\"stringValue\"\n\t\t\t:placeholder=\"field.placeholder || ''\"\n\t\t\t:readonly=\"field.readOnly\"\n\t\t\t:error=\"!!error\"\n\t\t\t:aria-describedby=\"describedBy\"\n\t\t\t@update:modelValue=\"emitValue($event)\" />\n\t\t<p v-if=\"shownError\"\n\t\t\t:id=\"`${inputId}-error`\"\n\t\t\tclass=\"cn-settings-field__error\"\n\t\t\t:data-testid=\"`cn-settings-field-error-${field.key}`\">\n\t\t\t{{ shownError }}\n\t\t</p>\n\t\t<p v-else-if=\"hint\" :id=\"`${inputId}-hint`\" class=\"cn-settings-field__hint\">\n\t\t\t{{ hint }}\n\t\t</p>\n\t</div>\n</template>\n\n<script>\nimport axios from '@nextcloud/axios'\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField } from '@nextcloud/vue'\nimport { buildHeaders, prefixUrl } from '../../utils/headers.js'\nimport { readPath } from '../../utils/readPath.js'\nimport { serverErrorMessage } from '../../utils/serverErrorMessage.js'\n\nlet fieldUid = 0\n\n/** Field types and the names CnSettingsPage's manifest uses for them. */\nconst KIND_ALIASES = { enum: 'select', string: 'text' }\n\n/**\n * CnSettingsField - one settings field: the control for its type with its\n * label, and under it an error or a hint. Shared by CnSettingsPage and\n * CnSettingsFieldsSection.\n *\n * Types: `text` (default), `textarea`, `number`, `switch`, `boolean` (a checkbox),\n * `select` (`enum`) with static `options` or options read from `optionsUrl`,\n * `password` (a masked input that shows its value back) and `secret`\n * (replace-only: the input stays empty, and with `secretSet` says a value is\n * stored; the host sends it only when something is typed), and `image` (a\n * preview tile, the initials without an image, and an upload button that\n * posts the file to `uploadUrl` at once and emits `uploaded`).\n *\n * ```vue\n * <CnSettingsField\n * :field=\"{ key: 'apiKey', label: 'API key', type: 'secret', secretSet: true }\"\n * v-model=\"form.apiKey\" />\n * ```\n */\nexport default {\n\tname: 'CnSettingsField',\n\n\tcomponents: { NcButton, NcCheckboxRadioSwitch, NcLoadingIcon, NcSelect, NcTextArea, NcTextField },\n\n\tprops: {\n\t\t/**\n\t\t * The field: `{ key, label, type?, options?, optionsUrl?, optionsPath?,\n\t\t * optionLabel?, optionValue?, placeholder?, rows?, min?, max?, required?,\n\t\t * readOnly?, secretSet? }`. `label` arrives translated.\n\t\t *\n\t\t * @type {object}\n\t\t */\n\t\tfield: {\n\t\t\ttype: Object,\n\t\t\trequired: true,\n\t\t},\n\n\t\t/**\n\t\t * The value: text, a number, a boolean or a select value. Any type,\n\t\t * because a Boolean in a type list would read an empty string as true.\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: null,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/** A validation message, drawn under the control and tied to it. */\n\t\terror: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/** A hint under the control (not drawn while there is an error). */\n\t\thint: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\t},\n\n\temits: ['update:modelValue', 'uploaded'],\n\n\tdata() {\n\t\tfieldUid += 1\n\t\treturn {\n\t\t\tuid: fieldUid,\n\t\t\tfetchedOptions: null,\n\t\t\toptionsLoading: false,\n\t\t\tuploading: false,\n\t\t\tuploadError: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/** @return {string} The control kind. */\n\t\tkind() {\n\t\t\tconst type = String(this.field.type || 'text')\n\t\t\treturn KIND_ALIASES[type] || type\n\t\t},\n\n\t\t/** @return {string} The label. */\n\t\tlabel() {\n\t\t\treturn String(this.field.label || this.field.key || '')\n\t\t},\n\n\t\t/** @return {string} The control's id. */\n\t\tinputId() {\n\t\t\treturn `cn-settings-field-${this.uid}-${String(this.field.key).replace(/[^A-Za-z0-9_-]/g, '-')}`\n\t\t},\n\n\t\t/** @return {string} The message shown under the control: an upload failure, else `error`. */\n\t\tshownError() {\n\t\t\treturn this.uploadError || this.error\n\t\t},\n\n\t\t/** @return {string|null} The id of the error or hint the control is described by. */\n\t\tdescribedBy() {\n\t\t\tif (this.shownError) {\n\t\t\t\treturn `${this.inputId}-error`\n\t\t\t}\n\t\t\treturn this.hint ? `${this.inputId}-hint` : null\n\t\t},\n\n\t\t/** @return {string} The value as text for a text control. */\n\t\tstringValue() {\n\t\t\treturn this.modelValue === null || this.modelValue === undefined ? '' : String(this.modelValue)\n\t\t},\n\n\t\t/** @return {string} The placeholder of a secret that is stored. */\n\t\tsecretSetPlaceholder() {\n\t\t\treturn t('nextcloud-vue', 'Stored. Type a new value to replace it.')\n\t\t},\n\n\t\t/**\n\t\t * The select options as `{ label, value }`: the static `options` (strings,\n\t\t * numbers or objects), or those read from `optionsUrl`.\n\t\t *\n\t\t * @return {Array<{label: string, value: (string|number|boolean)}>}\n\t\t */\n\t\tnormalizedOptions() {\n\t\t\tconst raw = Array.isArray(this.field.options) ? this.field.options : (this.fetchedOptions || [])\n\t\t\treturn raw.map((option) => (option && typeof option === 'object'\n\t\t\t\t? { ...option, label: String(option.label ?? option.value ?? ''), value: option.value }\n\t\t\t\t: { label: String(option), value: option }))\n\t\t},\n\n\t\t/** @return {object|null} The option the value selects, for NcSelect. */\n\t\tselectedOption() {\n\t\t\tif (this.modelValue === null || this.modelValue === undefined || this.modelValue === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn this.normalizedOptions.find((option) => option.value === this.modelValue)\n\t\t\t\t|| { label: String(this.modelValue), value: this.modelValue }\n\t\t},\n\t},\n\n\twatch: {\n\t\t'field.optionsUrl': {\n\t\t\thandler() {\n\t\t\t\tthis.loadOptions()\n\t\t\t},\n\n\t\t\timmediate: true,\n\t\t},\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Upload a chosen image to `uploadUrl` as multipart form data (the\n\t\t * file under `uploadField`, default `image`, plus `uploadParams`), then\n\t\t * take the new image url from the answer at `uploadValuePath` (or a\n\t\t * cache-busted `previewUrl`).\n\t\t *\n\t\t * @param {File|undefined} file The chosen file.\n\t\t * @return {Promise<void>}\n\t\t * @spec openspec/changes/settings-fields-section/specs/settings-fields-section/spec.md#requirement-an-image-field-uploads-at-once\n\t\t */\n\t\tasync upload(file) {\n\t\t\tif (!file || !this.field.uploadUrl) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst form = new FormData()\n\t\t\tfor (const [name, value] of Object.entries(this.field.uploadParams || {})) {\n\t\t\t\tform.append(name, value)\n\t\t\t}\n\t\t\tform.append(this.field.uploadField || 'image', file)\n\t\t\tthis.uploading = true\n\t\t\tthis.uploadError = ''\n\t\t\ttry {\n\t\t\t\tconst response = await axios.post(prefixUrl(this.field.uploadUrl), form)\n\t\t\t\tconst fromAnswer = this.field.uploadValuePath ? readPath(response?.data, this.field.uploadValuePath) : ''\n\t\t\t\tconst next = fromAnswer || (this.field.previewUrl ? `${prefixUrl(this.field.previewUrl)}${this.field.previewUrl.includes('?') ? '&' : '?'}v=${Date.now()}` : '')\n\t\t\t\t/**\n\t\t\t\t * @event uploaded An image was uploaded. Payload: its new url.\n\t\t\t\t */\n\t\t\t\tthis.$emit('uploaded', next)\n\t\t\t} catch (error) {\n\t\t\t\tthis.uploadError = t('nextcloud-vue', 'The image could not be uploaded: {reason}', { reason: serverErrorMessage(error) })\n\t\t\t} finally {\n\t\t\t\tthis.uploading = false\n\t\t\t\tif (this.$refs.file) {\n\t\t\t\t\tthis.$refs.file.value = ''\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Report a new value.\n\t\t *\n\t\t * @param {unknown} value The value.\n\t\t * @return {void}\n\t\t */\n\t\temitValue(value) {\n\t\t\t/**\n\t\t\t * @event update:modelValue The value changed. Payload: the new value.\n\t\t\t */\n\t\t\tthis.$emit('update:modelValue', value)\n\t\t},\n\n\t\t/**\n\t\t * The storable value of what NcSelect emits.\n\t\t *\n\t\t * @param {object|string|number|null} emitted An option, or null on clear.\n\t\t * @return {string|number|boolean|null}\n\t\t */\n\t\toptionValue(emitted) {\n\t\t\tif (emitted === null || emitted === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn typeof emitted === 'object' && 'value' in emitted ? emitted.value : emitted\n\t\t},\n\n\t\t/**\n\t\t * Read a sourced select's options: a list (or the list at\n\t\t * `optionsPath`, or under `results`) mapped through `optionLabel` and\n\t\t * `optionValue` (dotted paths; default `label`/`title`/`name` and `value`/`id`).\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync loadOptions() {\n\t\t\tconst url = this.kind === 'select' && !Array.isArray(this.field.options) ? this.field.optionsUrl : ''\n\t\t\tif (!url) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.optionsLoading = true\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(prefixUrl(url), { headers: buildHeaders() })\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthis.fetchedOptions = []\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst data = await response.json()\n\t\t\t\tconst list = this.field.optionsPath ? readPath(data, this.field.optionsPath) : (Array.isArray(data) ? data : data?.results)\n\t\t\t\tthis.fetchedOptions = (Array.isArray(list) ? list : []).map((item) => {\n\t\t\t\t\tif (!item || typeof item !== 'object') {\n\t\t\t\t\t\treturn { label: String(item), value: item }\n\t\t\t\t\t}\n\t\t\t\t\tconst value = this.field.optionValue ? readPath(item, this.field.optionValue) : (item.value ?? item.id)\n\t\t\t\t\tconst label = this.field.optionLabel ? readPath(item, this.field.optionLabel) : (item.label ?? item.title ?? item.name ?? value)\n\t\t\t\t\treturn { label: String(label ?? ''), value }\n\t\t\t\t})\n\t\t\t} catch {\n\t\t\t\tthis.fetchedOptions = []\n\t\t\t} finally {\n\t\t\t\tthis.optionsLoading = false\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-settings-field {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n}\n\n.cn-settings-field__hint,\n.cn-settings-field__error {\n\tmargin: 0;\n\tfont-size: 13px;\n\tline-height: 1.4;\n}\n\n.cn-settings-field__image {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n}\n\n.cn-settings-field__image-label {\n\tfont-weight: 600;\n}\n\n.cn-settings-field__image-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 12px;\n}\n\n.cn-settings-field__image-tile {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 64px;\n\theight: 64px;\n\toverflow: hidden;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-primary-element-light);\n}\n\n.cn-settings-field__image-tile img {\n\tmax-width: 100%;\n\tmax-height: 100%;\n\tobject-fit: contain;\n}\n\n.cn-settings-field__image-initials {\n\tfont-size: 20px;\n\tfont-weight: 700;\n\tcolor: var(--color-primary-element-light-text, var(--color-primary-element));\n}\n\n.cn-settings-field__hint {\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-settings-field__error {\n\tcolor: var(--color-error-text, var(--color-error));\n}\n</style>\n"],"names":["_createBlock","_normalizeClass","_createElementBlock","_openBlock","_toDisplayString","_createElementVNode","_createTextVNode","_createVNode"],"mappings":";;;;;AA6BQ,MAAA,UAAA,GAAA,EAAA,KAAC,EAAA,8BAAA,GAAA;;;;;AAGS,EAAA,KAAK,EAAC,mCAAG;AAAA,EAAA,aAAA,EAAA,MAAA;;;;;;;;;;;;;;;AArBrB,IAAA,KAAK,EAAC,mBAAgB;IAAA,aAAA,EAAA,CAAA,kBAAA,EAAA,MAAA,CAAA,KAAA,CAAA,GAAA,CAAA,CAAA;;AAEnB,IAAA,CAAA,QAAA,CAAA,IAAI,iBAAiB,QAAI,CAAA,IAAA,KAAA,SAAA;sBAD/BA,WAQuB,CAAA,gCAAA,EAAA;;AANtB,UAAA,IAAI,EAAE,QAAG,CAAA,IAAA,KAAA,QAAA,GAAA,QAAA,GAAA,UAAA;AACT,UAAA,UAAU,IAAI,MAAO,CAAA,UAAA;UACrB,QAAQ,EAAE,MAAK,CAAA,KAAA,CAAC,QAAQ;AACxB,UAAA,kBAAgB,EAAE,QAAW,CAAA,WAAA;UAC7B,qBAAU,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAA,QAAA,CAAA,SAAA,CAAA,MAAA,CAAA,CAAA,CAAA;;2BACX,MAAW;4CAAR,QAAK,CAAA,KAAA,CAAA,EAAA,CAAA,YAAA;;;;SAEO,QAAI,CAAA,IAAA,KAAA,OAAA;0CAmCd,CAAA,KAAA,EAAA;;AAlCJ,YAAA,KAAI,EAAC,0BAA0B;AAC/B,YAAA,IAAG,EAAC,OAAO;AACX,YAAA,iBAAe,KAAK,QAAO,CAAA,OAAA,CAAA,MAAA,CAAA;;8BAIrB,CAAA,MAAA,EAAA;AAFA,cAAA,EAAE,KAAK,QAAO,CAAA,OAAA,CAAA,MAAA,CAAA;mBACf,EAAAC,cAAA,CAAA,CAAA,gCAAiC,EAChC,EAAA,iBAAA,EAAA,MAAA,CAAA,KAAA,CAAA,SAAA,KAAA,IAAA,EAAA,CAAA,CAAA;+BAAA,QAAA,CAAA,KAAA,CAAA,EAAA,EAAA,2BAAA,UAAA,CAAA;+BA2BD,iBAAA,EAAA;gCAtBE,CAAA,MAAA,EAAA;AAHD,gBAAA,KAAK,EAAC,+BAAC;gBAAA,aAAA,EAAA,CAAA,wBAAA,EAAA,MAAA,CAAA,KAAA,CAAA,GAAA,CAAA,CAAA;;iBACH,QAAA,CAAA,WAAA;kCAATC,kBAAS,CAAA,KAAA,EAAA;;AAAA,sBAAA,GAAA,EAAA,QAAA,CAAA,WAAA;sBAAA,GAAA,EAAA,QAAA,CAAA,CAAA,CAAA,eAAA,EAAA,gBAAA,EAAA,EAAA,IAAA,EAAA,QAAA,CAAA,KAAA,EAAA,CAAA;;AACT,qBAAAC,SAAA,EAAA,EAAAD,kBAAA,CAAsB,MAAtB,EAAA,UAAsB,EAAAE,eAAA,CAAA,MAAA,CAAA,KAAA,CAAA,QAAA,IAAA,EAAA,CAAA,EAAA,CAAA,YAAA,CAAA;;cAEtBC,kBASqD,CAAA,OAAA,EAAA;AARpD,gBAAA,EAAE,EAAE,QAAO,CAAA,OAAA;AACZ,gBAAA,GAAG,EAAC,MAAM;AACV,gBAAA,KAAK,EAAC,iBAAiB;AACvB,gBAAA,IAAI,EAAC,MAAM;gBACV,MAAM,EAAA,MAAA,CAAA,KAAA,CAAA,MAAA,IAAA,SAAA;AACP,gBAAA,QAAQ,EAAC,IAAI;AACZ,gBAAA,iBAAe,KAAI,QAAA,CAAA,OAAA,CAAA,MAAA,CAAA;AACnB,gBAAA,kBAAgB,EAAE,QAAW,CAAA,WAAA;AAC7B,gBAAA,QAAM,EAAE,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAA,QAAA,CAAA,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;AAE9C,cAAA,CAAA,CAAA,MAAA,CAAA,KAAK,CAAC,QAAQ,IAAI,MAAA,CAAA,KAAK,CAAC,SAAC;gCADhCL,WAUU,CAAA,mBAAA,EAAA;;AART,oBAAA,QAAQ,EAAE,KAAS,CAAA,SAAA;AACnB,oBAAA,kBAAS,EAAA,QAAA,CAAA,WAAA;oBACT,aAAW,EAAA,CAAA,yBAAA,EAA+B,MAAI,CAAA,KAAA,CAAC,GAAG,CAAA,CAAA;oBAClD,OAAK,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAE,UAAC,CAAA,IAAA,IAAA,IAAA,CAAA,KAAA,CAAA,IAAA,CAAA,KAAA,EAAA,CAAA,CAAA;;qCAGJ,MACL;AADK,sBAAAM,eAAA,CAAA,GACL,mBAAG,MAAK,CAAA,KAAA,CAAC,WAAW,IAAI,QAAA,CAAA,CAAC,2CAAC,QAAA,CAAA,KAAA,EAAA,CAAA,CAAA,EAAA,CAAA,YAAA;;;;qBAHvB,KAAA,CAAA,SAAA;;gCAAA,MAAA;sCACF,MAAC;4BAADC,WAAC,CAAA,wBAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAAA,CAAA;;;;;;;;;WAOO,QAAI,CAAA,IAAA,KAAA,QAAA;0BADfP,WAYwB,CAAA,mBAAA,EAAA;;AAVvB,cAAA,OAAO,EAAE,QAAO,CAAA,OAAA;AAChB,cAAA,UAAU,EAAE,QAAY,CAAA,cAAA;AACxB,cAAA,OAAO,EAAE,QAAiB,CAAA,iBAAA;AAC1B,cAAA,UAAU,EAAC,QAAA,CAAA,KAAA;cACX,WAAW,EAAE,MAAK,CAAA,KAAA,CAAC,WAAU,IAAA,EAAA;AAC7B,cAAA,OAAO,EAAE,KAAc,CAAA,cAAA;cACvB,QAAQ,EAAA,MAAA,CAAA,KAAA,CAAA,QAAA;cACR,SAAS,EAAA,CAAG,MAAK,CAAA,KAAA,CAAE,QAAO;AAC3B,cAAA,KAAK,EAAC,OAAM;AACX,cAAA,kBAAY,EAAA,QAAA,CAAA,WAAA;AACZ,cAAA,qBAAiB,EAAE,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAA,QAAA,CAAA,SAAI,CAAA,QAAA,CAAA,WAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA;;aAEb,QAAI,CAAA,IAAA,KAAA,UAAA;4BADfA,WAUc,CAAA,qBAAA,EAAA;;AARb,gBAAA,EAAE,EAAE,QAAO,CAAA,OAAA;AACX,gBAAA,KAAK,EAAE,QAAK,CAAA,KAAA;AACZ,gBAAA,UAAU,EAAE,QAAW,CAAA,WAAA;gBACvB,IAAI,EAAE,MAAK,CAAA,KAAA,CAAC,IAAI,IAAA,CAAA;gBAChB,WAAS,EAAA,MAAA,CAAA,KAAA,CAAA,WAAA,IAAA,EAAA;gBACT,QAAQ,EAAE,MAAK,CAAA,KAAA,CAAC,QAAQ;AACxB,gBAAA,KAAK,IAAI,MAAE,CAAA,KAAA;AACX,gBAAA,kBAAY,EAAA,QAAA,CAAA,WAAA;gBACZ,qBAAa,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAA,QAAA,CAAA,SAAA,CAAA,MAAA,CAAA,CAAA,CAAA;;eAEH,QAAI,CAAA,IAAA,KAAA,QAAA;yCAUH,CAAA,sBAAA,EAAA;;AATX,kBAAA,EAAE,EAAE,QAAO,CAAA,OAAA;AACX,kBAAA,KAAK,EAAE,QAAK,CAAA,KAAA;AACb,kBAAA,IAAI,EAAC,UAAU;AACf,kBAAA,YAAY,EAAC,cAAc;AAC1B,kBAAA,UAAU,EAAE,QAAW,CAAA,WAAA;kBACvB,WAAS,EAAA,YAAA,CAAA,SAAA,GAAA,QAAA,CAAA,oBAAA,IAAA,MAAA,CAAA,KAAA,CAAA,WAAA,IAAA,EAAA,CAAA;kBACT,QAAQ,EAAE,MAAK,CAAA,KAAA,CAAC,QAAQ;AACxB,kBAAA,KAAK,IAAI,MAAE,CAAA,KAAA;AACX,kBAAA,kBAAY,EAAA,QAAA,CAAA,WAAA;kBACZ,qBAAW,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAA,QAAA,CAAA,SAAA,CAAA,MAAA,CAAA,CAAA,CAAA;;iBAED,QAAI,CAAA,IAAA,KAAA,QAAA;gCADfA,WAWgD,CAAA,sBAAA,EAAA;;AAT/C,oBAAA,EAAE,EAAE,QAAO,CAAA,OAAA;AACX,oBAAA,KAAK,EAAE,QAAK,CAAA,KAAA;AACb,oBAAA,IAAI,EAAC,QAAQ;oBACZ,GAAG,EAAE,MAAK,CAAA,KAAA,CAAC,GAAG;oBACd,GAAG,EAAE,MAAK,CAAA,KAAA,CAAC,GAAG;AACd,oBAAA,UAAS,EAAA,QAAA,CAAA,WAAA;oBACT,QAAI,EAAA,MAAA,CAAA,KAAA,CAAA,QAAA;AACJ,oBAAA,KAAK,IAAI,MAAE,CAAA,KAAA;AACX,oBAAA,kBAAY,EAAA,QAAA,CAAA,WAAA;AACZ,oBAAA,qBAAiB,uCAAE,QAAS,CAAA,SAAA,CAAC,MAAM,KAAY,EAAA,GAAA,IAAA,GAAA,MAAA,CAAA,MAAA,CAAA,CAAA,CAAA,CAAA;;2CAWjC,CAAA,sBAAA,EAAA;;AARd,oBAAA,EAAE,EAAE,QAAO,CAAA,OAAA;AACX,oBAAA,KAAK,EAAE,QAAK,CAAA,KAAA;AACZ,oBAAA,IAAI,EAAE,QAAI,CAAA,IAAA,KAAA,UAAA,GAAA,UAAA,GAAA,MAAA;AACV,oBAAA,UAAU,EAAE,QAAW,CAAA,WAAA;+BACZ,EAAE,MAAI,CAAA,KAAA,CAAA,WAAA,IAAA,EAAA;oBACjB,QAAQ,EAAE,MAAK,CAAA,KAAA,CAAC,QAAM;AACtB,oBAAA,KAAK,IAAI,MAAK,CAAA,KAAA;AACd,oBAAA,kBAAgB,EAAE,QAAW,CAAA,WAAA;oBAC7B,qBAAc,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,MAAA,KAAA,QAAA,CAAA,SAAA,CAAA,MAAA,CAAA,CAAA,CAAA;;KACb,QAAA,CAAA,UAAA;sBAAHE;;AACG,UAAA,EAAC,KAAK,QAAO,CAAA,OAAA,CAAA,MAAA,CAAA;AACf,UAAA,KAAK,EAAC,0BAAG;UACR,aAAC,EAAA,CAAA,wBAAA,EAAA,MAAA,CAAA,KAAA,CAAA,GAAA,CAAA,CAAA;2BACC,QAAA,CAAA,UAAA,CAAA,EAAA,CAAA,oBAAA,UAAA,CAAA;;;;;;;;;;;;;"}
@@ -2,7 +2,7 @@ import script from './CnSetupWizard.vue2.js';
2
2
  import { render } from './CnSetupWizard.vue3.js';
3
3
 
4
4
  script.render = render;
5
- script.__scopeId = "data-v-130330d9";
5
+ script.__scopeId = "data-v-dd2d6164";
6
6
  const __sfc_main = script;
7
7
 
8
8
  export { __sfc_main as default };