@conduction/nextcloud-vue 2.103.0 → 2.105.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/CnActionsBar/CnActionsBar.vue2.js +23 -0
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue2.js.map +1 -1
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js +94 -72
- package/dist/esm/components/CnActionsBar/CnActionsBar.vue3.js.map +1 -1
- 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/CnAppRoot/CnAppRoot.vue2.js +18 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
- package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +3 -3
- package/dist/esm/components/CnAppRoot/CnAppRoot.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/CnDataTable/CnDataTable.vue2.js +39 -2
- package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +14 -0
- package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
- package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +99 -3
- 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/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/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 +213 -4
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +105 -85
- package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
- package/dist/esm/components/CnIndexPage/useSelfFetchList.js +10 -4
- package/dist/esm/components/CnIndexPage/useSelfFetchList.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/CnObjectRow/CnObjectRow.vue.js +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js +57 -5
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue2.js.map +1 -1
- package/dist/esm/components/CnObjectRow/CnObjectRow.vue3.js +37 -4
- package/dist/esm/components/CnObjectRow/CnObjectRow.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/CnUserSettingsDialog/CnUserSettingsDialog.vue.js +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue2.js.map +1 -1
- package/dist/esm/components/CnUserSettingsDialog/CnUserSettingsDialog.vue3.js.map +1 -1
- 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/CnWidgetObjectTable/CnWidgetObjectTable.vue.js +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js +18 -2
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue2.js.map +1 -1
- package/dist/esm/components/CnWidgetObjectTable/CnWidgetObjectTable.vue3.js.map +1 -1
- package/dist/esm/composables/indexSources.js +7 -7
- package/dist/esm/composables/indexSources.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/l10n/en.json.js +8 -1
- package/dist/esm/l10n/en.json.js.map +1 -1
- package/dist/esm/l10n/nl.json.js +8 -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 +680 -328
- package/dist/esm/utils/libraryWidgetKeys.js +1 -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/nextcloudDirectory.js +18 -1
- package/dist/esm/utils/nextcloudDirectory.js.map +1 -1
- package/dist/esm/utils/scopeListLayout.js +9 -2
- package/dist/esm/utils/scopeListLayout.js.map +1 -1
- package/dist/esm/utils/sortOrder.js +61 -0
- package/dist/esm/utils/sortOrder.js.map +1 -0
- package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
- package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
- package/dist/esm/utils/visibleWhen.js +12 -4
- package/dist/esm/utils/visibleWhen.js.map +1 -1
- package/dist/nextcloud-vue.cjs.js +4046 -2999
- package/dist/nextcloud-vue.cjs.js.map +2 -2
- package/dist/nextcloud-vue.css +680 -328
- package/l10n/en.json +8 -1
- package/l10n/nl.json +8 -1
- package/package.json +1 -1
- package/src/components/CnActionsBar/CnActionsBar.md +1 -0
- package/src/components/CnActionsBar/CnActionsBar.vue +39 -2
- package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +1 -1
- package/src/components/CnAppRoot/CnAppRoot.md +1 -1
- package/src/components/CnAppRoot/CnAppRoot.vue +21 -4
- 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/CnDataTable/CnDataTable.md +1 -0
- package/src/components/CnDataTable/CnDataTable.vue +49 -0
- package/src/components/CnDetailPage/CnDetailPage.md +2 -0
- package/src/components/CnDetailPage/CnDetailPage.vue +99 -3
- package/src/components/CnFeaturesAndRoadmapView/CnFeaturesAndRoadmapView.vue +1 -1
- package/src/components/CnFeaturesBoard/CnFeaturesBoard.vue +4 -1
- package/src/components/CnFlowsPage/CnFlowBoard.vue +132 -8
- package/src/components/CnIndexPage/CnIndexPage.md +5 -2
- package/src/components/CnIndexPage/CnIndexPage.vue +228 -9
- package/src/components/CnIndexPage/useSelfFetchList.js +9 -3
- package/src/components/CnNoticeWidget/CnNoticeWidget.vue +153 -0
- package/src/components/CnNoticeWidget/index.js +12 -0
- package/src/components/CnObjectRow/CnObjectRow.vue +95 -1
- package/src/components/CnSettingsField/CnSettingsField.vue +4 -1
- package/src/components/CnSetupWizard/CnSetupWizard.vue +9 -1
- package/src/components/CnUserSettingsDialog/CnUserSettingsDialog.vue +7 -2
- package/src/components/CnVersionInfoCard/CnVersionInfoCard.vue +15 -4
- package/src/components/CnWidgetGrid/builtInWidgets.js +2 -0
- package/src/components/CnWidgetObjectTable/CnWidgetObjectTable.vue +18 -2
- package/src/components/index.js +1 -0
- package/src/composables/indexSources.js +7 -7
- package/src/css/dialog.css +20 -2
- package/src/css/index-page.css +19 -0
- package/src/css/look-board-detail.css +77 -4
- package/src/css/look-board-index.css +84 -2
- package/src/css/look-board.css +97 -12
- package/src/index.js +1 -0
- package/src/schemas/app-manifest-v2.schema.json +58 -3
- package/src/utils/libraryWidgetKeys.js +1 -0
- package/src/utils/nextcloudApps.js +50 -0
- package/src/utils/nextcloudDirectory.js +17 -0
- package/src/utils/scopeListLayout.js +9 -2
- package/src/utils/sortOrder.js +58 -0
- package/src/utils/validateManifestV2.compiled.js +3 -3
- package/src/utils/visibleWhen.js +12 -4
|
@@ -149,7 +149,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
149
149
|
_: 1 /* STABLE */
|
|
150
150
|
}, 8 /* PROPS */, ["href"]))
|
|
151
151
|
: createCommentVNode("v-if", true),
|
|
152
|
-
(!$props.tabs)
|
|
152
|
+
(!$props.tabs && $props.actionsMenu)
|
|
153
153
|
? (openBlock(), createBlock(_component_NcActions, {
|
|
154
154
|
key: 2,
|
|
155
155
|
menuName: $options.t('nextcloud-vue', 'Actions'),
|
|
@@ -213,37 +213,40 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
213
213
|
}, toDisplayString(tab.label), 11 /* TEXT, CLASS, PROPS */, _hoisted_8))
|
|
214
214
|
}), 128 /* KEYED_FRAGMENT */))
|
|
215
215
|
], 40 /* PROPS, NEED_HYDRATION */, _hoisted_7),
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return (openBlock(), createBlock(_component_NcActionLink, {
|
|
228
|
-
key: action.key,
|
|
229
|
-
href: action.href,
|
|
230
|
-
target: "_blank"
|
|
231
|
-
}, {
|
|
232
|
-
default: withCtx(() => [
|
|
233
|
-
createTextVNode(toDisplayString(action.label), 1 /* TEXT */)
|
|
234
|
-
]),
|
|
235
|
-
_: 2 /* DYNAMIC */
|
|
236
|
-
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["href"]))
|
|
237
|
-
}), 128 /* KEYED_FRAGMENT */)),
|
|
238
|
-
createVNode(_component_NcActionButton, { onClick: $options.onSupport }, {
|
|
216
|
+
($props.actionsMenu)
|
|
217
|
+
? (openBlock(), createBlock(_component_NcActions, {
|
|
218
|
+
key: 0,
|
|
219
|
+
menuName: $options.t('nextcloud-vue', 'Actions'),
|
|
220
|
+
forceName: true,
|
|
221
|
+
class: "cn-features-board__tab-actions",
|
|
222
|
+
"data-testid": "cn-features-board-actions"
|
|
223
|
+
}, {
|
|
224
|
+
icon: withCtx(() => [
|
|
225
|
+
createVNode(_component_DotsHorizontal, { size: 20 })
|
|
226
|
+
]),
|
|
239
227
|
default: withCtx(() => [
|
|
240
|
-
|
|
228
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList($options.menuLinks, (action) => {
|
|
229
|
+
return (openBlock(), createBlock(_component_NcActionLink, {
|
|
230
|
+
key: action.key,
|
|
231
|
+
href: action.href,
|
|
232
|
+
target: "_blank"
|
|
233
|
+
}, {
|
|
234
|
+
default: withCtx(() => [
|
|
235
|
+
createTextVNode(toDisplayString(action.label), 1 /* TEXT */)
|
|
236
|
+
]),
|
|
237
|
+
_: 2 /* DYNAMIC */
|
|
238
|
+
}, 1032 /* PROPS, DYNAMIC_SLOTS */, ["href"]))
|
|
239
|
+
}), 128 /* KEYED_FRAGMENT */)),
|
|
240
|
+
createVNode(_component_NcActionButton, { onClick: $options.onSupport }, {
|
|
241
|
+
default: withCtx(() => [
|
|
242
|
+
createTextVNode(toDisplayString($options.t('nextcloud-vue', 'Support this app')), 1 /* TEXT */)
|
|
243
|
+
]),
|
|
244
|
+
_: 1 /* STABLE */
|
|
245
|
+
}, 8 /* PROPS */, ["onClick"])
|
|
241
246
|
]),
|
|
242
247
|
_: 1 /* STABLE */
|
|
243
|
-
}, 8 /* PROPS */, ["
|
|
244
|
-
|
|
245
|
-
_: 1 /* STABLE */
|
|
246
|
-
}, 8 /* PROPS */, ["menuName"])
|
|
248
|
+
}, 8 /* PROPS */, ["menuName"]))
|
|
249
|
+
: createCommentVNode("v-if", true)
|
|
247
250
|
]))
|
|
248
251
|
: createCommentVNode("v-if", true),
|
|
249
252
|
createElementVNode("div", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CnFeaturesBoard.vue3.js","sources":["../../../../src/components/CnFeaturesBoard/CnFeaturesBoard.vue?vue&type=template&id=ed367d64&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-features-board\" :class=\"`cn-features-board--${layout}`\" data-testid=\"cn-features-board\">\n\t\t<header class=\"cn-features-board__header\">\n\t\t\t<div class=\"cn-features-board__title-row\">\n\t\t\t\t<h1 class=\"cn-features-board__title\">\n\t\t\t\t\t{{ resolvedTitle }}\n\t\t\t\t</h1>\n\t\t\t\t<div class=\"cn-features-board__header-actions\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"documentationButton && documentationUrl\"\n\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t:href=\"documentationUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\tdata-testid=\"cn-features-board-docs\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<BookOpenVariant :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Documentation') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<CnBuildiqEditButton />\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"suggestUrl && suggestButton\"\n\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t:href=\"suggestUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\tdata-testid=\"cn-features-board-suggest\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Suggest feature') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcActions\n\t\t\t\t\t\tv-if=\"!tabs\"\n\t\t\t\t\t\t:menuName=\"t('nextcloud-vue', 'Actions')\"\n\t\t\t\t\t\t:forceName=\"true\"\n\t\t\t\t\t\tdata-testid=\"cn-features-board-actions\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<DotsHorizontal :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-for=\"action in menuLinks\"\n\t\t\t\t\t\t\t:key=\"action.key\"\n\t\t\t\t\t\t\t:href=\"action.href\"\n\t\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton @click=\"onSupport\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Support this app') }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</NcActions>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<p v-if=\"resolvedSubtitle\" class=\"cn-features-board__subtitle\" data-testid=\"cn-features-board-subtitle\">\n\t\t\t\t{{ resolvedSubtitle }}\n\t\t\t</p>\n\t\t</header>\n\n\t\t<div v-if=\"tabs\" class=\"cn-features-board__tab-row\">\n\t\t\t<div\n\t\t\t\tclass=\"cn-features-board__tabs\"\n\t\t\t\trole=\"tablist\"\n\t\t\t\t:aria-label=\"resolvedTitle\"\n\t\t\t\t@keydown=\"onTabKeydown\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"tab in tabList\"\n\t\t\t\t\t:id=\"`${uid}-tab-${tab.key}`\"\n\t\t\t\t\t:key=\"tab.key\"\n\t\t\t\t\tref=\"tabButtons\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\trole=\"tab\"\n\t\t\t\t\tclass=\"cn-features-board__tab\"\n\t\t\t\t\t:class=\"{ 'cn-features-board__tab--active': activeTab === tab.key }\"\n\t\t\t\t\t:aria-selected=\"activeTab === tab.key ? 'true' : 'false'\"\n\t\t\t\t\t:aria-controls=\"`${uid}-panel`\"\n\t\t\t\t\t:tabindex=\"activeTab === tab.key ? 0 : -1\"\n\t\t\t\t\t:data-testid=\"`cn-features-board-tab-${tab.key}`\"\n\t\t\t\t\t@click=\"activeTab = tab.key\">\n\t\t\t\t\t{{ tab.label }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<NcActions\n\t\t\t\t:menuName=\"t('nextcloud-vue', 'Actions')\"\n\t\t\t\t:forceName=\"true\"\n\t\t\t\tclass=\"cn-features-board__tab-actions\"\n\t\t\t\tdata-testid=\"cn-features-board-actions\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<DotsHorizontal :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t<NcActionLink\n\t\t\t\t\tv-for=\"action in menuLinks\"\n\t\t\t\t\t:key=\"action.key\"\n\t\t\t\t\t:href=\"action.href\"\n\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t{{ action.label }}\n\t\t\t\t</NcActionLink>\n\t\t\t\t<NcActionButton @click=\"onSupport\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Support this app') }}\n\t\t\t\t</NcActionButton>\n\t\t\t</NcActions>\n\t\t</div>\n\n\t\t<div\n\t\t\t:id=\"`${uid}-panel`\"\n\t\t\tclass=\"cn-features-board__panel\"\n\t\t\t:class=\"{ 'cn-features-board__panel--tabbed': tabs }\"\n\t\t\t:role=\"tabs ? 'tabpanel' : null\"\n\t\t\t:aria-labelledby=\"tabs ? `${uid}-tab-${activeTab}` : null\">\n\t\t\t<CnRoadmapTab v-if=\"tabs && activeTab === 'roadmap'\" :repo=\"repo\" />\n\t\t\t<template v-else>\n\t\t\t\t<div\n\t\t\t\t\tclass=\"cn-features-board__filter\"\n\t\t\t\t\t:class=\"`cn-features-board__filter--${filter}`\"\n\t\t\t\t\trole=\"group\"\n\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Status')\"\n\t\t\t\t\tdata-testid=\"cn-features-board-filter\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"option in filterOptions\"\n\t\t\t\t\t\t:key=\"option.key\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"cn-features-board__filter-option\"\n\t\t\t\t\t\t:class=\"{ 'cn-features-board__filter-option--active': status === option.key }\"\n\t\t\t\t\t\t:aria-pressed=\"status === option.key ? 'true' : 'false'\"\n\t\t\t\t\t\t:data-status=\"option.key\"\n\t\t\t\t\t\t@click=\"status = option.key\">\n\t\t\t\t\t\t{{ option.label }}<span\n\t\t\t\t\t\t\tv-if=\"filter === 'chips'\"\n\t\t\t\t\t\t\tclass=\"cn-features-board__filter-count\"\n\t\t\t\t\t\t\tdata-testid=\"cn-features-board-filter-count\">{{ ' ' + option.count }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"cn-features-board__body\">\n\t\t\t\t\t<div class=\"cn-features-board__groups\" :class=\"`cn-features-board__groups--${layout}`\">\n\t\t\t\t\t\t<p v-if=\"shownGroups.length === 0\" class=\"cn-features-board__empty\" data-testid=\"cn-features-board-empty\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'No features with this status') }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<section\n\t\t\t\t\t\t\tv-for=\"group in shownGroups\"\n\t\t\t\t\t\t\t:key=\"group.key\"\n\t\t\t\t\t\t\tclass=\"cn-features-board__group\"\n\t\t\t\t\t\t\t:aria-labelledby=\"group.label ? `${uid}-group-${group.key}` : null\"\n\t\t\t\t\t\t\t:aria-label=\"group.label ? null : resolvedTitle\"\n\t\t\t\t\t\t\tdata-testid=\"cn-features-board-group\"\n\t\t\t\t\t\t\t:data-group=\"group.key\">\n\t\t\t\t\t\t\t<div v-if=\"group.label\" class=\"cn-features-board__group-head\">\n\t\t\t\t\t\t\t\t<h2 :id=\"`${uid}-group-${group.key}`\" class=\"cn-features-board__group-title\">\n\t\t\t\t\t\t\t\t\t{{ group.label }}\n\t\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tv-if=\"layout === 'cards'\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__group-caption\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-group-caption\">{{ groupCaption(group) }}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div v-if=\"layout === 'cards'\" class=\"cn-features-board__cards\">\n\t\t\t\t\t\t\t\t<article\n\t\t\t\t\t\t\t\t\tv-for=\"feature in group.shown\"\n\t\t\t\t\t\t\t\t\t:key=\"feature.slug\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__card\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-feature\">\n\t\t\t\t\t\t\t\t\t<div class=\"cn-features-board__card-head\">\n\t\t\t\t\t\t\t\t\t\t<h3 class=\"cn-features-board__card-title\">\n\t\t\t\t\t\t\t\t\t\t\t{{ feature.title }}\n\t\t\t\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\t\t\t:label=\"statusText(feature)\"\n\t\t\t\t\t\t\t\t\t\t\t:variant=\"variantOf(feature.status)\"\n\t\t\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-status\" />\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<p v-if=\"feature.summary\" class=\"cn-features-board__card-summary\">\n\t\t\t\t\t\t\t\t\t\t{{ feature.summary }}\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t<div v-if=\"readMoreHref(feature)\" class=\"cn-features-board__card-footer\">\n\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__read-more\"\n\t\t\t\t\t\t\t\t\t\t\t:href=\"readMoreHref(feature)\"\n\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Learn more about {title}', { title: feature.title })\">\n\t\t\t\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Learn more') }}\n\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</article>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<ul v-else class=\"cn-features-board__rows\">\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tv-for=\"feature in group.shown\"\n\t\t\t\t\t\t\t\t\t:key=\"feature.slug\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__row\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-feature\">\n\t\t\t\t\t\t\t\t\t<span class=\"cn-features-board__row-text\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"cn-features-board__row-title\">{{ feature.title }}</span>\n\t\t\t\t\t\t\t\t\t\t<span v-if=\"summaries && feature.summary\" class=\"cn-features-board__row-summary\">{{ feature.summary }}</span>\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\t\t:label=\"statusText(feature)\"\n\t\t\t\t\t\t\t\t\t\t:variant=\"variantOf(feature.status)\"\n\t\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-status\" />\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</section>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<aside\n\t\t\t\t\t\tv-if=\"next > 0 && repo\"\n\t\t\t\t\t\tclass=\"cn-features-board__next\"\n\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Next on the roadmap')\"\n\t\t\t\t\t\tdata-testid=\"cn-features-board-next\">\n\t\t\t\t\t\t<section class=\"cn-features-board__next-card\">\n\t\t\t\t\t\t\t<div class=\"cn-features-board__next-head\">\n\t\t\t\t\t\t\t\t<RoadVariant :size=\"20\" />\n\t\t\t\t\t\t\t\t<h2 class=\"cn-features-board__next-title\">\n\t\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Coming next') }}\n\t\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<p class=\"cn-features-board__next-lead\">\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'The most requested items from the issue tracker.') }}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t<ol v-if=\"nextIssues.length > 0\" class=\"cn-features-board__next-list\">\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tv-for=\"issue in nextIssues\"\n\t\t\t\t\t\t\t\t\t:key=\"issue.number\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__next-item\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-next-item\">\n\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__next-link\"\n\t\t\t\t\t\t\t\t\t\t:href=\"safeHref(issue.html_url)\"\n\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\">{{ issue.title }}</a>\n\t\t\t\t\t\t\t\t\t<div class=\"cn-features-board__next-meta\">\n\t\t\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\t\t\tv-if=\"issue.status\"\n\t\t\t\t\t\t\t\t\t\t\t:label=\"statusLabel(issue.status)\"\n\t\t\t\t\t\t\t\t\t\t\t:variant=\"variantOf(issue.status)\" />\n\t\t\t\t\t\t\t\t\t\t<span v-if=\"issue.opened\" class=\"cn-features-board__next-opened\">\n\t\t\t\t\t\t\t\t\t\t\t<CalendarBlankOutline :size=\"14\" />{{ t('nextcloud-vue', 'Opened {date}', { date: issue.opened }) }}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span>#{{ issue.number }}</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t</ol>\n\t\t\t\t\t\t\t<p v-else-if=\"!issuesLoading\" class=\"cn-features-board__next-lead\" data-testid=\"cn-features-board-next-empty\">\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'No roadmap items yet') }}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tv-if=\"tabs\"\n\t\t\t\t\t\t\t\thref=\"#\"\n\t\t\t\t\t\t\t\tclass=\"cn-features-board__next-more\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-whole-roadmap\"\n\t\t\t\t\t\t\t\t@click.prevent=\"activeTab = 'roadmap'\">\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'See the whole roadmap') }}<ChevronRight :size=\"16\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tv-if=\"documentationUrl\"\n\t\t\t\t\t\t\t\t:href=\"documentationUrl\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\tclass=\"cn-features-board__next-more\">\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Documentation') }}<ChevronRight :size=\"16\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</section>\n\t\t\t\t\t</aside>\n\t\t\t\t</div>\n\n\t\t\t\t<NcNoteCard v-if=\"notice\"\n\t\t\t\t\ttype=\"info\"\n\t\t\t\t\tclass=\"cn-features-board__notice\"\n\t\t\t\t\tdata-testid=\"cn-features-board-notice\">\n\t\t\t\t\t<template v-if=\"noticeParts.link\">\n\t\t\t\t\t\t{{ noticeParts.before }}<a\n\t\t\t\t\t\t\t:href=\"noticeParts.link.href\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tdata-testid=\"cn-features-board-notice-link\">{{ noticeParts.link.text }}</a>{{ noticeParts.after }}\n\t\t\t\t\t</template>\n\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t{{ noticeParts.before }}\n\t\t\t\t\t</template>\n\t\t\t\t</NcNoteCard>\n\t\t\t</template>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { getLanguage, translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcActions, NcButton, NcNoteCard } from '@nextcloud/vue'\nimport BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'\nimport CalendarBlankOutline from 'vue-material-design-icons/CalendarBlankOutline.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport RoadVariant from 'vue-material-design-icons/RoadVariant.vue'\nimport CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'\nimport CnRoadmapTab from '../CnRoadmapTab/CnRoadmapTab.vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport { formatBoardDate } from '../../utils/boardDate.js'\nimport { countByStatus, FEATURE_STATUS_VARIANTS, FEATURE_STATUSES, groupFeatures } from '../../utils/featureCatalog.js'\nimport { fetchRoadmapIssues, issueStatus } from '../../utils/roadmapIssues.js'\nimport { safeHref } from '../../utils/safeHref.js'\n\nlet featuresBoardUid = 0\n\n/**\n * Read the reader's language, which @nextcloud/l10n throws on outside a\n * Nextcloud page.\n *\n * @return {string} The language tag, or ''.\n */\nfunction readerLanguage() {\n\ttry {\n\t\treturn getLanguage() || ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * CnFeaturesBoard - the Features and roadmap page in the board look.\n *\n * A title with a subtitle, optional folder tabs (Features, Roadmap), a status\n * filter (count chips or a segmented control), the features grouped by\n * category (as two-up cards or as rows inside one card per group), an\n * optional \"Next\" card with the most requested forge issues, and an optional\n * notice under the groups. The links the default look puts in its right-hand\n * sidebar (suggest, buildiq, AI skills, support) sit in an Actions menu.\n *\n * Rendered by CnFeaturesAndRoadmapView when the page is in the board look.\n *\n * @spec openspec/changes/screens-roadmap-board-look/specs/features-roadmap-board-look/spec.md\n *\n * @event support Emitted when the reader picks \"Support this app\" in the Actions menu.\n */\nexport default {\n\tname: 'CnFeaturesBoard',\n\n\tcomponents: {\n\t\tBookOpenVariant,\n\t\tCalendarBlankOutline,\n\t\tChevronRight,\n\t\tCnBuildiqEditButton,\n\t\tCnRoadmapTab,\n\t\tCnStatusBadge,\n\t\tDotsHorizontal,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcActions,\n\t\tNcButton,\n\t\tNcNoteCard,\n\t\tPlus,\n\t\tRoadVariant,\n\t},\n\n\tinject: {\n\t\t/** The app's translate function, provided by CnAppRoot. Identity outside one. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** The features: `{ slug, title, summary, status, category, expected, docsUrl, title_<lang>, summary_<lang> }`. */\n\t\tfeatures: { type: Array, default: () => [] },\n\t\t/** Category key to caption; sets the order of the groups. */\n\t\tcategories: { type: Object, default: () => ({}) },\n\t\t/** `cards`: a section per category with two-up feature cards. `rows`: one card per category with a row per feature. */\n\t\tlayout: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cards',\n\t\t\tvalidator: (value) => ['cards', 'rows'].includes(value),\n\t\t},\n\n\t\t/** Show the Features and Roadmap folder tabs. */\n\t\ttabs: { type: Boolean, default: true },\n\t\t/** `chips`: pill buttons with a count. `segmented`: a segmented control without counts. */\n\t\tfilter: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (value) => ['chips', 'segmented'].includes(value),\n\t\t},\n\n\t\t/** Overrides of the status labels, by key (`all`, `available`, `beta`, `in_progress`, `planned`). */\n\t\tstatusLabels: { type: Object, default: () => ({}) },\n\t\t/** How many issues the Next card lists; 0 hides the card. */\n\t\tnext: { type: Number, default: 3 },\n\t\t/** Forge label to issue status (`in_progress`, `planned`) for the badges in the Next card. */\n\t\tissueLabels: { type: Object, default: () => ({}) },\n\t\t/** `<owner>/<repo>` on the forge, for the Roadmap tab and the Next card. */\n\t\trepo: { type: String, default: '' },\n\t\t/** Page title. */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Subtitle template; `{count}` is the number of features and `{appVersion}` the app version. */\n\t\tsubtitle: { type: String, default: '' },\n\t\t/** The app version, for `{appVersion}` in the subtitle. */\n\t\tappVersion: { type: String, default: '' },\n\t\t/** An info notice under the groups. */\n\t\tnotice: { type: String, default: '' },\n\t\t/** The app's documentation site: the Next card's link and the target of \"Learn more\". */\n\t\tdocumentationUrl: { type: String, default: '' },\n\t\t/** Show a Documentation button in the header. */\n\t\tdocumentationButton: { type: Boolean, default: false },\n\t\t/** The feature-request form; the header's primary button. */\n\t\tsuggestUrl: { type: String, default: '' },\n\t\t/** Show the feature-request form as the header's primary button; without it, it is an entry in the Actions menu. */\n\t\tsuggestButton: { type: Boolean, default: true },\n\t\t/** In the `rows` layout, draw each feature's summary under its title; false shows the title and status only. */\n\t\tsummaries: { type: Boolean, default: true },\n\t\t/** A link inside the notice: `{ text, href }`; the first occurrence of `text` in the translated notice opens `href` in a new tab. Only http(s) and site-relative hrefs link. */\n\t\tnoticeLink: { type: Object, default: null },\n\t\t/** Target of the OpenBuilt entry in the Actions menu. */\n\t\topenbuiltUrl: { type: String, default: '' },\n\t\t/** Target of the AI skills entry in the Actions menu. */\n\t\tllmSkillsUrl: { type: String, default: '' },\n\t},\n\n\temits: ['support'],\n\n\tdata() {\n\t\tfeaturesBoardUid += 1\n\t\treturn {\n\t\t\tuid: `cn-features-board-${featuresBoardUid}`,\n\t\t\tactiveTab: 'features',\n\t\t\tstatus: 'all',\n\t\t\tissues: [],\n\t\t\tissuesLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tlanguage() {\n\t\t\treturn readerLanguage()\n\t\t},\n\n\t\t/** The groups, their captions through the app's translate function. */\n\t\tgroups() {\n\t\t\treturn groupFeatures(this.features, this.categories, this.language)\n\t\t\t\t.map((group) => ({ ...group, label: group.label ? this.tr(group.label) : '' }))\n\t\t},\n\n\t\tallFeatures() {\n\t\t\treturn this.groups.flatMap((group) => group.features)\n\t\t},\n\n\t\tcounts() {\n\t\t\treturn countByStatus(this.allFeatures)\n\t\t},\n\n\t\t/** The groups with the features the filter lets through; an emptied group is left out. */\n\t\tshownGroups() {\n\t\t\treturn this.groups\n\t\t\t\t.map((group) => ({\n\t\t\t\t\t...group,\n\t\t\t\t\tshown: this.status === 'all' ? group.features : group.features.filter((feature) => feature.status === this.status),\n\t\t\t\t}))\n\t\t\t\t.filter((group) => group.shown.length > 0)\n\t\t},\n\n\t\t/** All, then each status; `in_progress` only when a feature has it. */\n\t\tfilterOptions() {\n\t\t\tconst options = [{ key: 'all', label: this.statusLabel('all'), count: this.counts.all }]\n\t\t\tfor (const key of FEATURE_STATUSES) {\n\t\t\t\tif (key === 'in_progress' && this.counts.in_progress === 0) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\toptions.push({ key, label: this.statusLabel(key), count: this.counts[key] })\n\t\t\t}\n\t\t\treturn options\n\t\t},\n\n\t\ttabList() {\n\t\t\treturn [\n\t\t\t\t{ key: 'features', label: t('nextcloud-vue', 'Features') },\n\t\t\t\t{ key: 'roadmap', label: t('nextcloud-vue', 'Roadmap') },\n\t\t\t]\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\treturn this.title ? this.tr(this.title) : t('nextcloud-vue', 'Features and roadmap')\n\t\t},\n\n\t\t/**\n\t\t * The notice split around its link: the text before, the link and the\n\t\t * text after. Without a usable `noticeLink` (no match in the\n\t\t * translated notice, or an href that is not http(s) or site-relative)\n\t\t * `before` is the whole notice.\n\t\t *\n\t\t * @return {{before: string, link: ({text: string, href: string}|null), after: string}} The parts.\n\t\t */\n\t\tnoticeParts() {\n\t\t\tconst text = this.notice ? this.tr(this.notice) : ''\n\t\t\tconst link = this.noticeLink\n\t\t\tconst label = link && typeof link.text === 'string' ? this.tr(link.text) : ''\n\t\t\tconst href = link && typeof link.href === 'string' ? link.href.trim() : ''\n\t\t\tconst index = label ? text.indexOf(label) : -1\n\t\t\tconst allowed = (/^https?:\\/\\//i.test(href) || href.startsWith('/')) && safeHref(href) === href\n\t\t\tif (index === -1 || !allowed) {\n\t\t\t\treturn { before: text, link: null, after: '' }\n\t\t\t}\n\t\t\treturn { before: text.slice(0, index), link: { text: label, href }, after: text.slice(index + label.length) }\n\t\t},\n\n\t\tresolvedSubtitle() {\n\t\t\tif (!this.subtitle) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn this.tr(this.subtitle)\n\t\t\t\t.replace(/\\{count\\}/g, String(this.counts.all))\n\t\t\t\t.replace(/\\{appVersion\\}/g, this.appVersion)\n\t\t},\n\n\t\tmenuLinks() {\n\t\t\tconst links = []\n\t\t\tif (this.suggestUrl && !this.suggestButton) {\n\t\t\t\tlinks.push({ key: 'suggest', href: this.suggestUrl, label: t('nextcloud-vue', 'Suggest feature') })\n\t\t\t}\n\t\t\tif (this.openbuiltUrl) {\n\t\t\t\tlinks.push({ key: 'openbuilt', href: this.openbuiltUrl, label: t('nextcloud-vue', 'Build on this app') })\n\t\t\t}\n\t\t\tif (this.llmSkillsUrl) {\n\t\t\t\tlinks.push({ key: 'llm', href: this.llmSkillsUrl, label: t('nextcloud-vue', 'AI skills') })\n\t\t\t}\n\t\t\treturn links\n\t\t},\n\n\t\tnextIssues() {\n\t\t\treturn this.issues.slice(0, this.next).map((issue) => ({\n\t\t\t\tnumber: issue.number,\n\t\t\t\ttitle: issue.title,\n\t\t\t\thtml_url: issue.html_url,\n\t\t\t\tstatus: issueStatus(issue, this.issueLabels),\n\t\t\t\topened: issue.created_at ? formatBoardDate(issue.created_at) : '',\n\t\t\t}))\n\t\t},\n\t},\n\n\tmounted() {\n\t\tif (this.next > 0 && this.repo) {\n\t\t\tthis.loadIssues()\n\t\t}\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tsafeHref,\n\n\t\t/**\n\t\t * Run an app-supplied string through the app's translate function.\n\t\t *\n\t\t * @param {string} key The string.\n\t\t * @return {string} The translated string.\n\t\t */\n\t\ttr(key) {\n\t\t\treturn this.cnTranslate(key)\n\t\t},\n\n\t\t/**\n\t\t * The label of a status, or of `all`: the app's override, else the library's.\n\t\t *\n\t\t * @param {string} key The status key.\n\t\t * @return {string} The label.\n\t\t */\n\t\tstatusLabel(key) {\n\t\t\tif (typeof this.statusLabels[key] === 'string' && this.statusLabels[key] !== '') {\n\t\t\t\treturn this.tr(this.statusLabels[key])\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tall: t('nextcloud-vue', 'All'),\n\t\t\t\tavailable: t('nextcloud-vue', 'Available'),\n\t\t\t\tbeta: t('nextcloud-vue', 'Beta'),\n\t\t\t\tin_progress: t('nextcloud-vue', 'In progress'),\n\t\t\t\tplanned: t('nextcloud-vue', 'Planned'),\n\t\t\t}[key] || key\n\t\t},\n\n\t\t/**\n\t\t * The badge text of a feature: its status, with the expected moment\n\t\t * when it has one (\"Planned, Q4 2026\").\n\t\t *\n\t\t * @param {{status: string, expected: string}} feature The feature.\n\t\t * @return {string} The badge text.\n\t\t */\n\t\tstatusText(feature) {\n\t\t\tconst label = this.statusLabel(feature.status)\n\t\t\treturn feature.expected ? t('nextcloud-vue', '{status}, {expected}', { status: label, expected: feature.expected }) : label\n\t\t},\n\n\t\t/**\n\t\t * The badge variant of a status.\n\t\t *\n\t\t * @param {string} status The status key.\n\t\t * @return {string} The CnStatusBadge variant.\n\t\t */\n\t\tvariantOf(status) {\n\t\t\treturn FEATURE_STATUS_VARIANTS[status] || 'default'\n\t\t},\n\n\t\t/**\n\t\t * \"14 features, 14 available\": the group's size, then each status it holds.\n\t\t *\n\t\t * @param {{features: Array<{status: string}>}} group The group.\n\t\t * @return {string} The caption.\n\t\t */\n\t\tgroupCaption(group) {\n\t\t\tconst counts = countByStatus(group.features)\n\t\t\tconst parts = [n('nextcloud-vue', '%n feature', '%n features', counts.all)]\n\t\t\tfor (const key of FEATURE_STATUSES) {\n\t\t\t\tif (counts[key] > 0) {\n\t\t\t\t\tparts.push(`${counts[key]} ${this.statusLabel(key).toLocaleLowerCase()}`)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn parts.join(', ')\n\t\t},\n\n\t\t/**\n\t\t * Where \"Learn more\" goes: the feature's own page when it is a web\n\t\t * address, else the documentation site, else nowhere.\n\t\t *\n\t\t * @param {{docsUrl: string}} feature The feature.\n\t\t * @return {string} The address, or ''.\n\t\t */\n\t\treadMoreHref(feature) {\n\t\t\tif (/^https?:\\/\\//i.test(feature.docsUrl)) {\n\t\t\t\treturn safeHref(feature.docsUrl)\n\t\t\t}\n\t\t\treturn this.documentationUrl ? safeHref(this.documentationUrl) : ''\n\t\t},\n\n\t\t/** Ask the host to open the support dialog. */\n\t\tonSupport() {\n\t\t\t/**\n\t\t\t * @event support Emitted when the reader picks \"Support this app\" in the Actions menu.\n\t\t\t */\n\t\t\tthis.$emit('support')\n\t\t},\n\n\t\t/** Fetch the forge issues for the Next card. */\n\t\tasync loadIssues() {\n\t\t\tthis.issuesLoading = true\n\t\t\tconst { items } = await fetchRoadmapIssues(this.repo)\n\t\t\tthis.issues = items\n\t\t\tthis.issuesLoading = false\n\t\t},\n\n\t\t/**\n\t\t * Arrow keys, Home and End move between the folder tabs.\n\t\t *\n\t\t * @param {KeyboardEvent} event The key press.\n\t\t */\n\t\tonTabKeydown(event) {\n\t\t\tconst keys = this.tabList.map((tab) => tab.key)\n\t\t\tconst index = keys.indexOf(this.activeTab)\n\t\t\tconst target = {\n\t\t\t\tArrowRight: (index + 1) % keys.length,\n\t\t\t\tArrowLeft: (index - 1 + keys.length) % keys.length,\n\t\t\t\tHome: 0,\n\t\t\t\tEnd: keys.length - 1,\n\t\t\t}[event.key]\n\t\t\tif (target === undefined) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.preventDefault()\n\t\t\tthis.activeTab = keys[target]\n\t\t\tthis.$nextTick(() => this.$refs.tabButtons?.[target]?.focus())\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-features-board {\n\tbox-sizing: border-box;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--cn-board-section-gap, 20px);\n\tpadding: var(--cn-board-content-padding, 24px 28px);\n\tmax-width: 1240px;\n\twidth: 100%;\n}\n\n.cn-features-board__header {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tpadding: 4px 0 8px;\n}\n\n.cn-features-board__title-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tgap: 12px 24px;\n}\n\n.cn-features-board__title {\n\tflex: 1 1 320px;\n\tmin-width: 0;\n\tmargin: 0;\n\tfont-size: 28px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-features-board__header-actions {\n\tflex: none;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 10px;\n}\n\n.cn-features-board__subtitle {\n\tmargin: 0;\n\tfont-size: 15px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__tab-row {\n\tdisplay: flex;\n\talign-items: flex-end;\n\tgap: 8px;\n\tmargin-bottom: calc(-1 * var(--cn-board-section-gap, 20px));\n}\n\n.cn-features-board__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-features-board__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tbox-sizing: border-box;\n\tmin-height: 34px;\n\tmargin: 0 0 -1px;\n\tpadding: 8px 12px;\n\tborder: 1px solid var(--cn-board-hairline, var(--color-border));\n\tborder-bottom: none;\n\tborder-radius: 8px 8px 0 0;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 400;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n\n.cn-features-board__tab--active {\n\tposition: relative;\n\tbackground: var(--color-main-background);\n\tborder-bottom: 1px solid var(--color-main-background);\n\tfont-weight: 700;\n}\n\n.cn-features-board__tab-actions {\n\tflex: none;\n\talign-self: flex-start;\n\tmargin: 0 8px 8px 0;\n}\n\n.cn-features-board__panel {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 22px;\n}\n\n.cn-features-board__panel--tabbed {\n\tpadding: 22px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 0 var(--cn-board-card-radius, 12px) var(--cn-board-card-radius, 12px) var(--cn-board-card-radius, 12px);\n\tbackground: var(--color-main-background);\n}\n\n.cn-features-board__filter {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-features-board__filter-option {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n}\n\n.cn-features-board__filter--chips .cn-features-board__filter-option {\n\theight: 36px;\n\tpadding: 0 14px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 18px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n}\n\n.cn-features-board__filter--chips .cn-features-board__filter-option--active {\n\tborder-color: var(--color-main-text);\n\tbackground: var(--color-main-text);\n\tcolor: var(--color-main-background);\n}\n\n.cn-features-board__filter-count {\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__filter--chips .cn-features-board__filter-option--active .cn-features-board__filter-count {\n\tcolor: var(--color-border-dark);\n}\n\n.cn-features-board__filter--segmented {\n\tdisplay: inline-flex;\n\talign-self: flex-start;\n\tgap: 2px;\n\tpadding: 3px;\n\tborder-radius: 8px;\n\tbackground: var(--color-background-dark);\n}\n\n.cn-features-board__filter--segmented .cn-features-board__filter-option {\n\theight: 34px;\n\tpadding: 0 14px;\n\tborder: 0;\n\tborder-radius: 6px;\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n}\n\n.cn-features-board__filter--segmented .cn-features-board__filter-option--active {\n\tbackground: var(--color-main-background);\n\tbox-shadow: 0 1px 2px rgba(27, 28, 29, 0.12);\n}\n\n.cn-features-board__body {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-start;\n\tgap: 24px;\n}\n\n.cn-features-board__groups {\n\tflex: 999 1 520px;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 26px;\n}\n\n.cn-features-board__groups--rows {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(340px, 1fr));\n\tgap: 20px;\n}\n\n.cn-features-board__group {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmax-width: none;\n\tmargin: 0;\n}\n\n.cn-features-board__groups--rows .cn-features-board__group {\n\tpadding: var(--cn-board-card-padding, 20px 22px);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--cn-board-card-radius, 12px);\n\tbackground: var(--color-main-background);\n}\n\n.cn-features-board__group-head {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tgap: 10px;\n}\n\n.cn-features-board__group-title {\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-features-board__groups--rows .cn-features-board__group-title {\n\tfont-size: 17px;\n}\n\n.cn-features-board__group-caption {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__cards {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n\tgap: 16px;\n}\n\n.cn-features-board__card {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 10px;\n\tpadding: 18px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--cn-board-card-radius, 12px);\n\tbackground: var(--color-main-background);\n}\n\n.cn-features-board__card-head {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\tgap: 4px;\n}\n\n.cn-features-board__card-title {\n\tmargin: 0;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tline-height: 1.3;\n}\n\n.cn-features-board__card-summary {\n\tmargin: 0;\n\tfont-size: 14px;\n\tcolor: var(--color-main-text);\n}\n\n.cn-features-board__card-footer {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\talign-items: center;\n\tmin-height: 34px;\n\tmargin-top: auto;\n\tpadding-top: 10px;\n\tborder-top: 1px solid var(--color-background-dark);\n}\n\n.cn-features-board__read-more {\n\tdisplay: inline-flex;\n\talign-items: center;\n\theight: 34px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 8px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\ttext-decoration: none;\n}\n\n.cn-features-board__rows {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-features-board__row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 6px 16px;\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--color-background-dark);\n}\n\n.cn-features-board__row-text {\n\tflex: 1 1 240px;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-features-board__row-title {\n\tfont-size: 15px;\n\tfont-weight: 500;\n}\n\n.cn-features-board__row-summary {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__next {\n\tflex: 1 1 280px;\n\tmin-width: 0;\n\tmax-width: 340px;\n}\n\n.cn-features-board__next-card {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tpadding: 18px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--cn-board-card-radius, 12px);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-features-board__next-head {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-features-board__next-title {\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-features-board__next-lead {\n\tmargin: 0;\n\tfont-size: 14px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__next-list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 10px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-features-board__next-item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 10px;\n\tbackground: var(--color-main-background);\n}\n\n.cn-features-board__next-link {\n\tfont-size: 15px;\n\tfont-weight: 600;\n\tline-height: 1.3;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-features-board__next-meta {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__next-opened {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-features-board__next-more {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n}\n\n.cn-features-board__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__notice {\n\tmargin: 0;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_toDisplayString","_createBlock","_createVNode","_createTextVNode","_Fragment","_renderList","_openBlock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CnFeaturesBoard.vue3.js","sources":["../../../../src/components/CnFeaturesBoard/CnFeaturesBoard.vue?vue&type=template&id=022166a7&lang.js"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-features-board\" :class=\"`cn-features-board--${layout}`\" data-testid=\"cn-features-board\">\n\t\t<header class=\"cn-features-board__header\">\n\t\t\t<div class=\"cn-features-board__title-row\">\n\t\t\t\t<h1 class=\"cn-features-board__title\">\n\t\t\t\t\t{{ resolvedTitle }}\n\t\t\t\t</h1>\n\t\t\t\t<div class=\"cn-features-board__header-actions\">\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"documentationButton && documentationUrl\"\n\t\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\t\t:href=\"documentationUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\tdata-testid=\"cn-features-board-docs\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<BookOpenVariant :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Documentation') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<CnBuildiqEditButton />\n\t\t\t\t\t<NcButton\n\t\t\t\t\t\tv-if=\"suggestUrl && suggestButton\"\n\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t:href=\"suggestUrl\"\n\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\tdata-testid=\"cn-features-board-suggest\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<Plus :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t{{ t('nextcloud-vue', 'Suggest feature') }}\n\t\t\t\t\t</NcButton>\n\t\t\t\t\t<NcActions\n\t\t\t\t\t\tv-if=\"!tabs && actionsMenu\"\n\t\t\t\t\t\t:menuName=\"t('nextcloud-vue', 'Actions')\"\n\t\t\t\t\t\t:forceName=\"true\"\n\t\t\t\t\t\tdata-testid=\"cn-features-board-actions\">\n\t\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t\t<DotsHorizontal :size=\"20\" />\n\t\t\t\t\t\t</template>\n\t\t\t\t\t\t<NcActionLink\n\t\t\t\t\t\t\tv-for=\"action in menuLinks\"\n\t\t\t\t\t\t\t:key=\"action.key\"\n\t\t\t\t\t\t\t:href=\"action.href\"\n\t\t\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t\t\t{{ action.label }}\n\t\t\t\t\t\t</NcActionLink>\n\t\t\t\t\t\t<NcActionButton @click=\"onSupport\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Support this app') }}\n\t\t\t\t\t\t</NcActionButton>\n\t\t\t\t\t</NcActions>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<p v-if=\"resolvedSubtitle\" class=\"cn-features-board__subtitle\" data-testid=\"cn-features-board-subtitle\">\n\t\t\t\t{{ resolvedSubtitle }}\n\t\t\t</p>\n\t\t</header>\n\n\t\t<div v-if=\"tabs\" class=\"cn-features-board__tab-row\">\n\t\t\t<div\n\t\t\t\tclass=\"cn-features-board__tabs\"\n\t\t\t\trole=\"tablist\"\n\t\t\t\t:aria-label=\"resolvedTitle\"\n\t\t\t\t@keydown=\"onTabKeydown\">\n\t\t\t\t<button\n\t\t\t\t\tv-for=\"tab in tabList\"\n\t\t\t\t\t:id=\"`${uid}-tab-${tab.key}`\"\n\t\t\t\t\t:key=\"tab.key\"\n\t\t\t\t\tref=\"tabButtons\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\trole=\"tab\"\n\t\t\t\t\tclass=\"cn-features-board__tab\"\n\t\t\t\t\t:class=\"{ 'cn-features-board__tab--active': activeTab === tab.key }\"\n\t\t\t\t\t:aria-selected=\"activeTab === tab.key ? 'true' : 'false'\"\n\t\t\t\t\t:aria-controls=\"`${uid}-panel`\"\n\t\t\t\t\t:tabindex=\"activeTab === tab.key ? 0 : -1\"\n\t\t\t\t\t:data-testid=\"`cn-features-board-tab-${tab.key}`\"\n\t\t\t\t\t@click=\"activeTab = tab.key\">\n\t\t\t\t\t{{ tab.label }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<NcActions\n\t\t\t\tv-if=\"actionsMenu\"\n\t\t\t\t:menuName=\"t('nextcloud-vue', 'Actions')\"\n\t\t\t\t:forceName=\"true\"\n\t\t\t\tclass=\"cn-features-board__tab-actions\"\n\t\t\t\tdata-testid=\"cn-features-board-actions\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<DotsHorizontal :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t\t<NcActionLink\n\t\t\t\t\tv-for=\"action in menuLinks\"\n\t\t\t\t\t:key=\"action.key\"\n\t\t\t\t\t:href=\"action.href\"\n\t\t\t\t\ttarget=\"_blank\">\n\t\t\t\t\t{{ action.label }}\n\t\t\t\t</NcActionLink>\n\t\t\t\t<NcActionButton @click=\"onSupport\">\n\t\t\t\t\t{{ t('nextcloud-vue', 'Support this app') }}\n\t\t\t\t</NcActionButton>\n\t\t\t</NcActions>\n\t\t</div>\n\n\t\t<div\n\t\t\t:id=\"`${uid}-panel`\"\n\t\t\tclass=\"cn-features-board__panel\"\n\t\t\t:class=\"{ 'cn-features-board__panel--tabbed': tabs }\"\n\t\t\t:role=\"tabs ? 'tabpanel' : null\"\n\t\t\t:aria-labelledby=\"tabs ? `${uid}-tab-${activeTab}` : null\">\n\t\t\t<CnRoadmapTab v-if=\"tabs && activeTab === 'roadmap'\" :repo=\"repo\" />\n\t\t\t<template v-else>\n\t\t\t\t<div\n\t\t\t\t\tclass=\"cn-features-board__filter\"\n\t\t\t\t\t:class=\"`cn-features-board__filter--${filter}`\"\n\t\t\t\t\trole=\"group\"\n\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Status')\"\n\t\t\t\t\tdata-testid=\"cn-features-board-filter\">\n\t\t\t\t\t<button\n\t\t\t\t\t\tv-for=\"option in filterOptions\"\n\t\t\t\t\t\t:key=\"option.key\"\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclass=\"cn-features-board__filter-option\"\n\t\t\t\t\t\t:class=\"{ 'cn-features-board__filter-option--active': status === option.key }\"\n\t\t\t\t\t\t:aria-pressed=\"status === option.key ? 'true' : 'false'\"\n\t\t\t\t\t\t:data-status=\"option.key\"\n\t\t\t\t\t\t@click=\"status = option.key\">\n\t\t\t\t\t\t{{ option.label }}<span\n\t\t\t\t\t\t\tv-if=\"filter === 'chips'\"\n\t\t\t\t\t\t\tclass=\"cn-features-board__filter-count\"\n\t\t\t\t\t\t\tdata-testid=\"cn-features-board-filter-count\">{{ ' ' + option.count }}</span>\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"cn-features-board__body\">\n\t\t\t\t\t<div class=\"cn-features-board__groups\" :class=\"`cn-features-board__groups--${layout}`\">\n\t\t\t\t\t\t<p v-if=\"shownGroups.length === 0\" class=\"cn-features-board__empty\" data-testid=\"cn-features-board-empty\">\n\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'No features with this status') }}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t\t<section\n\t\t\t\t\t\t\tv-for=\"group in shownGroups\"\n\t\t\t\t\t\t\t:key=\"group.key\"\n\t\t\t\t\t\t\tclass=\"cn-features-board__group\"\n\t\t\t\t\t\t\t:aria-labelledby=\"group.label ? `${uid}-group-${group.key}` : null\"\n\t\t\t\t\t\t\t:aria-label=\"group.label ? null : resolvedTitle\"\n\t\t\t\t\t\t\tdata-testid=\"cn-features-board-group\"\n\t\t\t\t\t\t\t:data-group=\"group.key\">\n\t\t\t\t\t\t\t<div v-if=\"group.label\" class=\"cn-features-board__group-head\">\n\t\t\t\t\t\t\t\t<h2 :id=\"`${uid}-group-${group.key}`\" class=\"cn-features-board__group-title\">\n\t\t\t\t\t\t\t\t\t{{ group.label }}\n\t\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\tv-if=\"layout === 'cards'\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__group-caption\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-group-caption\">{{ groupCaption(group) }}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div v-if=\"layout === 'cards'\" class=\"cn-features-board__cards\">\n\t\t\t\t\t\t\t\t<article\n\t\t\t\t\t\t\t\t\tv-for=\"feature in group.shown\"\n\t\t\t\t\t\t\t\t\t:key=\"feature.slug\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__card\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-feature\">\n\t\t\t\t\t\t\t\t\t<div class=\"cn-features-board__card-head\">\n\t\t\t\t\t\t\t\t\t\t<h3 class=\"cn-features-board__card-title\">\n\t\t\t\t\t\t\t\t\t\t\t{{ feature.title }}\n\t\t\t\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\t\t\t:label=\"statusText(feature)\"\n\t\t\t\t\t\t\t\t\t\t\t:variant=\"variantOf(feature.status)\"\n\t\t\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-status\" />\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<p v-if=\"feature.summary\" class=\"cn-features-board__card-summary\">\n\t\t\t\t\t\t\t\t\t\t{{ feature.summary }}\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t<div v-if=\"readMoreHref(feature)\" class=\"cn-features-board__card-footer\">\n\t\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__read-more\"\n\t\t\t\t\t\t\t\t\t\t\t:href=\"readMoreHref(feature)\"\n\t\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Learn more about {title}', { title: feature.title })\">\n\t\t\t\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Learn more') }}\n\t\t\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</article>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<ul v-else class=\"cn-features-board__rows\">\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tv-for=\"feature in group.shown\"\n\t\t\t\t\t\t\t\t\t:key=\"feature.slug\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__row\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-feature\">\n\t\t\t\t\t\t\t\t\t<span class=\"cn-features-board__row-text\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"cn-features-board__row-title\">{{ feature.title }}</span>\n\t\t\t\t\t\t\t\t\t\t<span v-if=\"summaries && feature.summary\" class=\"cn-features-board__row-summary\">{{ feature.summary }}</span>\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\t\t:label=\"statusText(feature)\"\n\t\t\t\t\t\t\t\t\t\t:variant=\"variantOf(feature.status)\"\n\t\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-status\" />\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t</section>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<aside\n\t\t\t\t\t\tv-if=\"next > 0 && repo\"\n\t\t\t\t\t\tclass=\"cn-features-board__next\"\n\t\t\t\t\t\t:aria-label=\"t('nextcloud-vue', 'Next on the roadmap')\"\n\t\t\t\t\t\tdata-testid=\"cn-features-board-next\">\n\t\t\t\t\t\t<section class=\"cn-features-board__next-card\">\n\t\t\t\t\t\t\t<div class=\"cn-features-board__next-head\">\n\t\t\t\t\t\t\t\t<RoadVariant :size=\"20\" />\n\t\t\t\t\t\t\t\t<h2 class=\"cn-features-board__next-title\">\n\t\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Coming next') }}\n\t\t\t\t\t\t\t\t</h2>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<p class=\"cn-features-board__next-lead\">\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'The most requested items from the issue tracker.') }}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t<ol v-if=\"nextIssues.length > 0\" class=\"cn-features-board__next-list\">\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tv-for=\"issue in nextIssues\"\n\t\t\t\t\t\t\t\t\t:key=\"issue.number\"\n\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__next-item\"\n\t\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-next-item\">\n\t\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\t\tclass=\"cn-features-board__next-link\"\n\t\t\t\t\t\t\t\t\t\t:href=\"safeHref(issue.html_url)\"\n\t\t\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\t\t\trel=\"noopener noreferrer\">{{ issue.title }}</a>\n\t\t\t\t\t\t\t\t\t<div class=\"cn-features-board__next-meta\">\n\t\t\t\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\t\t\t\tv-if=\"issue.status\"\n\t\t\t\t\t\t\t\t\t\t\t:label=\"statusLabel(issue.status)\"\n\t\t\t\t\t\t\t\t\t\t\t:variant=\"variantOf(issue.status)\" />\n\t\t\t\t\t\t\t\t\t\t<span v-if=\"issue.opened\" class=\"cn-features-board__next-opened\">\n\t\t\t\t\t\t\t\t\t\t\t<CalendarBlankOutline :size=\"14\" />{{ t('nextcloud-vue', 'Opened {date}', { date: issue.opened }) }}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t<span>#{{ issue.number }}</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t</ol>\n\t\t\t\t\t\t\t<p v-else-if=\"!issuesLoading\" class=\"cn-features-board__next-lead\" data-testid=\"cn-features-board-next-empty\">\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'No roadmap items yet') }}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tv-if=\"tabs\"\n\t\t\t\t\t\t\t\thref=\"#\"\n\t\t\t\t\t\t\t\tclass=\"cn-features-board__next-more\"\n\t\t\t\t\t\t\t\tdata-testid=\"cn-features-board-whole-roadmap\"\n\t\t\t\t\t\t\t\t@click.prevent=\"activeTab = 'roadmap'\">\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'See the whole roadmap') }}<ChevronRight :size=\"16\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\tv-if=\"documentationUrl\"\n\t\t\t\t\t\t\t\t:href=\"documentationUrl\"\n\t\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\t\tclass=\"cn-features-board__next-more\">\n\t\t\t\t\t\t\t\t{{ t('nextcloud-vue', 'Documentation') }}<ChevronRight :size=\"16\" />\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t</section>\n\t\t\t\t\t</aside>\n\t\t\t\t</div>\n\n\t\t\t\t<NcNoteCard v-if=\"notice\"\n\t\t\t\t\ttype=\"info\"\n\t\t\t\t\tclass=\"cn-features-board__notice\"\n\t\t\t\t\tdata-testid=\"cn-features-board-notice\">\n\t\t\t\t\t<template v-if=\"noticeParts.link\">\n\t\t\t\t\t\t{{ noticeParts.before }}<a\n\t\t\t\t\t\t\t:href=\"noticeParts.link.href\"\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tdata-testid=\"cn-features-board-notice-link\">{{ noticeParts.link.text }}</a>{{ noticeParts.after }}\n\t\t\t\t\t</template>\n\t\t\t\t\t<template v-else>\n\t\t\t\t\t\t{{ noticeParts.before }}\n\t\t\t\t\t</template>\n\t\t\t\t</NcNoteCard>\n\t\t\t</template>\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { getLanguage, translatePlural as n, translate as t } from '@nextcloud/l10n'\nimport { NcActionButton, NcActionLink, NcActions, NcButton, NcNoteCard } from '@nextcloud/vue'\nimport BookOpenVariant from 'vue-material-design-icons/BookOpenVariant.vue'\nimport CalendarBlankOutline from 'vue-material-design-icons/CalendarBlankOutline.vue'\nimport ChevronRight from 'vue-material-design-icons/ChevronRight.vue'\nimport DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'\nimport Plus from 'vue-material-design-icons/Plus.vue'\nimport RoadVariant from 'vue-material-design-icons/RoadVariant.vue'\nimport CnBuildiqEditButton from '../CnBuildiqEditButton/CnBuildiqEditButton.vue'\nimport CnRoadmapTab from '../CnRoadmapTab/CnRoadmapTab.vue'\nimport CnStatusBadge from '../CnStatusBadge/CnStatusBadge.vue'\nimport { formatBoardDate } from '../../utils/boardDate.js'\nimport { countByStatus, FEATURE_STATUS_VARIANTS, FEATURE_STATUSES, groupFeatures } from '../../utils/featureCatalog.js'\nimport { fetchRoadmapIssues, issueStatus } from '../../utils/roadmapIssues.js'\nimport { safeHref } from '../../utils/safeHref.js'\n\nlet featuresBoardUid = 0\n\n/**\n * Read the reader's language, which @nextcloud/l10n throws on outside a\n * Nextcloud page.\n *\n * @return {string} The language tag, or ''.\n */\nfunction readerLanguage() {\n\ttry {\n\t\treturn getLanguage() || ''\n\t} catch {\n\t\treturn ''\n\t}\n}\n\n/**\n * CnFeaturesBoard - the Features and roadmap page in the board look.\n *\n * A title with a subtitle, optional folder tabs (Features, Roadmap), a status\n * filter (count chips or a segmented control), the features grouped by\n * category (as two-up cards or as rows inside one card per group), an\n * optional \"Next\" card with the most requested forge issues, and an optional\n * notice under the groups. The links the default look puts in its right-hand\n * sidebar (suggest, buildiq, AI skills, support) sit in an Actions menu.\n *\n * Rendered by CnFeaturesAndRoadmapView when the page is in the board look.\n *\n * @spec openspec/changes/screens-roadmap-board-look/specs/features-roadmap-board-look/spec.md\n *\n * @event support Emitted when the reader picks \"Support this app\" in the Actions menu.\n */\nexport default {\n\tname: 'CnFeaturesBoard',\n\n\tcomponents: {\n\t\tBookOpenVariant,\n\t\tCalendarBlankOutline,\n\t\tChevronRight,\n\t\tCnBuildiqEditButton,\n\t\tCnRoadmapTab,\n\t\tCnStatusBadge,\n\t\tDotsHorizontal,\n\t\tNcActionButton,\n\t\tNcActionLink,\n\t\tNcActions,\n\t\tNcButton,\n\t\tNcNoteCard,\n\t\tPlus,\n\t\tRoadVariant,\n\t},\n\n\tinject: {\n\t\t/** The app's translate function, provided by CnAppRoot. Identity outside one. */\n\t\tcnTranslate: { default: () => (key) => key },\n\t},\n\n\tprops: {\n\t\t/** The features: `{ slug, title, summary, status, category, expected, docsUrl, title_<lang>, summary_<lang> }`. */\n\t\tfeatures: { type: Array, default: () => [] },\n\t\t/** Category key to caption; sets the order of the groups. */\n\t\tcategories: { type: Object, default: () => ({}) },\n\t\t/** `cards`: a section per category with two-up feature cards. `rows`: one card per category with a row per feature. */\n\t\tlayout: {\n\t\t\ttype: String,\n\t\t\tdefault: 'cards',\n\t\t\tvalidator: (value) => ['cards', 'rows'].includes(value),\n\t\t},\n\n\t\t/** Show the Features and Roadmap folder tabs. */\n\t\ttabs: { type: Boolean, default: true },\n\t\t/** Show the Actions menu (suggest, buildiq, AI skills, support), in the header or the tab row; false draws none. */\n\t\tactionsMenu: { type: Boolean, default: true },\n\t\t/** `chips`: pill buttons with a count. `segmented`: a segmented control without counts. */\n\t\tfilter: {\n\t\t\ttype: String,\n\t\t\tdefault: 'chips',\n\t\t\tvalidator: (value) => ['chips', 'segmented'].includes(value),\n\t\t},\n\n\t\t/** Overrides of the status labels, by key (`all`, `available`, `beta`, `in_progress`, `planned`). */\n\t\tstatusLabels: { type: Object, default: () => ({}) },\n\t\t/** How many issues the Next card lists; 0 hides the card. */\n\t\tnext: { type: Number, default: 3 },\n\t\t/** Forge label to issue status (`in_progress`, `planned`) for the badges in the Next card. */\n\t\tissueLabels: { type: Object, default: () => ({}) },\n\t\t/** `<owner>/<repo>` on the forge, for the Roadmap tab and the Next card. */\n\t\trepo: { type: String, default: '' },\n\t\t/** Page title. */\n\t\ttitle: { type: String, default: '' },\n\t\t/** Subtitle template; `{count}` is the number of features and `{appVersion}` the app version. */\n\t\tsubtitle: { type: String, default: '' },\n\t\t/** The app version, for `{appVersion}` in the subtitle. */\n\t\tappVersion: { type: String, default: '' },\n\t\t/** An info notice under the groups. */\n\t\tnotice: { type: String, default: '' },\n\t\t/** The app's documentation site: the Next card's link and the target of \"Learn more\". */\n\t\tdocumentationUrl: { type: String, default: '' },\n\t\t/** Show a Documentation button in the header. */\n\t\tdocumentationButton: { type: Boolean, default: false },\n\t\t/** The feature-request form; the header's primary button. */\n\t\tsuggestUrl: { type: String, default: '' },\n\t\t/** Show the feature-request form as the header's primary button; without it, it is an entry in the Actions menu. */\n\t\tsuggestButton: { type: Boolean, default: true },\n\t\t/** In the `rows` layout, draw each feature's summary under its title; false shows the title and status only. */\n\t\tsummaries: { type: Boolean, default: true },\n\t\t/** A link inside the notice: `{ text, href }`; the first occurrence of `text` in the translated notice opens `href` in a new tab. Only http(s) and site-relative hrefs link. */\n\t\tnoticeLink: { type: Object, default: null },\n\t\t/** Target of the OpenBuilt entry in the Actions menu. */\n\t\topenbuiltUrl: { type: String, default: '' },\n\t\t/** Target of the AI skills entry in the Actions menu. */\n\t\tllmSkillsUrl: { type: String, default: '' },\n\t},\n\n\temits: ['support'],\n\n\tdata() {\n\t\tfeaturesBoardUid += 1\n\t\treturn {\n\t\t\tuid: `cn-features-board-${featuresBoardUid}`,\n\t\t\tactiveTab: 'features',\n\t\t\tstatus: 'all',\n\t\t\tissues: [],\n\t\t\tissuesLoading: false,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tlanguage() {\n\t\t\treturn readerLanguage()\n\t\t},\n\n\t\t/** The groups, their captions through the app's translate function. */\n\t\tgroups() {\n\t\t\treturn groupFeatures(this.features, this.categories, this.language)\n\t\t\t\t.map((group) => ({ ...group, label: group.label ? this.tr(group.label) : '' }))\n\t\t},\n\n\t\tallFeatures() {\n\t\t\treturn this.groups.flatMap((group) => group.features)\n\t\t},\n\n\t\tcounts() {\n\t\t\treturn countByStatus(this.allFeatures)\n\t\t},\n\n\t\t/** The groups with the features the filter lets through; an emptied group is left out. */\n\t\tshownGroups() {\n\t\t\treturn this.groups\n\t\t\t\t.map((group) => ({\n\t\t\t\t\t...group,\n\t\t\t\t\tshown: this.status === 'all' ? group.features : group.features.filter((feature) => feature.status === this.status),\n\t\t\t\t}))\n\t\t\t\t.filter((group) => group.shown.length > 0)\n\t\t},\n\n\t\t/** All, then each status; `in_progress` only when a feature has it. */\n\t\tfilterOptions() {\n\t\t\tconst options = [{ key: 'all', label: this.statusLabel('all'), count: this.counts.all }]\n\t\t\tfor (const key of FEATURE_STATUSES) {\n\t\t\t\tif (key === 'in_progress' && this.counts.in_progress === 0) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\toptions.push({ key, label: this.statusLabel(key), count: this.counts[key] })\n\t\t\t}\n\t\t\treturn options\n\t\t},\n\n\t\ttabList() {\n\t\t\treturn [\n\t\t\t\t{ key: 'features', label: t('nextcloud-vue', 'Features') },\n\t\t\t\t{ key: 'roadmap', label: t('nextcloud-vue', 'Roadmap') },\n\t\t\t]\n\t\t},\n\n\t\tresolvedTitle() {\n\t\t\treturn this.title ? this.tr(this.title) : t('nextcloud-vue', 'Features and roadmap')\n\t\t},\n\n\t\t/**\n\t\t * The notice split around its link: the text before, the link and the\n\t\t * text after. Without a usable `noticeLink` (no match in the\n\t\t * translated notice, or an href that is not http(s) or site-relative)\n\t\t * `before` is the whole notice.\n\t\t *\n\t\t * @return {{before: string, link: ({text: string, href: string}|null), after: string}} The parts.\n\t\t */\n\t\tnoticeParts() {\n\t\t\tconst text = this.notice ? this.tr(this.notice) : ''\n\t\t\tconst link = this.noticeLink\n\t\t\tconst label = link && typeof link.text === 'string' ? this.tr(link.text) : ''\n\t\t\tconst href = link && typeof link.href === 'string' ? link.href.trim() : ''\n\t\t\tconst index = label ? text.indexOf(label) : -1\n\t\t\tconst allowed = (/^https?:\\/\\//i.test(href) || href.startsWith('/')) && safeHref(href) === href\n\t\t\tif (index === -1 || !allowed) {\n\t\t\t\treturn { before: text, link: null, after: '' }\n\t\t\t}\n\t\t\treturn { before: text.slice(0, index), link: { text: label, href }, after: text.slice(index + label.length) }\n\t\t},\n\n\t\tresolvedSubtitle() {\n\t\t\tif (!this.subtitle) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn this.tr(this.subtitle)\n\t\t\t\t.replace(/\\{count\\}/g, String(this.counts.all))\n\t\t\t\t.replace(/\\{appVersion\\}/g, this.appVersion)\n\t\t},\n\n\t\tmenuLinks() {\n\t\t\tconst links = []\n\t\t\tif (this.suggestUrl && !this.suggestButton) {\n\t\t\t\tlinks.push({ key: 'suggest', href: this.suggestUrl, label: t('nextcloud-vue', 'Suggest feature') })\n\t\t\t}\n\t\t\tif (this.openbuiltUrl) {\n\t\t\t\tlinks.push({ key: 'openbuilt', href: this.openbuiltUrl, label: t('nextcloud-vue', 'Build on this app') })\n\t\t\t}\n\t\t\tif (this.llmSkillsUrl) {\n\t\t\t\tlinks.push({ key: 'llm', href: this.llmSkillsUrl, label: t('nextcloud-vue', 'AI skills') })\n\t\t\t}\n\t\t\treturn links\n\t\t},\n\n\t\tnextIssues() {\n\t\t\treturn this.issues.slice(0, this.next).map((issue) => ({\n\t\t\t\tnumber: issue.number,\n\t\t\t\ttitle: issue.title,\n\t\t\t\thtml_url: issue.html_url,\n\t\t\t\tstatus: issueStatus(issue, this.issueLabels),\n\t\t\t\topened: issue.created_at ? formatBoardDate(issue.created_at) : '',\n\t\t\t}))\n\t\t},\n\t},\n\n\tmounted() {\n\t\tif (this.next > 0 && this.repo) {\n\t\t\tthis.loadIssues()\n\t\t}\n\t},\n\n\tmethods: {\n\t\tt,\n\t\tsafeHref,\n\n\t\t/**\n\t\t * Run an app-supplied string through the app's translate function.\n\t\t *\n\t\t * @param {string} key The string.\n\t\t * @return {string} The translated string.\n\t\t */\n\t\ttr(key) {\n\t\t\treturn this.cnTranslate(key)\n\t\t},\n\n\t\t/**\n\t\t * The label of a status, or of `all`: the app's override, else the library's.\n\t\t *\n\t\t * @param {string} key The status key.\n\t\t * @return {string} The label.\n\t\t */\n\t\tstatusLabel(key) {\n\t\t\tif (typeof this.statusLabels[key] === 'string' && this.statusLabels[key] !== '') {\n\t\t\t\treturn this.tr(this.statusLabels[key])\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tall: t('nextcloud-vue', 'All'),\n\t\t\t\tavailable: t('nextcloud-vue', 'Available'),\n\t\t\t\tbeta: t('nextcloud-vue', 'Beta'),\n\t\t\t\tin_progress: t('nextcloud-vue', 'In progress'),\n\t\t\t\tplanned: t('nextcloud-vue', 'Planned'),\n\t\t\t}[key] || key\n\t\t},\n\n\t\t/**\n\t\t * The badge text of a feature: its status, with the expected moment\n\t\t * when it has one (\"Planned, Q4 2026\").\n\t\t *\n\t\t * @param {{status: string, expected: string}} feature The feature.\n\t\t * @return {string} The badge text.\n\t\t */\n\t\tstatusText(feature) {\n\t\t\tconst label = this.statusLabel(feature.status)\n\t\t\treturn feature.expected ? t('nextcloud-vue', '{status}, {expected}', { status: label, expected: feature.expected }) : label\n\t\t},\n\n\t\t/**\n\t\t * The badge variant of a status.\n\t\t *\n\t\t * @param {string} status The status key.\n\t\t * @return {string} The CnStatusBadge variant.\n\t\t */\n\t\tvariantOf(status) {\n\t\t\treturn FEATURE_STATUS_VARIANTS[status] || 'default'\n\t\t},\n\n\t\t/**\n\t\t * \"14 features, 14 available\": the group's size, then each status it holds.\n\t\t *\n\t\t * @param {{features: Array<{status: string}>}} group The group.\n\t\t * @return {string} The caption.\n\t\t */\n\t\tgroupCaption(group) {\n\t\t\tconst counts = countByStatus(group.features)\n\t\t\tconst parts = [n('nextcloud-vue', '%n feature', '%n features', counts.all)]\n\t\t\tfor (const key of FEATURE_STATUSES) {\n\t\t\t\tif (counts[key] > 0) {\n\t\t\t\t\tparts.push(`${counts[key]} ${this.statusLabel(key).toLocaleLowerCase()}`)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn parts.join(', ')\n\t\t},\n\n\t\t/**\n\t\t * Where \"Learn more\" goes: the feature's own page when it is a web\n\t\t * address, else the documentation site, else nowhere.\n\t\t *\n\t\t * @param {{docsUrl: string}} feature The feature.\n\t\t * @return {string} The address, or ''.\n\t\t */\n\t\treadMoreHref(feature) {\n\t\t\tif (/^https?:\\/\\//i.test(feature.docsUrl)) {\n\t\t\t\treturn safeHref(feature.docsUrl)\n\t\t\t}\n\t\t\treturn this.documentationUrl ? safeHref(this.documentationUrl) : ''\n\t\t},\n\n\t\t/** Ask the host to open the support dialog. */\n\t\tonSupport() {\n\t\t\t/**\n\t\t\t * @event support Emitted when the reader picks \"Support this app\" in the Actions menu.\n\t\t\t */\n\t\t\tthis.$emit('support')\n\t\t},\n\n\t\t/** Fetch the forge issues for the Next card. */\n\t\tasync loadIssues() {\n\t\t\tthis.issuesLoading = true\n\t\t\tconst { items } = await fetchRoadmapIssues(this.repo)\n\t\t\tthis.issues = items\n\t\t\tthis.issuesLoading = false\n\t\t},\n\n\t\t/**\n\t\t * Arrow keys, Home and End move between the folder tabs.\n\t\t *\n\t\t * @param {KeyboardEvent} event The key press.\n\t\t */\n\t\tonTabKeydown(event) {\n\t\t\tconst keys = this.tabList.map((tab) => tab.key)\n\t\t\tconst index = keys.indexOf(this.activeTab)\n\t\t\tconst target = {\n\t\t\t\tArrowRight: (index + 1) % keys.length,\n\t\t\t\tArrowLeft: (index - 1 + keys.length) % keys.length,\n\t\t\t\tHome: 0,\n\t\t\t\tEnd: keys.length - 1,\n\t\t\t}[event.key]\n\t\t\tif (target === undefined) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tevent.preventDefault()\n\t\t\tthis.activeTab = keys[target]\n\t\t\tthis.$nextTick(() => this.$refs.tabButtons?.[target]?.focus())\n\t\t},\n\t},\n}\n</script>\n\n<style scoped>\n.cn-features-board {\n\tbox-sizing: border-box;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: var(--cn-board-section-gap, 20px);\n\tpadding: var(--cn-board-content-padding, 24px 28px);\n\tmax-width: 1240px;\n\twidth: 100%;\n}\n\n.cn-features-board__header {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tpadding: 4px 0 8px;\n}\n\n.cn-features-board__title-row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tjustify-content: space-between;\n\talign-items: flex-start;\n\tgap: 12px 24px;\n}\n\n.cn-features-board__title {\n\tflex: 1 1 320px;\n\tmin-width: 0;\n\tmargin: 0;\n\tfont-size: 28px;\n\tfont-weight: 700;\n\tline-height: 1.2;\n}\n\n.cn-features-board__header-actions {\n\tflex: none;\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 10px;\n}\n\n.cn-features-board__subtitle {\n\tmargin: 0;\n\tfont-size: 15px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__tab-row {\n\tdisplay: flex;\n\talign-items: flex-end;\n\tgap: 8px;\n\tmargin-bottom: calc(-1 * var(--cn-board-section-gap, 20px));\n}\n\n.cn-features-board__tabs {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 4px;\n\tflex: 1 1 auto;\n\tmin-width: 0;\n}\n\n.cn-features-board__tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tbox-sizing: border-box;\n\tmin-height: 34px;\n\tmargin: 0 0 -1px;\n\tpadding: 8px 12px;\n\tborder: 1px solid var(--cn-board-hairline, var(--color-border));\n\tborder-bottom: none;\n\tborder-radius: 8px 8px 0 0;\n\tbackground: var(--color-background-dark);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 400;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n\n.cn-features-board__tab--active {\n\tposition: relative;\n\tbackground: var(--color-main-background);\n\tborder-bottom: 1px solid var(--color-main-background);\n\tfont-weight: 700;\n}\n\n.cn-features-board__tab-actions {\n\tflex: none;\n\talign-self: flex-start;\n\tmargin: 0 8px 8px 0;\n}\n\n.cn-features-board__panel {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 22px;\n}\n\n.cn-features-board__panel--tabbed {\n\tpadding: 22px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 0 var(--cn-board-card-radius, 12px) var(--cn-board-card-radius, 12px) var(--cn-board-card-radius, 12px);\n\tbackground: var(--color-main-background);\n}\n\n.cn-features-board__filter {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-features-board__filter-option {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin: 0;\n\tfont-size: 14px;\n\tfont-weight: 600;\n\tcursor: pointer;\n}\n\n.cn-features-board__filter--chips .cn-features-board__filter-option {\n\theight: 36px;\n\tpadding: 0 14px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 18px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n}\n\n.cn-features-board__filter--chips .cn-features-board__filter-option--active {\n\tborder-color: var(--color-main-text);\n\tbackground: var(--color-main-text);\n\tcolor: var(--color-main-background);\n}\n\n.cn-features-board__filter-count {\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__filter--chips .cn-features-board__filter-option--active .cn-features-board__filter-count {\n\tcolor: var(--color-border-dark);\n}\n\n.cn-features-board__filter--segmented {\n\tdisplay: inline-flex;\n\talign-self: flex-start;\n\tgap: 2px;\n\tpadding: 3px;\n\tborder-radius: 8px;\n\tbackground: var(--color-background-dark);\n}\n\n.cn-features-board__filter--segmented .cn-features-board__filter-option {\n\theight: 34px;\n\tpadding: 0 14px;\n\tborder: 0;\n\tborder-radius: 6px;\n\tbackground: transparent;\n\tcolor: var(--color-main-text);\n}\n\n.cn-features-board__filter--segmented .cn-features-board__filter-option--active {\n\tbackground: var(--color-main-background);\n\tbox-shadow: 0 1px 2px rgba(27, 28, 29, 0.12);\n}\n\n.cn-features-board__body {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-start;\n\tgap: 24px;\n}\n\n.cn-features-board__groups {\n\tflex: 999 1 520px;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 26px;\n}\n\n.cn-features-board__groups--rows {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fit, minmax(340px, 1fr));\n\tgap: 20px;\n}\n\n.cn-features-board__group {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tmax-width: none;\n\tmargin: 0;\n}\n\n.cn-features-board__groups--rows .cn-features-board__group {\n\tpadding: var(--cn-board-card-padding, 20px 22px);\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--cn-board-card-radius, 12px);\n\tbackground: var(--color-main-background);\n}\n\n.cn-features-board__group-head {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: baseline;\n\tgap: 10px;\n}\n\n.cn-features-board__group-title {\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-features-board__groups--rows .cn-features-board__group-title {\n\tfont-size: 17px;\n}\n\n.cn-features-board__group-caption {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__cards {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n\tgap: 16px;\n}\n\n.cn-features-board__card {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 10px;\n\tpadding: 18px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--cn-board-card-radius, 12px);\n\tbackground: var(--color-main-background);\n}\n\n.cn-features-board__card-head {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\tgap: 4px;\n}\n\n.cn-features-board__card-title {\n\tmargin: 0;\n\tfont-size: 17px;\n\tfont-weight: 700;\n\tline-height: 1.3;\n}\n\n.cn-features-board__card-summary {\n\tmargin: 0;\n\tfont-size: 14px;\n\tcolor: var(--color-main-text);\n}\n\n.cn-features-board__card-footer {\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\talign-items: center;\n\tmin-height: 34px;\n\tmargin-top: auto;\n\tpadding-top: 10px;\n\tborder-top: 1px solid var(--color-background-dark);\n}\n\n.cn-features-board__read-more {\n\tdisplay: inline-flex;\n\talign-items: center;\n\theight: 34px;\n\tpadding: 0 12px;\n\tborder: 1px solid var(--color-border-dark);\n\tborder-radius: 8px;\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\tfont-weight: 600;\n\ttext-decoration: none;\n}\n\n.cn-features-board__rows {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-features-board__row {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 6px 16px;\n\tpadding: 10px 0;\n\tborder-top: 1px solid var(--color-background-dark);\n}\n\n.cn-features-board__row-text {\n\tflex: 1 1 240px;\n\tmin-width: 0;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n}\n\n.cn-features-board__row-title {\n\tfont-size: 15px;\n\tfont-weight: 500;\n}\n\n.cn-features-board__row-summary {\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__next {\n\tflex: 1 1 280px;\n\tmin-width: 0;\n\tmax-width: 340px;\n}\n\n.cn-features-board__next-card {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 12px;\n\tpadding: 18px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--cn-board-card-radius, 12px);\n\tbackground: var(--color-background-hover);\n}\n\n.cn-features-board__next-head {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n}\n\n.cn-features-board__next-title {\n\tmargin: 0;\n\tfont-size: 18px;\n\tfont-weight: 700;\n}\n\n.cn-features-board__next-lead {\n\tmargin: 0;\n\tfont-size: 14px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__next-list {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 10px;\n\tmargin: 0;\n\tpadding: 0;\n\tlist-style: none;\n}\n\n.cn-features-board__next-item {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 6px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 10px;\n\tbackground: var(--color-main-background);\n}\n\n.cn-features-board__next-link {\n\tfont-size: 15px;\n\tfont-weight: 600;\n\tline-height: 1.3;\n\tcolor: var(--color-main-text);\n\ttext-decoration: none;\n}\n\n.cn-features-board__next-meta {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: center;\n\tgap: 8px;\n\tfont-size: 13px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__next-opened {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n}\n\n.cn-features-board__next-more {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 4px;\n\tfont-size: 14px;\n\tfont-weight: 600;\n}\n\n.cn-features-board__empty {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.cn-features-board__notice {\n\tmargin: 0;\n}\n</style>\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_toDisplayString","_createBlock","_createVNode","_createTextVNode","_Fragment","_renderList","_openBlock"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import script from './CnFlowBoard.vue2.js';
|
|
|
2
2
|
import { render } from './CnFlowBoard.vue3.js';
|
|
3
3
|
|
|
4
4
|
script.render = render;
|
|
5
|
-
script.__scopeId = "data-v-
|
|
5
|
+
script.__scopeId = "data-v-72119172";
|
|
6
6
|
const __sfc_main = script;
|
|
7
7
|
|
|
8
8
|
export { __sfc_main as default };
|
|
@@ -11,6 +11,7 @@ import __sfc_main$3 from '../CnResourceSelect/CnResourceSelect.vue.js';
|
|
|
11
11
|
import { useFlowStore, FLOW_RUN_ACTIVE_STATUSES } from '../../composables/useFlowStore.js';
|
|
12
12
|
import { formatRelativeDate } from '../../utils/boardDate.js';
|
|
13
13
|
import { formatFlowDuration, flowRunDurationMs, flowRunName, flowRunLogLines, flowOutcomeLevels } from '../../utils/flowRunLog.js';
|
|
14
|
+
import { appDisplayNames } from '../../utils/nextcloudApps.js';
|
|
14
15
|
import __sfc_main$7 from '../CnStatusBadge/CnStatusBadge.vue.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -57,7 +58,7 @@ var script = {
|
|
|
57
58
|
},
|
|
58
59
|
|
|
59
60
|
data() {
|
|
60
|
-
return { runTab: 'step', testOpen: false, testRecord: null }
|
|
61
|
+
return { runTab: 'step', testOpen: false, testRecord: null, appNames: {}, showRuns: false }
|
|
61
62
|
},
|
|
62
63
|
|
|
63
64
|
computed: {
|
|
@@ -193,17 +194,25 @@ var script = {
|
|
|
193
194
|
return { tone: 'success', text: this.t('nextcloud-vue', 'The flow is valid.') }
|
|
194
195
|
},
|
|
195
196
|
|
|
196
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* The palette grouped by owning app, each group named by the app's
|
|
199
|
+
* display name (its id when Nextcloud names none), the app that owns
|
|
200
|
+
* this flow first.
|
|
201
|
+
*
|
|
202
|
+
* @return {Array<{app: string, name: string, entries: Array<object>}>} The groups.
|
|
203
|
+
*/
|
|
197
204
|
paletteGroups() {
|
|
198
205
|
const groups = {}
|
|
199
206
|
;(this.store.nodeCatalog || []).forEach((entry) => {
|
|
200
207
|
const app = String(entry?.app || String(entry?.id || '').split('.')[0] || '');
|
|
201
208
|
if (!groups[app]) {
|
|
202
|
-
groups[app] = { app, entries: [] };
|
|
209
|
+
groups[app] = { app, name: this.appNames[app] || app, entries: [] };
|
|
203
210
|
}
|
|
204
211
|
groups[app].entries.push(entry);
|
|
205
212
|
});
|
|
206
|
-
|
|
213
|
+
const list = Object.values(groups);
|
|
214
|
+
const host = list.findIndex((group) => group.app === this.app);
|
|
215
|
+
return host > 0 ? [list[host], ...list.slice(0, host), ...list.slice(host + 1)] : list
|
|
207
216
|
},
|
|
208
217
|
|
|
209
218
|
/** @return {object|null} The run on screen. */
|
|
@@ -256,6 +265,37 @@ var script = {
|
|
|
256
265
|
return entry ? (entry.displayName || entry.id) : String(node?.type || '')
|
|
257
266
|
},
|
|
258
267
|
|
|
268
|
+
/**
|
|
269
|
+
* The selected step's settings as its owner declares them in the
|
|
270
|
+
* catalogue's `configForm`: label and value, a select's option label,
|
|
271
|
+
* Yes or No for a switch. Unset settings are left out.
|
|
272
|
+
*
|
|
273
|
+
* @return {Array<{key: string, label: string, value: string}>} The settings.
|
|
274
|
+
*/
|
|
275
|
+
stepSettings() {
|
|
276
|
+
const node = this.store.selectedNode;
|
|
277
|
+
const entry = node ? this.store.catalogEntry(node.type) : null;
|
|
278
|
+
const config = (node && node.config) || {};
|
|
279
|
+
const form = (entry && Array.isArray(entry.configForm)) ? entry.configForm : [];
|
|
280
|
+
return form
|
|
281
|
+
.filter((field) => field && field.key && config[field.key] !== undefined && config[field.key] !== null && config[field.key] !== '')
|
|
282
|
+
.map((field) => {
|
|
283
|
+
const raw = config[field.key];
|
|
284
|
+
const option = Array.isArray(field.options) ? field.options.find((o) => o && o.value === raw) : null;
|
|
285
|
+
let value;
|
|
286
|
+
if (option) {
|
|
287
|
+
value = String(option.label ?? option.value);
|
|
288
|
+
} else if (typeof raw === 'boolean') {
|
|
289
|
+
value = raw ? this.t('nextcloud-vue', 'Yes') : this.t('nextcloud-vue', 'No');
|
|
290
|
+
} else if (typeof raw === 'object') {
|
|
291
|
+
value = JSON.stringify(raw);
|
|
292
|
+
} else {
|
|
293
|
+
value = String(raw);
|
|
294
|
+
}
|
|
295
|
+
return { key: field.key, label: field.label || field.key, value }
|
|
296
|
+
})
|
|
297
|
+
},
|
|
298
|
+
|
|
259
299
|
/** @return {string} The selected step's name. */
|
|
260
300
|
stepName() {
|
|
261
301
|
const node = this.store.selectedNode;
|
|
@@ -286,7 +326,36 @@ var script = {
|
|
|
286
326
|
},
|
|
287
327
|
},
|
|
288
328
|
|
|
329
|
+
watch: {
|
|
330
|
+
// A selected step takes the panel back from the run history.
|
|
331
|
+
'store.selectedNodeId': function(id) {
|
|
332
|
+
if (id) {
|
|
333
|
+
this.showRuns = false;
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
async created() {
|
|
339
|
+
// The palette names its groups by app display name; only the column
|
|
340
|
+
// palette draws them, so only it reads the names.
|
|
341
|
+
if (this.palette !== 'column') {
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
const { default: axios } = await import('@nextcloud/axios');
|
|
345
|
+
this.appNames = await appDisplayNames(axios);
|
|
346
|
+
},
|
|
347
|
+
|
|
289
348
|
methods: {
|
|
349
|
+
/**
|
|
350
|
+
* Run the flow, with the run history in the panel to follow it.
|
|
351
|
+
*
|
|
352
|
+
* @return {void}
|
|
353
|
+
*/
|
|
354
|
+
onRun() {
|
|
355
|
+
this.showRuns = true;
|
|
356
|
+
this.$emit('run');
|
|
357
|
+
},
|
|
358
|
+
|
|
290
359
|
/**
|
|
291
360
|
* Run the saved flow once with the picked record as its subject, then
|
|
292
361
|
* close the dialog; the run shows on the canvas as any run does.
|