@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.
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +1 -1
- package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue.js +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js +18 -0
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue2.js.map +1 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js +3 -1
- package/dist/esm/components/CnCardGrid/CnCardGrid.vue3.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +18 -0
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js +1 -1
- package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue.js +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js +93 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnChartWidget/CnChartWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +6 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +3 -3
- package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +112 -5
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +9 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js +24 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js +49 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -0
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue.js +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js +36 -18
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue2.js.map +1 -1
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js +17 -38
- package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHost.vue3.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue3.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue.js +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js +2 -0
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js +32 -29
- package/dist/esm/components/CnFeaturesBoard/CnFeaturesBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue.js +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js +53 -2
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue2.js.map +1 -1
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js +119 -111
- package/dist/esm/components/CnFilesBrowser/CnFilesBrowser.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +62 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue.js +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js +73 -4
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue2.js.map +1 -1
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js +74 -27
- package/dist/esm/components/CnFlowsPage/CnFlowBoard.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +208 -46
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +121 -98
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue.js +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js +24 -0
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js +20 -4
- package/dist/esm/components/CnIndexPage/CnIndexPageWidgets.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +25 -6
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js +112 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js +100 -44
- package/dist/esm/components/CnIndexSidebar/CnIndexSidebar.vue3.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js +67 -4
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js +1 -1
- package/dist/esm/components/CnNcWidgetWidget/CnNcWidgetWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js +9 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue.js.map +1 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js +88 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js +39 -0
- package/dist/esm/components/CnNoticeWidget/CnNoticeWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +295 -12
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +267 -144
- package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue.js +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js +4 -0
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js +3 -1
- package/dist/esm/components/CnObjectSidebar/CnFilesTab.vue3.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +93 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +322 -246
- package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue.js +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js +122 -7
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js +189 -93
- package/dist/esm/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue.js +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue2.js.map +1 -1
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js +3 -3
- package/dist/esm/components/CnSettingsField/CnSettingsField.vue3.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue.js +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue2.js.map +1 -1
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js +16 -4
- package/dist/esm/components/CnSetupWizard/CnSetupWizard.vue3.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue.js +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue2.js.map +1 -1
- package/dist/esm/components/CnTabs/CnTabs.vue3.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue.js +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +42 -0
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +38 -19
- package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js +9 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue.js.map +1 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js +258 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue2.js.map +1 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js +69 -0
- package/dist/esm/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue3.js.map +1 -0
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue.js +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js +11 -0
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue2.js.map +1 -1
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js +4 -4
- package/dist/esm/components/CnVersionInfoCard/CnVersionInfoCard.vue3.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js +16 -14
- package/dist/esm/components/CnWidgetGrid/builtInWidgets.js.map +1 -1
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
- package/dist/esm/components/CnWidgetGrid/registerDashboardWidgets.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +24 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +24 -1
- package/dist/esm/l10n/nl.json.js.map +1 -1
- package/dist/esm/library-style.js +1 -1
- package/dist/esm/nextcloud-vue.css +1369 -748
- package/dist/esm/utils/dueText.js +18 -3
- package/dist/esm/utils/dueText.js.map +1 -1
- package/dist/esm/utils/libraryWidgetKeys.js +2 -0
- package/dist/esm/utils/libraryWidgetKeys.js.map +1 -1
- package/dist/esm/utils/nextcloudApps.js +45 -0
- package/dist/esm/utils/nextcloudApps.js.map +1 -0
- package/dist/esm/utils/scopeListLayout.js +9 -2
- package/dist/esm/utils/scopeListLayout.js.map +1 -1
- package/dist/esm/utils/sortOrder.js +11 -1
- package/dist/esm/utils/sortOrder.js.map +1 -1
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/visibleWhen.js +12 -4
- package/dist/esm/utils/visibleWhen.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +8965 -6497
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +1369 -748
- package/l10n/en.json +24 -1
- package/l10n/nl.json +24 -1
- package/package.json +1 -1
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -1
- package/src/components/CnCardGrid/CnCardGrid.md +2 -0
- package/src/components/CnCardGrid/CnCardGrid.vue +20 -0
- package/src/components/CnCellRenderer/CnCellRenderer.vue +19 -1
- package/src/components/CnChartWidget/CnChartWidget.md +2 -0
- package/src/components/CnChartWidget/CnChartWidget.vue +93 -1
- package/src/components/CnDashboardPage/CnDashboardPage.vue +9 -6
- package/src/components/CnDetailPage/CnDetailPage.md +3 -2
- package/src/components/CnDetailPage/CnDetailPage.vue +112 -5
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +60 -0
- package/src/components/CnDetailWidgetHost/CnDetailWidgetHost.vue +36 -29
- package/src/components/CnFactsWidget/CnFactsWidget.vue +4 -0
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -1
- package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +4 -1
- package/src/components/CnFilesBrowser/CnFilesBrowser.vue +70 -4
- package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +62 -1
- package/src/components/CnFlowsPage/CnFlowBoard.vue +132 -8
- package/src/components/CnIndexPage/CnIndexPage.md +8 -5
- package/src/components/CnIndexPage/CnIndexPage.vue +236 -54
- package/src/components/CnIndexPage/CnIndexPageWidgets.vue +36 -1
- package/src/components/CnIndexPage/useSelfFetchList.js +25 -6
- package/src/components/CnIndexSidebar/CnIndexSidebar.md +2 -0
- package/src/components/CnIndexSidebar/CnIndexSidebar.vue +148 -1
- package/src/components/CnNcWidgetWidget/CnNcWidgetWidget.vue +68 -5
- package/src/components/CnNoticeWidget/CnNoticeWidget.vue +153 -0
- package/src/components/CnNoticeWidget/index.js +12 -0
- package/src/components/CnObjectCard/CnObjectCard.md +1 -0
- package/src/components/CnObjectCard/CnObjectCard.vue +354 -13
- package/src/components/CnObjectSidebar/CnFilesTab.vue +6 -0
- package/src/components/CnRecordListWidget/CnRecordListWidget.vue +190 -4
- package/src/components/CnRelatedObjectsWidget/CnRelatedObjectsWidget.vue +209 -9
- package/src/components/CnSettingsField/CnSettingsField.vue +4 -1
- package/src/components/CnSetupWizard/CnSetupWizard.vue +9 -1
- package/src/components/CnTabs/CnTabs.vue +11 -0
- package/src/components/CnTabsWidget/CnTabsWidget.vue +91 -18
- package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.md +11 -0
- package/src/components/CnTeamWorkloadWidget/CnTeamWorkloadWidget.vue +382 -0
- package/src/components/CnTeamWorkloadWidget/index.js +14 -0
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +15 -4
- package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
- package/src/components/CnWidgetGrid/registerDashboardWidgets.js +12 -0
- package/src/components/index.js +2 -0
- package/src/css/dialog.css +20 -2
- package/src/css/index-page.css +14 -2
- package/src/css/look-board-detail.css +125 -8
- package/src/css/look-board-index.css +100 -4
- package/src/css/look-board.css +122 -14
- package/src/index.js +2 -1
- package/src/schemas/app-manifest-v2.schema.json +110 -8
- package/src/utils/dueText.js +18 -3
- package/src/utils/libraryWidgetKeys.js +2 -0
- package/src/utils/nextcloudApps.js +50 -0
- package/src/utils/scopeListLayout.js +9 -2
- package/src/utils/sortOrder.js +10 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- 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
|
|
188
|
-
a facts card's status pill). -->
|
|
189
|
-
<template v-if="
|
|
190
|
-
<
|
|
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
|
|
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: '',
|
|
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
|
-
|
|
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
|
|
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
|
|
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,
|
|
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.
|
|
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="
|
|
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.
|
|
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="
|
|
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
|
-
<
|
|
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
|
-
/**
|
|
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
|
-
|
|
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;
|