@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
@@ -184,27 +184,10 @@
184
184
  <CnIcon :name="widget.icon" :size="20" />
185
185
  </template>
186
186
  <!-- A renderer that reports its own header (`header` event:
187
- `{ link, note, action, pill }`, e.g. record-list's "3 in totaal",
188
- a facts card's status pill). -->
189
- <template v-if="rendererHeader.note || rendererHeader.action || rendererHeader.pill" #actions>
190
- <CnStatusBadge
191
- v-if="rendererHeader.pill"
192
- :label="rendererHeader.pill.label"
193
- :variant="rendererHeader.pill.variant"
194
- data-testid="cn-detail-widget-header-pill" />
195
- <span
196
- v-if="rendererHeader.note"
197
- class="cn-detail-page__catalog-note"
198
- data-testid="cn-detail-widget-header-note">{{ rendererHeader.note }}</span>
199
- <button
200
- v-if="rendererHeader.action"
201
- type="button"
202
- class="cn-detail-page__catalog-action"
203
- data-testid="cn-detail-widget-header-action"
204
- @click="rendererHeader.action.run()">
205
- <CnIcon v-if="rendererHeader.action.icon" :name="rendererHeader.action.icon" :size="16" />
206
- {{ rendererHeader.action.label }}
207
- </button>
187
+ `{ link, note, action, actions, pill }`, e.g. record-list's "3 in
188
+ totaal", a facts card's status pill). -->
189
+ <template v-if="hasRendererHeaderItems" #actions>
190
+ <CnDetailWidgetHeaderItems :header="rendererHeader" />
208
191
  </template>
209
192
  <template v-if="catalogAddEnabled" #action-items>
210
193
  <NcActionButton @click="invokeCatalogAdd">
@@ -264,10 +247,16 @@
264
247
  <template v-if="widget.icon" #title-icon>
265
248
  <CnIcon :name="widget.icon" :size="20" />
266
249
  </template>
250
+ <!-- The app widget reports its title row the way the built-in
251
+ cards do (`header` event). -->
252
+ <template v-if="hasRendererHeaderItems" #actions>
253
+ <CnDetailWidgetHeaderItems :header="rendererHeader" />
254
+ </template>
267
255
  <component
268
256
  :is="renderer"
269
257
  ref="renderer"
270
258
  v-bind="rendererProps"
259
+ @header="onRendererHeader"
271
260
  @selectObject="onSelectObject" />
272
261
  </CnWidgetWrapper>
273
262
 
@@ -304,7 +293,7 @@ import CnObjectDataWidget from '../CnObjectDataWidget/CnObjectDataWidget.vue'
304
293
  import CnObjectFilesWidget from '../CnObjectFilesWidget/CnObjectFilesWidget.vue'
305
294
  import CnObjectGeoWidget from '../CnObjectGeoWidget/CnObjectGeoWidget.vue'
306
295
  import CnRelatedObjectsWidget from '../CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue'
307
- import CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'
296
+ import CnDetailWidgetHeaderItems from './CnDetailWidgetHeaderItems.vue'
308
297
  import { useIntegrationRegistry } from '../../composables/useIntegrationRegistry.js'
309
298
  import { normalizeLook } from '../../composables/useLook.js'
310
299
  import { isAppInstalled } from '../../utils/appInstalled.js'
@@ -378,12 +367,12 @@ export default {
378
367
  name: 'CnDetailWidgetHost',
379
368
 
380
369
  components: {
370
+ CnDetailWidgetHeaderItems,
381
371
  CnIcon,
382
372
  CnLeafMountHost,
383
373
  CnObjectDataWidget,
384
374
  CnObjectGeoWidget,
385
375
  CnRelatedObjectsWidget,
386
- CnStatusBadge,
387
376
  CnWidgetWrapper,
388
377
  NcActionButton,
389
378
  CnEmptyContent,
@@ -639,7 +628,7 @@ export default {
639
628
  * `header` event (screens-relation-pages): a link and a note,
640
629
  * with the list's total already filled in.
641
630
  */
642
- rendererHeader: { link: null, note: '', action: null, pill: null },
631
+ rendererHeader: { link: null, note: '', actions: [], pill: null },
643
632
  }
644
633
  },
645
634
 
@@ -672,6 +661,12 @@ export default {
672
661
  return this.isBare ? undefined : widgetTitleOf(this.widget)
673
662
  },
674
663
 
664
+ /** @return {boolean} Whether the reported header has anything for the title row. */
665
+ hasRendererHeaderItems() {
666
+ const h = this.rendererHeader
667
+ return !!(h.note || h.pill || (h.actions && h.actions.length > 0))
668
+ },
669
+
675
670
  /**
676
671
  * The card header's link: the one the renderer reports, else, with
677
672
  * `showHeaderLink`, the one the manifest declares for the widget.
@@ -1072,11 +1067,20 @@ export default {
1072
1067
  * override a value the widget computes there; the whole content still
1073
1068
  * arrives as `content`.
1074
1069
  *
1070
+ * `content.chartKind` is read as the chart's `type`, as the dashboard
1071
+ * dispatcher reads it, so a chart placed on a detail page draws.
1072
+ *
1075
1073
  * @return {object} The declared content keys.
1076
1074
  * @spec openspec/changes/declared-props-detail-index-sidebar/specs/widget-hosts/spec.md#requirement-a-widget-host-passes-only-the-keys-a-widget-declares
1075
+ * @spec openspec/changes/detail-chart-kind/specs/widget-hosts/spec.md#requirement-a-detail-chart-reads-chartkind-as-its-type
1077
1076
  */
1078
1077
  declaredContent() {
1079
- return pickDeclaredProps(this.renderer, this.content, this.widget?.type || '')
1078
+ let bindings = this.content
1079
+ if (bindings && typeof bindings === 'object' && bindings.chartKind !== undefined && bindings.type === undefined) {
1080
+ const { chartKind, ...rest } = bindings
1081
+ bindings = { ...rest, type: chartKind }
1082
+ }
1083
+ return pickDeclaredProps(this.renderer, bindings, this.widget?.type || '')
1080
1084
  },
1081
1085
 
1082
1086
  /**
@@ -1217,17 +1221,20 @@ export default {
1217
1221
 
1218
1222
  methods: {
1219
1223
  /**
1220
- * Take the header a content-only renderer reports.
1224
+ * Take the header a content-only renderer, or an app widget in the
1225
+ * titled card, reports.
1221
1226
  *
1222
- * @param {{link?: object|null, note?: string, action?: {label: string, icon?: string, run: () => unknown}|null}} header The header parts.
1227
+ * @param {{link?: object|null, note?: string, action?: {label: string, icon?: string, run: () => unknown}|null, actions?: Array<{label: string, icon?: string, run: () => unknown}>}} header The header parts.
1223
1228
  * @spec openspec/changes/screens-relation-pages/specs/relation-pages/spec.md#requirement-a-record-list-shows-the-objects-that-point-at-this-record
1224
1229
  */
1225
1230
  onRendererHeader(header) {
1226
1231
  const link = header && header.link && typeof header.link === 'object' ? header.link : null
1227
1232
  const note = header && typeof header.note === 'string' ? header.note : ''
1228
- const action = header && header.action && typeof header.action.run === 'function' && header.action.label ? header.action : null
1233
+ const usable = (action) => action && typeof action.run === 'function' && action.label
1234
+ // `action` (one) and `actions` (several) both count, `action` first.
1235
+ const actions = [header && header.action, ...((header && Array.isArray(header.actions)) ? header.actions : [])].filter(usable)
1229
1236
  const pill = header && header.pill && typeof header.pill.label === 'string' && header.pill.label !== '' ? header.pill : null
1230
- this.rendererHeader = { link, note, action, pill }
1237
+ this.rendererHeader = { link, note, actions, pill }
1231
1238
  },
1232
1239
 
1233
1240
  /**
@@ -1206,11 +1206,15 @@ export default {
1206
1206
  min-width: 0;
1207
1207
  }
1208
1208
 
1209
+ /* `padding: 0`: Nextcloud's core stylesheet pads every `dl` 12px at the top
1210
+ and bottom, which put a side card's facts 24px under its title, against
1211
+ the board's 12 (DqZaak "Behandeling", DqZaakDocumenten). */
1209
1212
  .cn-facts-widget__rows {
1210
1213
  display: grid;
1211
1214
  grid-template-columns: max-content 1fr;
1212
1215
  gap: 8px 16px;
1213
1216
  margin: 0;
1217
+ padding: 0;
1214
1218
  font-size: 14px;
1215
1219
  }
1216
1220
 
@@ -460,7 +460,7 @@ export default {
460
460
  * @return {object}
461
461
  */
462
462
  boardOptions() {
463
- const keys = ['layout', 'tabs', 'filter', 'statusLabels', 'next', 'issueLabels', 'subtitle', 'notice', 'noticeLink', 'summaries', 'documentationButton', 'suggestButton']
463
+ const keys = ['layout', 'tabs', 'filter', 'statusLabels', 'next', 'issueLabels', 'subtitle', 'notice', 'noticeLink', 'summaries', 'documentationButton', 'suggestButton', 'actionsMenu']
464
464
  const options = {}
465
465
  for (const key of keys) {
466
466
  if (this.board && this.board[key] !== undefined && this.board[key] !== null) {
@@ -36,7 +36,7 @@
36
36
  {{ t('nextcloud-vue', 'Suggest feature') }}
37
37
  </NcButton>
38
38
  <NcActions
39
- v-if="!tabs"
39
+ v-if="!tabs && actionsMenu"
40
40
  :menuName="t('nextcloud-vue', 'Actions')"
41
41
  :forceName="true"
42
42
  data-testid="cn-features-board-actions">
@@ -85,6 +85,7 @@
85
85
  </button>
86
86
  </div>
87
87
  <NcActions
88
+ v-if="actionsMenu"
88
89
  :menuName="t('nextcloud-vue', 'Actions')"
89
90
  :forceName="true"
90
91
  class="cn-features-board__tab-actions"
@@ -375,6 +376,8 @@ export default {
375
376
 
376
377
  /** Show the Features and Roadmap folder tabs. */
377
378
  tabs: { type: Boolean, default: true },
379
+ /** Show the Actions menu (suggest, buildiq, AI skills, support), in the header or the tab row; false draws none. */
380
+ actionsMenu: { type: Boolean, default: true },
378
381
  /** `chips`: pill buttons with a count. `segmented`: a segmented control without counts. */
379
382
  filter: {
380
383
  type: String,
@@ -5,7 +5,7 @@
5
5
  <template>
6
6
  <div
7
7
  class="cn-files-browser"
8
- :class="{ 'cn-files-browser--dragging': dragging }"
8
+ :class="{ 'cn-files-browser--dragging': dragging, 'cn-files-browser--drop-panel': dropOverlay && dropDetail !== '' }"
9
9
  data-testid="cn-files-browser"
10
10
  @dragenter.prevent="onDragEnter"
11
11
  @dragover.prevent="onDragOver"
@@ -22,7 +22,10 @@
22
22
  aria-hidden="true"
23
23
  data-testid="cn-files-browser-drop-overlay">
24
24
  <span class="cn-files-browser__drop-icon"><Upload :size="28" /></span>
25
- <strong class="cn-files-browser__drop-label">{{ dropLabel }}</strong>
25
+ <strong class="cn-files-browser__drop-label">{{ cnTranslate(dropLabel) }}</strong>
26
+ <span v-if="dropDetailText"
27
+ class="cn-files-browser__drop-detail"
28
+ data-testid="cn-files-browser-drop-detail">{{ dropDetailText }}</span>
26
29
  </div>
27
30
  <p v-if="dropOverlay"
28
31
  class="hidden-visually"
@@ -1026,12 +1029,26 @@ export default {
1026
1029
  default: false,
1027
1030
  },
1028
1031
 
1029
- /** The line `dropOverlay` draws and announces. */
1032
+ /** The line `dropOverlay` draws and announces, through the host translate. */
1030
1033
  dropLabel: {
1031
1034
  type: String,
1032
1035
  default: () => t('nextcloud-vue', 'Drop to add'),
1033
1036
  },
1034
1037
 
1038
+ /**
1039
+ * A second line under `dropLabel` in the drop state, through the host
1040
+ * translate: where the files go ("{count} bestanden komen bij zaak
1041
+ * 2026-0082, als nog te beoordelen document."). `{count}` is the number
1042
+ * of files dragged when the browser can tell, and the line is left out
1043
+ * when it cannot. The overlay then also fills the panel.
1044
+ *
1045
+ * @spec openspec/changes/files-drop-panel/specs/files-browser/spec.md#requirement-the-drop-state-fills-the-panel-and-says-where-the-files-go
1046
+ */
1047
+ dropDetail: {
1048
+ type: String,
1049
+ default: '',
1050
+ },
1051
+
1035
1052
  /** Show a line under the list saying files can be dropped on it. */
1036
1053
  dropHint: {
1037
1054
  type: Boolean,
@@ -1259,6 +1276,8 @@ export default {
1259
1276
  */
1260
1277
  visibleColumnKeys: null,
1261
1278
  dragging: false,
1279
+ /** The number of files the current drag carries, null when unknown. */
1280
+ dragCount: null,
1262
1281
  /** Nested dragenter/dragleave pairs, so a child does not end the drag. */
1263
1282
  dragDepth: 0,
1264
1283
  /** What the live region says: the drop label, then what was added. */
@@ -1294,6 +1313,24 @@ export default {
1294
1313
  },
1295
1314
 
1296
1315
  computed: {
1316
+ /**
1317
+ * `dropDetail` through the host translate with `{count}` filled, '' when
1318
+ * there is none or the count it needs is unknown.
1319
+ *
1320
+ * @spec openspec/changes/files-drop-panel/specs/files-browser/spec.md#requirement-the-drop-state-fills-the-panel-and-says-where-the-files-go
1321
+ * @return {string}
1322
+ */
1323
+ dropDetailText() {
1324
+ if (!this.dropDetail) {
1325
+ return ''
1326
+ }
1327
+ const text = this.cnTranslate(this.dropDetail)
1328
+ if (!text.includes('{count}')) {
1329
+ return text
1330
+ }
1331
+ return this.dragCount === null ? '' : text.replace(/\{count\}/g, String(this.dragCount))
1332
+ },
1333
+
1297
1334
  /**
1298
1335
  * Whether this person may add to and change the open folder. Over
1299
1336
  * WebDAV the server answers each write on its own, so this is true;
@@ -2247,7 +2284,8 @@ export default {
2247
2284
  this.dragDepth++
2248
2285
  if (!this.dragging) {
2249
2286
  this.dragging = true
2250
- this.dropStatus = this.dropOverlay ? this.dropLabel : ''
2287
+ this.dragCount = this.draggedFileCount(event)
2288
+ this.dropStatus = this.dropOverlay ? [this.cnTranslate(this.dropLabel), this.dropDetailText].filter(Boolean).join(' ') : ''
2251
2289
  }
2252
2290
  },
2253
2291
 
@@ -2277,6 +2315,22 @@ export default {
2277
2315
  }
2278
2316
  },
2279
2317
 
2318
+ /**
2319
+ * How many files a drag carries, or null when the browser does not
2320
+ * say (it lists the items only once they are dropped in some browsers).
2321
+ *
2322
+ * @param {DragEvent} event The drag.
2323
+ * @return {number|null}
2324
+ */
2325
+ draggedFileCount(event) {
2326
+ const items = event?.dataTransfer?.items
2327
+ if (!items || typeof items.length !== 'number') {
2328
+ return null
2329
+ }
2330
+ const count = Array.from(items).filter((item) => item && item.kind === 'file').length
2331
+ return count > 0 ? count : null
2332
+ },
2333
+
2280
2334
  /**
2281
2335
  * Whether a drag carries files (not text or a link from the page).
2282
2336
  * A drag whose types cannot be read counts as files, as before.
@@ -2888,6 +2942,18 @@ export default {
2888
2942
  outline-offset: 4px;
2889
2943
  }
2890
2944
 
2945
+ /* With a `dropDetail` the drop state fills the panel it sits in, as the
2946
+ board draws it (DqZaakDocumentenSlepen), not only the list's own height. */
2947
+ .cn-files-browser--dragging.cn-files-browser--drop-panel {
2948
+ min-height: max(320px, 100%);
2949
+ }
2950
+
2951
+ .cn-files-browser__drop-detail {
2952
+ max-width: 520px;
2953
+ font-size: 14px;
2954
+ color: var(--color-main-text);
2955
+ }
2956
+
2891
2957
  .cn-files-browser__drop-overlay {
2892
2958
  position: absolute;
2893
2959
  inset: 0;
@@ -105,9 +105,10 @@ import { translate as t } from '@nextcloud/l10n'
105
105
  import { NcLoadingIcon } from '@nextcloud/vue'
106
106
  import { computed, inject, ref } from 'vue'
107
107
  import { useEndpointSource } from '../../composables/useEndpointSource.js'
108
+ import { dispatchAction } from '../../utils/actionsDispatcher.js'
108
109
  import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'
109
110
  import { followLinkClick, resolveHref } from '../../utils/linkNavigation.js'
110
- import { resolveFilterValue } from '../../utils/resolveFilterTokens.js'
111
+ import { resolveDeepTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js'
111
112
 
112
113
  /**
113
114
  * The OpenRegister endpoint that lists the caller's live flow runs.
@@ -205,6 +206,8 @@ export default {
205
206
  * so a library string localises through the consuming app's l10n.
206
207
  */
207
208
  cnTranslate: { default: () => (key) => key },
209
+ /** The page's action dispatcher (CnPageRenderer), for `headerAction`. */
210
+ cnDispatchAction: { default: null },
208
211
  },
209
212
 
210
213
  props: {
@@ -228,6 +231,10 @@ export default {
228
231
  * subject's finished runs render below it. Absent = today's org-wide
229
232
  * widget, unchanged.
230
233
  * - `emptyText` — override for the "nothing running" line.
234
+ * - `headerAction` — an action descriptor drawn in the card header
235
+ * (`{ label, icon?, ...action }`, "Flow uitvoeren"), reported through
236
+ * the `header` event and dispatched with the page's dispatcher; its
237
+ * tokens resolve against the record. The runs are read again after it.
231
238
  *
232
239
  * @type {{limit?: number, pollSeconds?: number, rowRoute?: string, runRoute?: string, subject?: string, emptyText?: string, title?: string}}
233
240
  */
@@ -257,6 +264,8 @@ export default {
257
264
  },
258
265
  },
259
266
 
267
+ emits: ['header'],
268
+
260
269
  setup(props) {
261
270
  // The shared endpoint engine owns request dedup, the short-TTL cache
262
271
  // and the cn:page:refresh / cn:widget:refresh subscriptions — the same
@@ -352,6 +361,7 @@ export default {
352
361
  refetchCompleted,
353
362
  resolvedSubject,
354
363
  injectedTranslate,
364
+ tokenCtx,
355
365
  }
356
366
  },
357
367
 
@@ -521,7 +531,17 @@ export default {
521
531
  },
522
532
  },
523
533
 
534
+ watch: {
535
+ 'content.headerAction': {
536
+ deep: true,
537
+ handler() {
538
+ this.emitHeader()
539
+ },
540
+ },
541
+ },
542
+
524
543
  mounted() {
544
+ this.emitHeader()
525
545
  this.startPolling()
526
546
  document.addEventListener('visibilitychange', this.onVisibilityChange)
527
547
  },
@@ -531,6 +551,47 @@ export default {
531
551
  },
532
552
 
533
553
  methods: {
554
+ /**
555
+ * Tell the card around the runs what its header shows: the header
556
+ * action, if any.
557
+ *
558
+ * @return {void}
559
+ */
560
+ emitHeader() {
561
+ const action = this.content && this.content.headerAction
562
+ const usable = action && typeof action === 'object' && typeof action.label === 'string' && action.label !== ''
563
+ /**
564
+ * @event header The card header's parts: `{ link, note, action, pill }`, `action` being `{ label, icon, run }` or null.
565
+ */
566
+ this.$emit('header', {
567
+ link: null,
568
+ note: '',
569
+ action: usable ? { label: this.tr(action.label), icon: action.icon || '', run: () => this.runHeaderAction() } : null,
570
+ pill: null,
571
+ })
572
+ },
573
+
574
+ /**
575
+ * Run the header action with the record's tokens resolved, then read the
576
+ * runs again so a started run shows.
577
+ *
578
+ * @return {Promise<void>}
579
+ */
580
+ async runHeaderAction() {
581
+ const { label, icon, ...action } = resolveDeepTokens(this.content.headerAction, this.tokenCtx())
582
+ try {
583
+ const outcome = await (typeof this.cnDispatchAction === 'function'
584
+ ? this.cnDispatchAction(action)
585
+ : dispatchAction(action, { router: this.$router || null }))
586
+ if (outcome === false) {
587
+ return
588
+ }
589
+ } catch {
590
+ return
591
+ }
592
+ this.refetchAll()
593
+ },
594
+
534
595
  /**
535
596
  * Start (or restart) the refetch interval, unless polling is disabled.
536
597
  *
@@ -36,7 +36,7 @@
36
36
  <NcButton v-if="showRun"
37
37
  :disabled="store.running || !store.flow.id"
38
38
  data-testid="flow-board-run"
39
- @click="$emit('run')">
39
+ @click="onRun">
40
40
  {{ t('nextcloud-vue', 'Run') }}
41
41
  </NcButton>
42
42
  <NcButton v-if="testSubjectReady"
@@ -109,7 +109,7 @@
109
109
  :key="group.app"
110
110
  class="cn-flow-board__palette-group">
111
111
  <h4 class="cn-flow-board__palette-app">
112
- {{ group.app }}
112
+ {{ group.name }}
113
113
  </h4>
114
114
  <ul class="cn-flow-board__palette-list">
115
115
  <li v-for="entry in group.entries" :key="entry.id">
@@ -135,7 +135,7 @@
135
135
  :toolbarActions="false"
136
136
  :addStep="!showPalette"
137
137
  @save="$emit('save')"
138
- @run="$emit('run')" />
138
+ @run="onRun" />
139
139
  <div v-if="store.inRunView"
140
140
  class="cn-flow-board__legend"
141
141
  data-testid="flow-board-legend">
@@ -183,6 +183,15 @@
183
183
  <h3 class="cn-flow-board__card-title" data-testid="flow-board-step-name">
184
184
  {{ stepName }}
185
185
  </h3>
186
+ <dl v-if="stepSettings.length > 0" class="cn-flow-board__settings">
187
+ <div v-for="setting in stepSettings"
188
+ :key="setting.key"
189
+ class="cn-flow-board__setting"
190
+ data-testid="flow-board-step-setting">
191
+ <dt>{{ setting.label }}</dt>
192
+ <dd>{{ setting.value }}</dd>
193
+ </div>
194
+ </dl>
186
195
  <div class="cn-flow-board__step-actions">
187
196
  <NcButton data-testid="flow-board-edit-step" @click="store.editingNodeId = store.selectedNodeId">
188
197
  {{ t('nextcloud-vue', 'Edit step') }}
@@ -212,7 +221,23 @@
212
221
  </NcButton>
213
222
  </div>
214
223
  </template>
215
- <CnFlowSidebar v-else embedded />
224
+ <template v-else-if="showRuns">
225
+ <NcButton variant="tertiary"
226
+ class="cn-flow-board__runs-back"
227
+ data-testid="flow-board-hide-runs"
228
+ @click="showRuns = false">
229
+ {{ t('nextcloud-vue', 'Back to the step settings') }}
230
+ </NcButton>
231
+ <CnFlowSidebar embedded />
232
+ </template>
233
+ <div v-else class="cn-flow-board__inspector-empty" data-testid="flow-board-inspector-empty">
234
+ <p>{{ t('nextcloud-vue', 'Select a step on the canvas to see its settings.') }}</p>
235
+ <NcButton variant="secondary"
236
+ data-testid="flow-board-show-runs"
237
+ @click="showRuns = true">
238
+ {{ t('nextcloud-vue', 'Show runs') }}
239
+ </NcButton>
240
+ </div>
216
241
  </aside>
217
242
  </div>
218
243
  </div>
@@ -232,6 +257,7 @@ import CnResourceSelect from '../CnResourceSelect/CnResourceSelect.vue'
232
257
  import { FLOW_RUN_ACTIVE_STATUSES, useFlowStore } from '../../composables/useFlowStore.js'
233
258
  import { formatRelativeDate } from '../../utils/boardDate.js'
234
259
  import { flowOutcomeLevels, flowRunDurationMs, flowRunLogLines, flowRunName, formatFlowDuration } from '../../utils/flowRunLog.js'
260
+ import { appDisplayNames } from '../../utils/nextcloudApps.js'
235
261
  import { CnStatusBadge } from '../CnStatusBadge/index.js'
236
262
 
237
263
  /**
@@ -278,7 +304,7 @@ export default {
278
304
  },
279
305
 
280
306
  data() {
281
- return { runTab: 'step', testOpen: false, testRecord: null }
307
+ return { runTab: 'step', testOpen: false, testRecord: null, appNames: {}, showRuns: false }
282
308
  },
283
309
 
284
310
  computed: {
@@ -414,17 +440,25 @@ export default {
414
440
  return { tone: 'success', text: this.t('nextcloud-vue', 'The flow is valid.') }
415
441
  },
416
442
 
417
- /** @return {Array<object>} The palette grouped by owning app. */
443
+ /**
444
+ * The palette grouped by owning app, each group named by the app's
445
+ * display name (its id when Nextcloud names none), the app that owns
446
+ * this flow first.
447
+ *
448
+ * @return {Array<{app: string, name: string, entries: Array<object>}>} The groups.
449
+ */
418
450
  paletteGroups() {
419
451
  const groups = {}
420
452
  ;(this.store.nodeCatalog || []).forEach((entry) => {
421
453
  const app = String(entry?.app || String(entry?.id || '').split('.')[0] || '')
422
454
  if (!groups[app]) {
423
- groups[app] = { app, entries: [] }
455
+ groups[app] = { app, name: this.appNames[app] || app, entries: [] }
424
456
  }
425
457
  groups[app].entries.push(entry)
426
458
  })
427
- return Object.values(groups)
459
+ const list = Object.values(groups)
460
+ const host = list.findIndex((group) => group.app === this.app)
461
+ return host > 0 ? [list[host], ...list.slice(0, host), ...list.slice(host + 1)] : list
428
462
  },
429
463
 
430
464
  /** @return {object|null} The run on screen. */
@@ -477,6 +511,37 @@ export default {
477
511
  return entry ? (entry.displayName || entry.id) : String(node?.type || '')
478
512
  },
479
513
 
514
+ /**
515
+ * The selected step's settings as its owner declares them in the
516
+ * catalogue's `configForm`: label and value, a select's option label,
517
+ * Yes or No for a switch. Unset settings are left out.
518
+ *
519
+ * @return {Array<{key: string, label: string, value: string}>} The settings.
520
+ */
521
+ stepSettings() {
522
+ const node = this.store.selectedNode
523
+ const entry = node ? this.store.catalogEntry(node.type) : null
524
+ const config = (node && node.config) || {}
525
+ const form = (entry && Array.isArray(entry.configForm)) ? entry.configForm : []
526
+ return form
527
+ .filter((field) => field && field.key && config[field.key] !== undefined && config[field.key] !== null && config[field.key] !== '')
528
+ .map((field) => {
529
+ const raw = config[field.key]
530
+ const option = Array.isArray(field.options) ? field.options.find((o) => o && o.value === raw) : null
531
+ let value
532
+ if (option) {
533
+ value = String(option.label ?? option.value)
534
+ } else if (typeof raw === 'boolean') {
535
+ value = raw ? this.t('nextcloud-vue', 'Yes') : this.t('nextcloud-vue', 'No')
536
+ } else if (typeof raw === 'object') {
537
+ value = JSON.stringify(raw)
538
+ } else {
539
+ value = String(raw)
540
+ }
541
+ return { key: field.key, label: field.label || field.key, value }
542
+ })
543
+ },
544
+
480
545
  /** @return {string} The selected step's name. */
481
546
  stepName() {
482
547
  const node = this.store.selectedNode
@@ -507,7 +572,36 @@ export default {
507
572
  },
508
573
  },
509
574
 
575
+ watch: {
576
+ // A selected step takes the panel back from the run history.
577
+ 'store.selectedNodeId': function(id) {
578
+ if (id) {
579
+ this.showRuns = false
580
+ }
581
+ },
582
+ },
583
+
584
+ async created() {
585
+ // The palette names its groups by app display name; only the column
586
+ // palette draws them, so only it reads the names.
587
+ if (this.palette !== 'column') {
588
+ return
589
+ }
590
+ const { default: axios } = await import('@nextcloud/axios')
591
+ this.appNames = await appDisplayNames(axios)
592
+ },
593
+
510
594
  methods: {
595
+ /**
596
+ * Run the flow, with the run history in the panel to follow it.
597
+ *
598
+ * @return {void}
599
+ */
600
+ onRun() {
601
+ this.showRuns = true
602
+ this.$emit('run')
603
+ },
604
+
511
605
  /**
512
606
  * Run the saved flow once with the picked record as its subject, then
513
607
  * close the dialog; the run shows on the canvas as any run does.
@@ -822,6 +916,36 @@ export default {
822
916
  text-align: center;
823
917
  }
824
918
 
919
+ .cn-flow-board__settings {
920
+ display: flex;
921
+ flex-direction: column;
922
+ gap: 10px;
923
+ margin: 0;
924
+ }
925
+
926
+ .cn-flow-board__setting dt {
927
+ font-size: 13px;
928
+ color: var(--color-text-maxcontrast);
929
+ }
930
+
931
+ .cn-flow-board__setting dd {
932
+ margin: 2px 0 0;
933
+ font-weight: 600;
934
+ overflow-wrap: anywhere;
935
+ }
936
+
937
+ .cn-flow-board__inspector-empty {
938
+ display: flex;
939
+ flex-direction: column;
940
+ align-items: flex-start;
941
+ gap: 12px;
942
+ color: var(--color-text-maxcontrast);
943
+ }
944
+
945
+ .cn-flow-board__inspector-empty p {
946
+ margin: 0;
947
+ }
948
+
825
949
  .cn-flow-board__step-actions,
826
950
  .cn-flow-board__step-footer {
827
951
  display: flex;