@conduction/nextcloud-vue 2.147.0 → 2.149.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue.js +1 -1
  2. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +24 -7
  3. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  4. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue.js +1 -1
  6. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +12 -1
  7. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
  8. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +2 -1
  9. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
  10. package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue.js +1 -1
  11. package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js +23 -1
  12. package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue2.js.map +1 -1
  13. package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js +1 -1
  14. package/dist/esm/components/CnChecklistRunWidget/CnChecklistRunWidget.vue3.js.map +1 -1
  15. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +34 -1
  16. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  17. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  18. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +71 -8
  19. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  20. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +2 -2
  21. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  22. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue.js +1 -1
  23. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue2.js.map +1 -1
  24. package/dist/esm/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue3.js.map +1 -1
  25. package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue.js +1 -1
  26. package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue2.js.map +1 -1
  27. package/dist/esm/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue3.js.map +1 -1
  28. package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue.js +1 -1
  29. package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js +64 -8
  30. package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue2.js.map +1 -1
  31. package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js +14 -4
  32. package/dist/esm/components/CnDuplicateWarning/CnDuplicateWarning.vue3.js.map +1 -1
  33. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue.js +1 -1
  34. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js +32 -4
  35. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue2.js.map +1 -1
  36. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js +10 -2
  37. package/dist/esm/components/CnFactsWidget/CnFactsWidget.vue3.js.map +1 -1
  38. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue.js +1 -1
  39. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js +84 -1
  40. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js +61 -33
  42. package/dist/esm/components/CnFieldListWidget/CnFieldListWidget.vue3.js.map +1 -1
  43. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue.js +1 -1
  44. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js +49 -2
  45. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue2.js.map +1 -1
  46. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js +90 -59
  47. package/dist/esm/components/CnFlowRunsWidget/CnFlowRunsWidget.vue3.js.map +1 -1
  48. package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue2.js +3 -1
  49. package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue2.js.map +1 -1
  50. package/dist/esm/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue3.js.map +1 -1
  51. package/dist/esm/components/CnNotesCard/CnNotesCard.vue.js +1 -1
  52. package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js +10 -0
  53. package/dist/esm/components/CnNotesCard/CnNotesCard.vue2.js.map +1 -1
  54. package/dist/esm/components/CnNotesCard/CnNotesCard.vue3.js.map +1 -1
  55. package/dist/esm/components/CnObjectCard/CnObjectCard.vue.js +1 -1
  56. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js +11 -0
  57. package/dist/esm/components/CnObjectCard/CnObjectCard.vue2.js.map +1 -1
  58. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js +28 -21
  59. package/dist/esm/components/CnObjectCard/CnObjectCard.vue3.js.map +1 -1
  60. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue.js +1 -1
  61. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js +8 -0
  62. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue2.js.map +1 -1
  63. package/dist/esm/components/CnObjectDataWidget/CnObjectDataWidget.vue3.js.map +1 -1
  64. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue.js +1 -1
  65. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +1 -1
  66. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  67. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  68. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue.js +1 -1
  69. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js +3 -15
  70. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue2.js.map +1 -1
  71. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js +123 -115
  72. package/dist/esm/components/CnRecordListWidget/CnRecordListWidget.vue3.js.map +1 -1
  73. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue.js +1 -1
  74. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js +4 -0
  75. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue2.js.map +1 -1
  76. package/dist/esm/components/CnRegisterMapping/CnRegisterMapping.vue3.js.map +1 -1
  77. package/dist/esm/components/CnStepper/CnStepper.vue.js +1 -1
  78. package/dist/esm/components/CnStepper/CnStepper.vue2.js.map +1 -1
  79. package/dist/esm/components/CnStepper/CnStepper.vue3.js.map +1 -1
  80. package/dist/esm/dialogs/CnAccessPurposeDialog.vue.js +1 -1
  81. package/dist/esm/dialogs/CnAccessPurposeDialog.vue2.js +3 -1
  82. package/dist/esm/dialogs/CnAccessPurposeDialog.vue2.js.map +1 -1
  83. package/dist/esm/dialogs/CnAccessPurposeDialog.vue3.js +26 -15
  84. package/dist/esm/dialogs/CnAccessPurposeDialog.vue3.js.map +1 -1
  85. package/dist/esm/l10n/en.json.js +3 -1
  86. package/dist/esm/l10n/en.json.js.map +1 -1
  87. package/dist/esm/l10n/nl.json.js +3 -1
  88. package/dist/esm/l10n/nl.json.js.map +1 -1
  89. package/dist/esm/library-style.js +1 -1
  90. package/dist/esm/nextcloud-vue.css +785 -518
  91. package/dist/esm/utils/builtInFormatters.js +53 -1
  92. package/dist/esm/utils/builtInFormatters.js.map +1 -1
  93. package/dist/esm/utils/validateManifestV2.compiled.js +3 -3
  94. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  95. package/dist/nextcloud-vue.cjs.js +2688 -2154
  96. package/dist/nextcloud-vue.cjs.js.map +2 -2
  97. package/dist/nextcloud-vue.css +785 -518
  98. package/l10n/en.json +3 -1
  99. package/l10n/nl.json +3 -1
  100. package/package.json +1 -1
  101. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +24 -7
  102. package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +13 -1
  103. package/src/components/CnChecklistRunWidget/CnChecklistRunWidget.vue +29 -2
  104. package/src/components/CnDataTable/CnDataTable.vue +34 -1
  105. package/src/components/CnDetailPage/CnDetailPage.md +1 -1
  106. package/src/components/CnDetailPage/CnDetailPage.vue +73 -10
  107. package/src/components/CnDetailWidgetHost/CnDetailWidgetHeaderItems.vue +6 -1
  108. package/src/components/CnDeviceFramesWidget/CnDeviceFramesWidget.vue +1 -0
  109. package/src/components/CnDuplicateWarning/CnDuplicateWarning.vue +74 -10
  110. package/src/components/CnFactsWidget/CnFactsWidget.vue +41 -4
  111. package/src/components/CnFieldListWidget/CnFieldListWidget.vue +131 -3
  112. package/src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue +103 -5
  113. package/src/components/CnFollowingWidgetHost/CnFollowingWidgetHost.vue +3 -1
  114. package/src/components/CnNotesCard/CnNotesCard.vue +10 -0
  115. package/src/components/CnObjectCard/CnObjectCard.vue +16 -0
  116. package/src/components/CnObjectDataWidget/CnObjectDataWidget.md +1 -1
  117. package/src/components/CnObjectDataWidget/CnObjectDataWidget.vue +8 -0
  118. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +1 -1
  119. package/src/components/CnRecordListWidget/CnRecordListWidget.vue +19 -19
  120. package/src/components/CnRegisterMapping/CnRegisterMapping.vue +4 -0
  121. package/src/components/CnStepper/CnStepper.vue +10 -2
  122. package/src/css/dialog.css +22 -2
  123. package/src/css/look-board-detail.css +52 -3
  124. package/src/css/look-board-index.css +51 -1
  125. package/src/css/look-board.css +48 -5
  126. package/src/css/table.css +5 -2
  127. package/src/dialogs/CnAccessPurposeDialog.vue +27 -12
  128. package/src/schemas/app-manifest-v2.schema.json +4 -2
  129. package/src/utils/builtInFormatters.js +52 -0
  130. package/src/utils/validateManifestV2.compiled.js +3 -3
@@ -3,9 +3,11 @@ import { NcLoadingIcon } from '@nextcloud/vue';
3
3
  import { ref, inject, computed } from 'vue';
4
4
  import { useEndpointSource } from '../../composables/useEndpointSource.js';
5
5
  import { dispatchAction } from '../../utils/actionsDispatcher.js';
6
+ import { formatBoardDate } from '../../utils/boardDate.js';
6
7
  import { resolveObjectTokenContext } from '../../utils/detailObjectContext.js';
7
8
  import { resolveHref, followLinkClick } from '../../utils/linkNavigation.js';
8
9
  import { resolveFilterValue, resolveDeepTokens } from '../../utils/resolveFilterTokens.js';
10
+ import __sfc_main from '../CnStatusBadge/CnStatusBadge.vue.js';
9
11
 
10
12
  /**
11
13
  * The OpenRegister endpoint that lists the caller's live flow runs.
@@ -94,6 +96,7 @@ var script = {
94
96
  name: 'CnFlowRunsWidget',
95
97
 
96
98
  components: {
99
+ CnStatusBadge: __sfc_main,
97
100
  NcLoadingIcon,
98
101
  },
99
102
 
@@ -128,6 +131,17 @@ var script = {
128
131
  * subject's finished runs render below it. Absent = today's org-wide
129
132
  * widget, unchanged.
130
133
  * - `emptyText` — override for the "nothing running" line.
134
+ * - `quietLineWithHistory` — `false` leaves out the "nothing running"
135
+ * line while the subject has finished runs to list.
136
+ * - `historyTitle` — `false` leaves out the "Earlier runs" heading.
137
+ * - `statusPill` — `true` shows the status as a pill on each row
138
+ * (no dot, and the meta line leaves the status out), rows ruled.
139
+ * - `statusLabels` — words per status (`{ completed: 'Succeeded' }`),
140
+ * translated, over the built-in ones.
141
+ * - `triggerLabels` — the meta line per trigger in words
142
+ * (`{ 'object.created': 'Started when the case was created' }`), translated.
143
+ * - `age` — `'datetime'` shows when the run started ("3 okt, 14:32")
144
+ * instead of how long ago ("13d").
131
145
  * - `headerAction` — an action descriptor drawn in the card header
132
146
  * (`{ label, icon?, ...action }`, "Flow uitvoeren"), reported through
133
147
  * the `header` event and dispatched with the page's dispatcher; its
@@ -318,6 +332,11 @@ var script = {
318
332
  return this.tr('+{count} more').replace('{count}', String(this.hiddenCount))
319
333
  },
320
334
 
335
+ /** Whether each row shows its status as a pill (`content.statusPill`). */
336
+ pills() {
337
+ return this.content.statusPill === true
338
+ },
339
+
321
340
  /** The nothing-running line. */
322
341
  emptyLabel() {
323
342
  const override = this.content.emptyText;
@@ -575,10 +594,29 @@ var script = {
575
594
  * @return {string} The label.
576
595
  */
577
596
  statusLabel(status) {
578
- const key = STATUS_LABELS[status];
597
+ const own = this.content.statusLabels && this.content.statusLabels[status];
598
+ const key = (typeof own === 'string' && own !== '') ? own : STATUS_LABELS[status];
579
599
  return key ? this.tr(key) : String(status || '')
580
600
  },
581
601
 
602
+ /**
603
+ * The pill tone of a status: finished well is success, failed is error,
604
+ * anything still going is info.
605
+ *
606
+ * @param {string} status The run status.
607
+ * @return {string} A CnStatusBadge variant.
608
+ * @spec openspec/changes/flow-runs-ruled-with-pills/specs/cn-flow-runs-widget/spec.md
609
+ */
610
+ statusVariant(status) {
611
+ if (status === 'completed') {
612
+ return 'success'
613
+ }
614
+ if (status === 'failed' || status === 'dead_letter') {
615
+ return 'error'
616
+ }
617
+ return status === 'stopped' ? 'default' : 'info'
618
+ },
619
+
582
620
  /**
583
621
  * The secondary line: status, the step the run sits on, and what
584
622
  * triggered it — whichever of those the run actually carries.
@@ -587,7 +625,11 @@ var script = {
587
625
  * @return {string} The meta line.
588
626
  */
589
627
  metaLine(run) {
590
- const parts = [this.statusLabel(run.status)];
628
+ const words = this.content.triggerLabels && this.content.triggerLabels[run.trigger];
629
+ if (typeof words === 'string' && words !== '') {
630
+ return this.tr(words)
631
+ }
632
+ const parts = this.pills ? [] : [this.statusLabel(run.status)];
591
633
  if (run.step) {
592
634
  parts.push(String(run.step));
593
635
  }
@@ -611,6 +653,11 @@ var script = {
611
653
  if (Number.isFinite(started) === false) {
612
654
  return ''
613
655
  }
656
+ if (this.content.age === 'datetime') {
657
+ const at = new Date(started);
658
+ const pad = (value) => String(value).padStart(2, '0');
659
+ return `${formatBoardDate(at)}, ${pad(at.getHours())}:${pad(at.getMinutes())}`
660
+ }
614
661
  const seconds = Math.max(0, Math.round((Date.now() - started) / 1000));
615
662
  if (seconds < 60) {
616
663
  return this.tr('now')
@@ -1 +1 @@
1
- {"version":3,"file":"CnFlowRunsWidget.vue2.js","sources":["../../../../src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-flow-runs-widget\">\n\t\t<!-- One quiet line on failure, never a leaked axios status string\n\t\t (ADR-062). The real error goes to the console. -->\n\t\t<p v-if=\"error\" class=\"cn-flow-runs-widget__error\">\n\t\t\t{{ tr('Could not load the running flows') }}\n\t\t</p>\n\t\t<!-- A configured-but-unresolved subject token also shows the loading\n\t\t state: \"no runs\" would be a claim about a case the widget has not\n\t\t identified yet. -->\n\t\t<div v-else-if=\"(loading || subjectPending) && rows.length === 0\" class=\"cn-flow-runs-widget__loading\">\n\t\t\t<NcLoadingIcon :size=\"24\" />\n\t\t</div>\n\t\t<!-- A subject where nothing EVER ran gets its own line: distinct from\n\t\t a case that is merely quiet right now. -->\n\t\t<p v-else-if=\"neverRan\" class=\"cn-flow-runs-widget__empty\">\n\t\t\t{{ tr('No flows have run yet') }}\n\t\t</p>\n\t\t<!-- Nothing running is the NORMAL state for this widget, not an\n\t\t error and not a void: one muted line, no illustration. -->\n\t\t<p v-else-if=\"rows.length === 0 && showHistory === false\" class=\"cn-flow-runs-widget__empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<template v-else>\n\t\t\t<p v-if=\"rows.length === 0\" class=\"cn-flow-runs-widget__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\t\t\t<ul v-else class=\"cn-flow-runs-widget__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"(run, index) in rows\"\n\t\t\t\t\t:key=\"run.uuid || `row-${index}`\"\n\t\t\t\t\tclass=\"cn-flow-runs-widget__row\"\n\t\t\t\t\t:class=\"{ 'cn-flow-runs-widget__row--linked': isLinked }\"\n\t\t\t\t\t:data-status=\"run.status\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"runHref(run) ? 'a' : 'div'\"\n\t\t\t\t\t\tclass=\"cn-flow-runs-widget__row-content\"\n\t\t\t\t\t\t:href=\"runHref(run) || undefined\"\n\t\t\t\t\t\t@click=\"onRowClick($event, run)\">\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclass=\"cn-flow-runs-widget__dot\"\n\t\t\t\t\t\t\t:class=\"`cn-flow-runs-widget__dot--${run.status}`\"\n\t\t\t\t\t\t\t:title=\"statusLabel(run.status)\" />\n\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__body\">\n\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__name\">{{ run.flowName }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__meta\">{{ metaLine(run) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__age\">{{ ageLabel(run) }}</span>\n\t\t\t\t\t</component>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<!-- The remainder is a count, never a scrollbar: the widget shows\n\t\t\t what fits its cell and states the honest total (ADR-062). -->\n\t\t\t<p v-if=\"hiddenCount > 0\" class=\"cn-flow-runs-widget__more\">\n\t\t\t\t{{ moreLabel }}\n\t\t\t</p>\n\t\t\t<!-- The subject's run history. Terminal rows sit under their own\n\t\t\t labelled section with a hollow dot and a muted name, so live\n\t\t\t and finished never rely on colour alone to tell apart. -->\n\t\t\t<template v-if=\"showHistory\">\n\t\t\t\t<p class=\"cn-flow-runs-widget__history-title\">\n\t\t\t\t\t{{ tr('Earlier runs') }}\n\t\t\t\t</p>\n\t\t\t\t<p v-if=\"completedError\" class=\"cn-flow-runs-widget__error\">\n\t\t\t\t\t{{ tr('Could not load the run history') }}\n\t\t\t\t</p>\n\t\t\t\t<ul v-else class=\"cn-flow-runs-widget__list\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"(run, index) in completedRows\"\n\t\t\t\t\t\t:key=\"run.uuid || `completed-${index}`\"\n\t\t\t\t\t\tclass=\"cn-flow-runs-widget__row cn-flow-runs-widget__row--terminal\"\n\t\t\t\t\t\t:class=\"{ 'cn-flow-runs-widget__row--linked': isLinked }\"\n\t\t\t\t\t\t:data-status=\"run.status\">\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"runHref(run) ? 'a' : 'div'\"\n\t\t\t\t\t\t\tclass=\"cn-flow-runs-widget__row-content\"\n\t\t\t\t\t\t\t:href=\"runHref(run) || undefined\"\n\t\t\t\t\t\t\t@click=\"onRowClick($event, run)\">\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tclass=\"cn-flow-runs-widget__dot cn-flow-runs-widget__dot--terminal\"\n\t\t\t\t\t\t\t\t:class=\"`cn-flow-runs-widget__dot--${run.status}`\"\n\t\t\t\t\t\t\t\t:title=\"statusLabel(run.status)\" />\n\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__body\">\n\t\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__name\">{{ run.flowName }}</span>\n\t\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__meta\">{{ metaLine(run) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__age\">{{ ageLabel(run) }}</span>\n\t\t\t\t\t\t</component>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<p v-if=\"completedError === '' && completedHiddenCount > 0\" class=\"cn-flow-runs-widget__more\">\n\t\t\t\t\t{{ completedMoreLabel }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { computed, inject, ref } from 'vue'\nimport { useEndpointSource } from '../../composables/useEndpointSource.js'\nimport { dispatchAction } from '../../utils/actionsDispatcher.js'\nimport { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'\nimport { followLinkClick, resolveHref } from '../../utils/linkNavigation.js'\nimport { resolveDeepTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js'\n\n/**\n * The OpenRegister endpoint that lists the caller's live flow runs.\n *\n * Every Conduction app runs its flows on OpenRegister's ONE flow engine\n * (ADR-065), so \"what is running right now\" has a single answer for the whole\n * instance and this widget can be app-agnostic: an app places it and gets its\n * users' live runs without shipping a controller, a store or a view.\n *\n * @type {string}\n */\nconst ACTIVE_RUNS_URL = '/apps/openregister/api/flow-runs/active'\n\n/**\n * The OpenRegister endpoint that lists the finished runs for ONE subject\n * object. Subject-required by contract (openregister change\n * `flow-runs-subject-scope`): there is no org-wide \"all finished runs\" here,\n * so the widget only ever calls it with a resolved subject uuid.\n *\n * @type {string}\n */\nconst COMPLETED_RUNS_URL = '/apps/openregister/api/flow-runs/completed'\n\n/**\n * Statuses, in the order a person reads them: what is executing, what is\n * queued behind it, what is parked waiting on a timer or a child run, and\n * then the terminal set a subject's run history renders.\n *\n * @type {Record<string, string>}\n */\nconst STATUS_LABELS = {\n\trunning: 'Running',\n\tqueued: 'Queued',\n\tsuspended: 'Waiting',\n\tcompleted: 'Completed',\n\tstopped: 'Stopped',\n\tfailed: 'Failed',\n\tdead_letter: 'Failed after retries',\n}\n\n/**\n * The terminal statuses (FlowRun::TERMINAL on the OpenRegister side). Rows\n * with one of these are HISTORY: rendered in the earlier-runs section with a\n * hollow dot and a muted name, never mixed into the live list.\n *\n * @type {string[]}\n */\nconst TERMINAL_STATUSES = ['completed', 'stopped', 'failed', 'dead_letter']\n\n/**\n * CnFlowRunsWidget — the live flow runs for the viewer's organisation.\n *\n * Reads OpenRegister's `flow-runs/active` surface (non-terminal runs, scoped\n * server-side to the caller's organisation) and renders one row per run: its\n * flow's NAME, what triggered it, the step it currently sits on, and how long\n * it has been going. Placed by its registry type key `flow-runs`, so any app\n * gets the widget from a single manifest placement:\n *\n * ```js\n * { id: 'running-flows', type: 'flow-runs', title: 'Running flows',\n * content: { limit: 6, pollSeconds: 15, rowRoute: 'GraphDetail' } }\n * ```\n *\n * Why it polls: a run is a moving thing. A widget titled \"running flows\" that\n * only reflects the moment the dashboard mounted would be wrong within\n * seconds and would look identical to being right — so it refetches on an\n * interval, and stops while the tab is hidden so an idle dashboard is not a\n * background request loop.\n *\n * Statuses shown are ALL the non-terminal ones (queued / running / suspended),\n * because filtering to literally `running` would show an empty widget almost\n * always: a run holds that status only during a worker pass, while queued and\n * suspended are where live runs actually wait. See FlowRun::ACTIVE.\n *\n * Subject mode: a `content.subject` (a subject object uuid, or the\n * `@objectId` / `@object.<field>` token a detail placement authors) narrows\n * the live list to one case AND adds that case's finished runs below it, so\n * a flow that completed does not look like nothing ever happened. Tokens\n * resolve against the detail surface's injected object context, the same\n * route CnStatWidget and CnChartWidget take.\n *\n * @spec openspec/changes/cn-flow-runs-widget/specs/cn-flow-runs-widget/spec.md\n * @spec openspec/changes/cn-flow-runs-widget-subject/specs/cn-flow-runs-widget-subject/spec.md\n */\nexport default {\n\tname: 'CnFlowRunsWidget',\n\n\tcomponents: {\n\t\tNcLoadingIcon,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Host translate function, provided by CnAppRoot (identity by default)\n\t\t * so a library string localises through the consuming app's l10n.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's action dispatcher (CnPageRenderer), for `headerAction`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's persisted configuration blob.\n\t\t *\n\t\t * - `limit` — rows to request AND show (1–50, default 6). The total is\n\t\t * always reported honestly regardless of this cap.\n\t\t * - `pollSeconds` — refetch interval (default 15; `0` disables polling).\n\t\t * - `rowRoute` — vue-router route NAME to open on a row click, receiving\n\t\t * the run's flow id as `:id` and the clicked run's uuid as `?run=`, so\n\t\t * the flow opens with that run inspected rather than merely open.\n\t\t * Omitted = rows are not clickable, which is correct for an app that\n\t\t * has no flow-detail page.\n\t\t * - `runRoute` — vue-router route NAME to open on a row click, receiving\n\t\t * the RUN's uuid as `:id`. Takes precedence over `rowRoute`; a row\n\t\t * without a run uuid falls back to the `rowRoute` flow-id behaviour.\n\t\t * - `subject` — a subject object uuid, or an object-context token\n\t\t * (`@objectId`, `@object.<field>`) a detail placement authors. When\n\t\t * set, the live list is filtered to that subject server-side and the\n\t\t * subject's finished runs render below it. Absent = today's org-wide\n\t\t * widget, unchanged.\n\t\t * - `emptyText` — override for the \"nothing running\" line.\n\t\t * - `headerAction` — an action descriptor drawn in the card header\n\t\t * (`{ label, icon?, ...action }`, \"Flow uitvoeren\"), reported through\n\t\t * the `header` event and dispatched with the page's dispatcher; its\n\t\t * tokens resolve against the record. The runs are read again after it.\n\t\t *\n\t\t * @type {{limit?: number, pollSeconds?: number, rowRoute?: string, runRoute?: string, subject?: string, emptyText?: string, title?: string}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Widget placement id, so the per-widget Refresh action\n\t\t * (`cn:widget:refresh`) reaches this instance's fetch.\n\t\t */\n\t\twidgetId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Translate function. Falls back to the injected `cnTranslate`.\n\t\t * Provide explicitly when mounting outside a CnAppRoot ancestor.\n\t\t *\n\t\t * @type {((key: string) => string)|null}\n\t\t */\n\t\ttranslate: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['header'],\n\n\tsetup(props) {\n\t\t// The shared endpoint engine owns request dedup, the short-TTL cache\n\t\t// and the cn:page:refresh / cn:widget:refresh subscriptions — the same\n\t\t// binding CnStatWidget's endpoint mode uses, so a page-level Refresh\n\t\t// updates this widget with everything else on the page.\n\t\tconst widgetIdRef = ref(props.widgetId)\n\n\t\t// The detail surface's object context, injected the same way the other\n\t\t// endpoint-bound widgets (stat / chart / audit-trail) receive it, so a\n\t\t// `subject: '@objectId'` placement binds the CURRENT object without the\n\t\t// manifest hardcoding a uuid. Null on plain dashboards — the token then\n\t\t// stays unresolved and the endpoint engine's `blocked` semantics hold\n\t\t// the fetch instead of sending a literal `@objectId` to the server.\n\t\tconst objectCtxRaw = inject('cnObjectContext', null)\n\t\tconst detailCtxRaw = inject('cnDetailObjectContext', null)\n\t\tconst tokenCtx = () => ({\n\t\t\tworkspace: {},\n\t\t\tconfig: {},\n\t\t\t...(resolveObjectTokenContext(objectCtxRaw, detailCtxRaw) || {}),\n\t\t})\n\n\t\tconst configuredSubject = () => {\n\t\t\tconst subject = props.content && props.content.subject\n\t\t\treturn (typeof subject === 'string' && subject !== '') ? subject : ''\n\t\t}\n\n\t\t/**\n\t\t * The subject uuid after token resolution: `''` when no subject is\n\t\t * configured, `null` while a token still waits on the object context,\n\t\t * else the concrete uuid.\n\t\t */\n\t\tconst resolvedSubject = computed(() => {\n\t\t\tconst subject = configuredSubject()\n\t\t\tif (subject === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst value = resolveFilterValue(subject, tokenCtx())\n\t\t\tif (typeof value === 'string' && value.charAt(0) === '@') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (value === undefined || value === null) ? null : String(value)\n\t\t})\n\n\t\tconst source = () => {\n\t\t\tconst params = { limit: normaliseLimit(props.content && props.content.limit) }\n\t\t\tconst subject = configuredSubject()\n\t\t\tif (subject !== '') {\n\t\t\t\tparams.subject = subject\n\t\t\t}\n\t\t\treturn { url: ACTIVE_RUNS_URL, method: 'GET', params }\n\t\t}\n\t\tconst { data, loading, error, refetch } = useEndpointSource(source, {\n\t\t\twidgetId: widgetIdRef,\n\t\t\tctx: tokenCtx,\n\t\t})\n\n\t\t// The history half of the subject view. A null config (no subject)\n\t\t// means the composable never queries: the org-wide widget stays a\n\t\t// single-request surface, bit-identical to before.\n\t\tconst completedSource = () => {\n\t\t\tconst subject = configuredSubject()\n\t\t\tif (subject === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn {\n\t\t\t\turl: COMPLETED_RUNS_URL,\n\t\t\t\tmethod: 'GET',\n\t\t\t\tparams: { subject, limit: normaliseLimit(props.content && props.content.limit) },\n\t\t\t}\n\t\t}\n\t\tconst {\n\t\t\tdata: completedData,\n\t\t\tloading: completedLoading,\n\t\t\terror: completedError,\n\t\t\trefetch: refetchCompleted,\n\t\t} = useEndpointSource(completedSource, {\n\t\t\twidgetId: widgetIdRef,\n\t\t\tctx: tokenCtx,\n\t\t})\n\n\t\t// `inject` is re-read in setup so Vue 2.7 and Vue 3 resolve it\n\t\t// identically to the Options `inject` block (CnStatWidget precedent).\n\t\tconst injectedTranslate = inject('cnTranslate', null)\n\n\t\treturn {\n\t\t\tpayload: data,\n\t\t\tloading,\n\t\t\terror,\n\t\t\trefetch,\n\t\t\tcompletedPayload: completedData,\n\t\t\tcompletedLoading,\n\t\t\tcompletedError,\n\t\t\trefetchCompleted,\n\t\t\tresolvedSubject,\n\t\t\tinjectedTranslate,\n\t\t\ttokenCtx,\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpollTimer: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Effective translate function: the explicit prop, then the injected\n\t\t * host one, then `@nextcloud/l10n` under the library's own app id.\n\t\t *\n\t\t * @return {(key: string) => string}\n\t\t */\n\t\ttr() {\n\t\t\tconst fn = this.translate ?? this.injectedTranslate ?? this.cnTranslate\n\t\t\tif (typeof fn === 'function') {\n\t\t\t\treturn (key) => fn(key)\n\t\t\t}\n\t\t\treturn (key) => t('nextcloud-vue', key)\n\t\t},\n\n\t\t/**\n\t\t * The rows to render — the endpoint's bounded page, defensively\n\t\t * re-capped so a wider server default can never overflow the cell.\n\t\t *\n\t\t * @return {Array<object>} The run rows.\n\t\t */\n\t\trows() {\n\t\t\tconst results = (this.payload && this.payload.results) || []\n\t\t\tif (Array.isArray(results) === false) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn results.slice(0, normaliseLimit(this.content.limit))\n\t\t},\n\n\t\t/**\n\t\t * How many live runs exist beyond the rendered rows.\n\t\t *\n\t\t * Read off the server's `total`, NOT the array length — the point of\n\t\t * the total is to be honest about what the cell could not fit.\n\t\t *\n\t\t * @return {number} The hidden run count (never negative).\n\t\t */\n\t\thiddenCount() {\n\t\t\tconst total = Number((this.payload && this.payload.total) ?? this.rows.length)\n\t\t\tif (Number.isFinite(total) === false) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.max(0, total - this.rows.length)\n\t\t},\n\n\t\t/** The \"+N more\" line. */\n\t\tmoreLabel() {\n\t\t\treturn this.tr('+{count} more').replace('{count}', String(this.hiddenCount))\n\t\t},\n\n\t\t/** The nothing-running line. */\n\t\temptyLabel() {\n\t\t\tconst override = this.content.emptyText\n\t\t\tif (typeof override === 'string' && override !== '') {\n\t\t\t\treturn this.tr(override)\n\t\t\t}\n\t\t\treturn this.tr('No flows are running')\n\t\t},\n\n\t\t/** Whether this placement is scoped to one subject object. */\n\t\thasSubject() {\n\t\t\treturn typeof this.content.subject === 'string' && this.content.subject !== ''\n\t\t},\n\n\t\t/**\n\t\t * Whether a configured subject token still waits on the object\n\t\t * context. The widget shows its loading state instead of an empty\n\t\t * line then: \"no runs\" would be a claim about a case it has not\n\t\t * identified yet.\n\t\t *\n\t\t * @return {boolean} True while the subject is configured but unresolved.\n\t\t */\n\t\tsubjectPending() {\n\t\t\treturn this.hasSubject && this.resolvedSubject === null\n\t\t},\n\n\t\t/**\n\t\t * The subject's finished runs — the completed-runs read's bounded\n\t\t * page, re-capped like the live rows.\n\t\t *\n\t\t * @return {Array<object>} The terminal run rows (empty without a subject).\n\t\t */\n\t\tcompletedRows() {\n\t\t\tif (this.hasSubject === false) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst results = (this.completedPayload && this.completedPayload.results) || []\n\t\t\tif (Array.isArray(results) === false) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn results.slice(0, normaliseLimit(this.content.limit))\n\t\t},\n\n\t\t/**\n\t\t * How many finished runs exist beyond the rendered history rows, read\n\t\t * off the completed read's honest total.\n\t\t *\n\t\t * @return {number} The hidden finished-run count (never negative).\n\t\t */\n\t\tcompletedHiddenCount() {\n\t\t\tconst total = Number((this.completedPayload && this.completedPayload.total) ?? this.completedRows.length)\n\t\t\tif (Number.isFinite(total) === false) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.max(0, total - this.completedRows.length)\n\t\t},\n\n\t\t/** The \"+N earlier\" line under the history section. */\n\t\tcompletedMoreLabel() {\n\t\t\treturn this.tr('+{count} earlier').replace('{count}', String(this.completedHiddenCount))\n\t\t},\n\n\t\t/**\n\t\t * Whether this subject has NO runs at all, live or finished. Rendered\n\t\t * as its own line: a case where nothing ever ran reads differently\n\t\t * from a case that is merely quiet right now.\n\t\t *\n\t\t * @return {boolean} True when both reads settled empty for a subject.\n\t\t */\n\t\tneverRan() {\n\t\t\treturn this.hasSubject\n\t\t\t\t&& this.subjectPending === false\n\t\t\t\t&& this.loading === false\n\t\t\t\t&& this.completedLoading === false\n\t\t\t\t&& this.completedError === ''\n\t\t\t\t&& this.rows.length === 0\n\t\t\t\t&& this.completedRows.length === 0\n\t\t},\n\n\t\t/** Whether the history section renders (rows or a failed history read). */\n\t\tshowHistory() {\n\t\t\treturn this.hasSubject\n\t\t\t\t&& this.subjectPending === false\n\t\t\t\t&& (this.completedRows.length > 0 || this.completedError !== '')\n\t\t},\n\n\t\t/** Whether a row click navigates (a `runRoute` or `rowRoute` is configured). */\n\t\tisLinked() {\n\t\t\treturn (typeof this.content.rowRoute === 'string' && this.content.rowRoute !== '')\n\t\t\t\t|| (typeof this.content.runRoute === 'string' && this.content.runRoute !== '')\n\t\t},\n\n\t\t/**\n\t\t * Poll interval in ms, or 0 when polling is off.\n\t\t *\n\t\t * Floored at 5s so a mis-authored `pollSeconds: 0.1` cannot turn a\n\t\t * dashboard into a request storm; `0` remains an explicit opt-out.\n\t\t *\n\t\t * @return {number} The interval in milliseconds.\n\t\t */\n\t\tpollMs() {\n\t\t\tconst raw = this.content.pollSeconds\n\t\t\tconst seconds = (raw === undefined || raw === null) ? 15 : Number(raw)\n\t\t\tif (Number.isFinite(seconds) === false || seconds <= 0) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.max(5, seconds) * 1000\n\t\t},\n\t},\n\n\twatch: {\n\t\t'content.headerAction': {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.emitHeader()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.emitHeader()\n\t\tthis.startPolling()\n\t\tdocument.addEventListener('visibilitychange', this.onVisibilityChange)\n\t},\n\n\tbeforeUnmount() {\n\t\tthis.teardown()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Tell the card around the runs what its header shows: the header\n\t\t * action, if any.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\temitHeader() {\n\t\t\tconst action = this.content && this.content.headerAction\n\t\t\tconst usable = action && typeof action === 'object' && typeof action.label === 'string' && action.label !== ''\n\t\t\t/**\n\t\t\t * @event header The card header's parts: `{ link, note, action, pill }`, `action` being `{ label, icon, run }` or null.\n\t\t\t */\n\t\t\tthis.$emit('header', {\n\t\t\t\tlink: null,\n\t\t\t\tnote: '',\n\t\t\t\taction: usable ? { label: this.tr(action.label), icon: action.icon || '', run: () => this.runHeaderAction() } : null,\n\t\t\t\tpill: null,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Run the header action with the record's tokens resolved, then read the\n\t\t * runs again so a started run shows.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync runHeaderAction() {\n\t\t\tconst { label, icon, ...action } = resolveDeepTokens(this.content.headerAction, this.tokenCtx())\n\t\t\ttry {\n\t\t\t\tconst outcome = await (typeof this.cnDispatchAction === 'function'\n\t\t\t\t\t? this.cnDispatchAction(action)\n\t\t\t\t\t: dispatchAction(action, { router: this.$router || null }))\n\t\t\t\tif (outcome === false) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.refetchAll()\n\t\t},\n\n\t\t/**\n\t\t * Start (or restart) the refetch interval, unless polling is disabled.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tstartPolling() {\n\t\t\tthis.stopPolling()\n\t\t\tif (this.pollMs === 0 || document.hidden === true) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.pollTimer = setInterval(() => {\n\t\t\t\tthis.refetchAll()\n\t\t\t}, this.pollMs)\n\t\t},\n\n\t\t/**\n\t\t * Refetch the live read, and the history read when a subject is\n\t\t * configured — a run that finishes between polls must MOVE to the\n\t\t * history section, not vanish from the widget.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\trefetchAll() {\n\t\t\tthis.refetch(true)\n\t\t\tif (this.hasSubject) {\n\t\t\t\tthis.refetchCompleted(true)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Clear the refetch interval.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tstopPolling() {\n\t\t\tif (this.pollTimer !== null) {\n\t\t\t\tclearInterval(this.pollTimer)\n\t\t\t\tthis.pollTimer = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Remove the timer and the visibility listener.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tteardown() {\n\t\t\tthis.stopPolling()\n\t\t\tdocument.removeEventListener('visibilitychange', this.onVisibilityChange)\n\t\t},\n\n\t\t/**\n\t\t * Pause polling while the tab is hidden; refetch once and resume when\n\t\t * it comes back, so returning to the dashboard shows current state\n\t\t * rather than whatever was true when the tab was backgrounded.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonVisibilityChange() {\n\t\t\tif (document.hidden === true) {\n\t\t\t\tthis.stopPolling()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.refetchAll()\n\t\t\tthis.startPolling()\n\t\t},\n\n\t\t/**\n\t\t * Whether a run's status is terminal — the history half of the\n\t\t * subject view. Drives the hollow-dot / muted-name row treatment.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {boolean} True for a finished run.\n\t\t */\n\t\tisTerminal(run) {\n\t\t\treturn TERMINAL_STATUSES.includes(run && run.status)\n\t\t},\n\n\t\t/**\n\t\t * The human label for a status, falling back to the raw value so an\n\t\t * engine that gains a status still renders something truthful.\n\t\t *\n\t\t * @param {string} status The run status.\n\t\t * @return {string} The label.\n\t\t */\n\t\tstatusLabel(status) {\n\t\t\tconst key = STATUS_LABELS[status]\n\t\t\treturn key ? this.tr(key) : String(status || '')\n\t\t},\n\n\t\t/**\n\t\t * The secondary line: status, the step the run sits on, and what\n\t\t * triggered it — whichever of those the run actually carries.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {string} The meta line.\n\t\t */\n\t\tmetaLine(run) {\n\t\t\tconst parts = [this.statusLabel(run.status)]\n\t\t\tif (run.step) {\n\t\t\t\tparts.push(String(run.step))\n\t\t\t}\n\t\t\tif (run.trigger) {\n\t\t\t\tparts.push(String(run.trigger))\n\t\t\t}\n\t\t\treturn parts.join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * How long the run has been going, as a coarse relative label.\n\t\t *\n\t\t * Coarse on purpose: a dashboard reader wants \"8m\", not a timestamp,\n\t\t * and a second-precision label on a 15s poll would read as stale.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {string} The age label, or '' when the run has no start time.\n\t\t */\n\t\tageLabel(run) {\n\t\t\tconst started = Date.parse(run.created || '')\n\t\t\tif (Number.isFinite(started) === false) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst seconds = Math.max(0, Math.round((Date.now() - started) / 1000))\n\t\t\tif (seconds < 60) {\n\t\t\t\treturn this.tr('now')\n\t\t\t}\n\t\t\tconst minutes = Math.round(seconds / 60)\n\t\t\tif (minutes < 60) {\n\t\t\t\treturn `${minutes}m`\n\t\t\t}\n\t\t\tconst hours = Math.round(minutes / 60)\n\t\t\tif (hours < 24) {\n\t\t\t\treturn `${hours}h`\n\t\t\t}\n\t\t\treturn `${Math.round(hours / 24)}d`\n\t\t},\n\n\t\t/**\n\t\t * The route a run row links to, or null when it links nowhere.\n\t\t *\n\t\t * `runRoute` wins when the row carries a run uuid: on a case page a\n\t\t * click means \"show me THIS run\", and the run uuid is the deep link\n\t\t * the row contract carries. Without a `runRoute` (or on a row with no\n\t\t * uuid) `rowRoute` receives the FLOW id, the surface every\n\t\t * flow-authoring app has.\n\t\t *\n\t\t * The flow id alone answers the wrong question, so the run travels as\n\t\t * `?run=`, the address CnFlowDetail documents its `run` prop as\n\t\t * reading: a `rowRoute` click and a pasted run link open the same\n\t\t * screen.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {object|null} A vue-router location, or null.\n\t\t */\n\t\trunTarget(run) {\n\t\t\tif (this.isLinked === false || !this.$router) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst hasUuid = run.uuid !== undefined && run.uuid !== null && run.uuid !== ''\n\t\t\tconst runRoute = this.content.runRoute\n\t\t\tif (typeof runRoute === 'string' && runRoute !== '' && hasUuid) {\n\t\t\t\treturn { name: runRoute, params: { id: String(run.uuid) } }\n\t\t\t}\n\t\t\tif (typeof this.content.rowRoute !== 'string' || this.content.rowRoute === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst id = run.flowId\n\t\t\tif (id === undefined || id === null || id === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst target = { name: this.content.rowRoute, params: { id: String(id) } }\n\t\t\t// An empty `?run=` is not a deep link; CnFlowDetail's `run` prop\n\t\t\t// defaults to '' so \"no run named\" stays one value.\n\t\t\tif (hasUuid) {\n\t\t\t\ttarget.query = { run: String(run.uuid) }\n\t\t\t}\n\t\t\treturn target\n\t\t},\n\n\t\t/**\n\t\t * The href of a run row's link, or '' when the row links nowhere.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {string} The resolved href.\n\t\t */\n\t\trunHref(run) {\n\t\t\treturn resolveHref(this.runTarget(run), this.$router)\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on a run row's link in-app; modified clicks\n\t\t * are left to the browser.\n\t\t *\n\t\t * @param {MouseEvent} event The click event.\n\t\t * @param {object} run The clicked run row.\n\t\t * @return {void}\n\t\t */\n\t\tonRowClick(event, run) {\n\t\t\tfollowLinkClick(event, this.runTarget(run), this.$router)\n\t\t},\n\t},\n}\n\n/**\n * Clamp a configured row limit into the range the endpoint accepts.\n *\n * @param {number|string|undefined} raw The configured limit.\n * @return {number} A limit between 1 and 50 (default 6).\n */\nfunction normaliseLimit(raw) {\n\tconst n = Number(raw)\n\tif (Number.isFinite(n) === false || n <= 0) {\n\t\treturn 6\n\t}\n\treturn Math.min(50, Math.round(n))\n}\n</script>\n\n<style scoped>\n.cn-flow-runs-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-flow-runs-widget__loading {\n\tdisplay: flex;\n\tjustify-content: center;\n\tpadding: 8px 0;\n}\n\n.cn-flow-runs-widget__empty,\n.cn-flow-runs-widget__error,\n.cn-flow-runs-widget__more {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-flow-runs-widget__more {\n\tpadding-top: 4px;\n}\n\n.cn-flow-runs-widget__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tmin-width: 0;\n}\n\n.cn-flow-runs-widget__row {\n\tborder-bottom: 1px solid var(--color-border);\n\tmin-width: 0;\n}\n\n.cn-flow-runs-widget__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-flow-runs-widget__row-content {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tpadding: 6px 0;\n\tmin-width: 0;\n\tcolor: inherit;\n\ttext-decoration: none;\n}\n\na.cn-flow-runs-widget__row-content {\n\tcursor: pointer;\n}\n\n.cn-flow-runs-widget__dot {\n\tflex: 0 0 auto;\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground: var(--color-text-maxcontrast);\n}\n\n/* Executing now — the primary colour, and the only row that animates. */\n.cn-flow-runs-widget__dot--running {\n\tbackground: var(--color-primary-element, #0082c9);\n\tanimation: cn-flow-runs-pulse 1.6s ease-in-out infinite;\n}\n\n.cn-flow-runs-widget__dot--queued {\n\tbackground: var(--color-warning, #c28900);\n}\n\n.cn-flow-runs-widget__dot--suspended {\n\tbackground: var(--color-text-maxcontrast);\n}\n\n/* Terminal rows: the dot is a hollow RING, so live (filled) and finished\n (hollow) never differ by colour alone. The per-status colour still rides\n on the ring's border. */\n.cn-flow-runs-widget__dot--terminal {\n\twidth: 6px;\n\theight: 6px;\n\tbackground: transparent;\n\tborder: 2px solid var(--color-text-maxcontrast);\n}\n\n.cn-flow-runs-widget__dot--terminal.cn-flow-runs-widget__dot--completed {\n\tborder-color: var(--color-success, #2d7b41);\n}\n\n.cn-flow-runs-widget__dot--terminal.cn-flow-runs-widget__dot--failed,\n.cn-flow-runs-widget__dot--terminal.cn-flow-runs-widget__dot--dead_letter {\n\tborder-color: var(--color-error, #d91f2d);\n}\n\n.cn-flow-runs-widget__body {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1 1 auto;\n}\n\n.cn-flow-runs-widget__name {\n\tfont-weight: 600;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* Finished runs read as history: regular weight, muted colour. The hollow\n dot and the section label carry the distinction for anyone who cannot\n rely on colour. */\n.cn-flow-runs-widget__row--terminal .cn-flow-runs-widget__name {\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* Must sit AFTER the plain `__name` rule: the compound selector is more\n specific, and stylelint's no-descending-specificity flags the reverse\n order because the cascade then depends on specificity rather than\n source order — the shape that quietly stops working when someone adds\n a competing rule. */\na.cn-flow-runs-widget__row-content:hover .cn-flow-runs-widget__name {\n\ttext-decoration: underline;\n}\n\n.cn-flow-runs-widget__meta {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-flow-runs-widget__age {\n\tflex: 0 0 auto;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-variant-numeric: tabular-nums;\n}\n\n/* The history section label. Small caps text, not a colour: the section\n boundary must survive monochrome. */\n.cn-flow-runs-widget__history-title {\n\tmargin: 0;\n\tpadding-top: 8px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n}\n\n@keyframes cn-flow-runs-pulse {\n\t0%, 100% { opacity: 1; }\n\t50% { opacity: 0.35; }\n}\n\n/* Respect a reduced-motion preference: the pulse is decoration, and the dot\n colour already carries the status. */\n@media (prefers-reduced-motion: reduce) {\n\t.cn-flow-runs-widget__dot--running {\n\t\tanimation: none;\n\t}\n}\n</style>\n"],"names":["t"],"mappings":"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"}
1
+ {"version":3,"file":"CnFlowRunsWidget.vue2.js","sources":["../../../../src/components/CnFlowRunsWidget/CnFlowRunsWidget.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2026 Conduction B.V.\n - SPDX-License-Identifier: EUPL-1.2\n-->\n<template>\n\t<div class=\"cn-flow-runs-widget\" :class=\"{ 'cn-flow-runs-widget--pills': pills }\">\n\t\t<!-- One quiet line on failure, never a leaked axios status string\n\t\t (ADR-062). The real error goes to the console. -->\n\t\t<p v-if=\"error\" class=\"cn-flow-runs-widget__error\">\n\t\t\t{{ tr('Could not load the running flows') }}\n\t\t</p>\n\t\t<!-- A configured-but-unresolved subject token also shows the loading\n\t\t state: \"no runs\" would be a claim about a case the widget has not\n\t\t identified yet. -->\n\t\t<div v-else-if=\"(loading || subjectPending) && rows.length === 0\" class=\"cn-flow-runs-widget__loading\">\n\t\t\t<NcLoadingIcon :size=\"24\" />\n\t\t</div>\n\t\t<!-- A subject where nothing EVER ran gets its own line: distinct from\n\t\t a case that is merely quiet right now. -->\n\t\t<p v-else-if=\"neverRan\" class=\"cn-flow-runs-widget__empty\">\n\t\t\t{{ tr('No flows have run yet') }}\n\t\t</p>\n\t\t<!-- Nothing running is the NORMAL state for this widget, not an\n\t\t error and not a void: one muted line, no illustration. -->\n\t\t<p v-else-if=\"rows.length === 0 && showHistory === false\" class=\"cn-flow-runs-widget__empty\">\n\t\t\t{{ emptyLabel }}\n\t\t</p>\n\t\t<template v-else>\n\t\t\t<p v-if=\"rows.length === 0 && content.quietLineWithHistory !== false\" class=\"cn-flow-runs-widget__empty\">\n\t\t\t\t{{ emptyLabel }}\n\t\t\t</p>\n\t\t\t<ul v-else class=\"cn-flow-runs-widget__list\">\n\t\t\t\t<li\n\t\t\t\t\tv-for=\"(run, index) in rows\"\n\t\t\t\t\t:key=\"run.uuid || `row-${index}`\"\n\t\t\t\t\tclass=\"cn-flow-runs-widget__row\"\n\t\t\t\t\t:class=\"{ 'cn-flow-runs-widget__row--linked': isLinked }\"\n\t\t\t\t\t:data-status=\"run.status\">\n\t\t\t\t\t<component\n\t\t\t\t\t\t:is=\"runHref(run) ? 'a' : 'div'\"\n\t\t\t\t\t\tclass=\"cn-flow-runs-widget__row-content\"\n\t\t\t\t\t\t:href=\"runHref(run) || undefined\"\n\t\t\t\t\t\t@click=\"onRowClick($event, run)\">\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tv-if=\"!pills\"\n\t\t\t\t\t\t\tclass=\"cn-flow-runs-widget__dot\"\n\t\t\t\t\t\t\t:class=\"`cn-flow-runs-widget__dot--${run.status}`\"\n\t\t\t\t\t\t\t:title=\"statusLabel(run.status)\" />\n\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__body\">\n\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__name\">{{ run.flowName }}</span>\n\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__meta\">{{ metaLine(run) }}</span>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\tv-if=\"pills\"\n\t\t\t\t\t\t\tclass=\"cn-flow-runs-widget__pill\"\n\t\t\t\t\t\t\t:label=\"statusLabel(run.status)\"\n\t\t\t\t\t\t\t:variant=\"statusVariant(run.status)\"\n\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__age\">{{ ageLabel(run) }}</span>\n\t\t\t\t\t</component>\n\t\t\t\t</li>\n\t\t\t</ul>\n\t\t\t<!-- The remainder is a count, never a scrollbar: the widget shows\n\t\t\t what fits its cell and states the honest total (ADR-062). -->\n\t\t\t<p v-if=\"hiddenCount > 0\" class=\"cn-flow-runs-widget__more\">\n\t\t\t\t{{ moreLabel }}\n\t\t\t</p>\n\t\t\t<!-- The subject's run history. Terminal rows sit under their own\n\t\t\t labelled section with a hollow dot and a muted name, so live\n\t\t\t and finished never rely on colour alone to tell apart. -->\n\t\t\t<template v-if=\"showHistory\">\n\t\t\t\t<p v-if=\"content.historyTitle !== false\" class=\"cn-flow-runs-widget__history-title\">\n\t\t\t\t\t{{ tr('Earlier runs') }}\n\t\t\t\t</p>\n\t\t\t\t<p v-if=\"completedError\" class=\"cn-flow-runs-widget__error\">\n\t\t\t\t\t{{ tr('Could not load the run history') }}\n\t\t\t\t</p>\n\t\t\t\t<ul v-else class=\"cn-flow-runs-widget__list\">\n\t\t\t\t\t<li\n\t\t\t\t\t\tv-for=\"(run, index) in completedRows\"\n\t\t\t\t\t\t:key=\"run.uuid || `completed-${index}`\"\n\t\t\t\t\t\tclass=\"cn-flow-runs-widget__row cn-flow-runs-widget__row--terminal\"\n\t\t\t\t\t\t:class=\"{ 'cn-flow-runs-widget__row--linked': isLinked }\"\n\t\t\t\t\t\t:data-status=\"run.status\">\n\t\t\t\t\t\t<component\n\t\t\t\t\t\t\t:is=\"runHref(run) ? 'a' : 'div'\"\n\t\t\t\t\t\t\tclass=\"cn-flow-runs-widget__row-content\"\n\t\t\t\t\t\t\t:href=\"runHref(run) || undefined\"\n\t\t\t\t\t\t\t@click=\"onRowClick($event, run)\">\n\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\tv-if=\"!pills\"\n\t\t\t\t\t\t\t\tclass=\"cn-flow-runs-widget__dot cn-flow-runs-widget__dot--terminal\"\n\t\t\t\t\t\t\t\t:class=\"`cn-flow-runs-widget__dot--${run.status}`\"\n\t\t\t\t\t\t\t\t:title=\"statusLabel(run.status)\" />\n\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__body\">\n\t\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__name\">{{ run.flowName }}</span>\n\t\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__meta\">{{ metaLine(run) }}</span>\n\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t<CnStatusBadge\n\t\t\t\t\t\t\t\tv-if=\"pills\"\n\t\t\t\t\t\t\t\tclass=\"cn-flow-runs-widget__pill\"\n\t\t\t\t\t\t\t\t:label=\"statusLabel(run.status)\"\n\t\t\t\t\t\t\t\t:variant=\"statusVariant(run.status)\"\n\t\t\t\t\t\t\t\tsize=\"small\" />\n\t\t\t\t\t\t\t<span class=\"cn-flow-runs-widget__age\">{{ ageLabel(run) }}</span>\n\t\t\t\t\t\t</component>\n\t\t\t\t\t</li>\n\t\t\t\t</ul>\n\t\t\t\t<p v-if=\"completedError === '' && completedHiddenCount > 0\" class=\"cn-flow-runs-widget__more\">\n\t\t\t\t\t{{ completedMoreLabel }}\n\t\t\t\t</p>\n\t\t\t</template>\n\t\t</template>\n\t</div>\n</template>\n\n<script>\nimport { translate as t } from '@nextcloud/l10n'\nimport { NcLoadingIcon } from '@nextcloud/vue'\nimport { computed, inject, ref } from 'vue'\nimport { useEndpointSource } from '../../composables/useEndpointSource.js'\nimport { dispatchAction } from '../../utils/actionsDispatcher.js'\nimport { formatBoardDate } from '../../utils/boardDate.js'\nimport { resolveObjectTokenContext } from '../../utils/detailObjectContext.js'\nimport { followLinkClick, resolveHref } from '../../utils/linkNavigation.js'\nimport { resolveDeepTokens, resolveFilterValue } from '../../utils/resolveFilterTokens.js'\nimport { CnStatusBadge } from '../CnStatusBadge/index.js'\n\n/**\n * The OpenRegister endpoint that lists the caller's live flow runs.\n *\n * Every Conduction app runs its flows on OpenRegister's ONE flow engine\n * (ADR-065), so \"what is running right now\" has a single answer for the whole\n * instance and this widget can be app-agnostic: an app places it and gets its\n * users' live runs without shipping a controller, a store or a view.\n *\n * @type {string}\n */\nconst ACTIVE_RUNS_URL = '/apps/openregister/api/flow-runs/active'\n\n/**\n * The OpenRegister endpoint that lists the finished runs for ONE subject\n * object. Subject-required by contract (openregister change\n * `flow-runs-subject-scope`): there is no org-wide \"all finished runs\" here,\n * so the widget only ever calls it with a resolved subject uuid.\n *\n * @type {string}\n */\nconst COMPLETED_RUNS_URL = '/apps/openregister/api/flow-runs/completed'\n\n/**\n * Statuses, in the order a person reads them: what is executing, what is\n * queued behind it, what is parked waiting on a timer or a child run, and\n * then the terminal set a subject's run history renders.\n *\n * @type {Record<string, string>}\n */\nconst STATUS_LABELS = {\n\trunning: 'Running',\n\tqueued: 'Queued',\n\tsuspended: 'Waiting',\n\tcompleted: 'Completed',\n\tstopped: 'Stopped',\n\tfailed: 'Failed',\n\tdead_letter: 'Failed after retries',\n}\n\n/**\n * The terminal statuses (FlowRun::TERMINAL on the OpenRegister side). Rows\n * with one of these are HISTORY: rendered in the earlier-runs section with a\n * hollow dot and a muted name, never mixed into the live list.\n *\n * @type {string[]}\n */\nconst TERMINAL_STATUSES = ['completed', 'stopped', 'failed', 'dead_letter']\n\n/**\n * CnFlowRunsWidget — the live flow runs for the viewer's organisation.\n *\n * Reads OpenRegister's `flow-runs/active` surface (non-terminal runs, scoped\n * server-side to the caller's organisation) and renders one row per run: its\n * flow's NAME, what triggered it, the step it currently sits on, and how long\n * it has been going. Placed by its registry type key `flow-runs`, so any app\n * gets the widget from a single manifest placement:\n *\n * ```js\n * { id: 'running-flows', type: 'flow-runs', title: 'Running flows',\n * content: { limit: 6, pollSeconds: 15, rowRoute: 'GraphDetail' } }\n * ```\n *\n * Why it polls: a run is a moving thing. A widget titled \"running flows\" that\n * only reflects the moment the dashboard mounted would be wrong within\n * seconds and would look identical to being right — so it refetches on an\n * interval, and stops while the tab is hidden so an idle dashboard is not a\n * background request loop.\n *\n * Statuses shown are ALL the non-terminal ones (queued / running / suspended),\n * because filtering to literally `running` would show an empty widget almost\n * always: a run holds that status only during a worker pass, while queued and\n * suspended are where live runs actually wait. See FlowRun::ACTIVE.\n *\n * Subject mode: a `content.subject` (a subject object uuid, or the\n * `@objectId` / `@object.<field>` token a detail placement authors) narrows\n * the live list to one case AND adds that case's finished runs below it, so\n * a flow that completed does not look like nothing ever happened. Tokens\n * resolve against the detail surface's injected object context, the same\n * route CnStatWidget and CnChartWidget take.\n *\n * @spec openspec/changes/cn-flow-runs-widget/specs/cn-flow-runs-widget/spec.md\n * @spec openspec/changes/cn-flow-runs-widget-subject/specs/cn-flow-runs-widget-subject/spec.md\n */\nexport default {\n\tname: 'CnFlowRunsWidget',\n\n\tcomponents: {\n\t\tCnStatusBadge,\n\t\tNcLoadingIcon,\n\t},\n\n\tinject: {\n\t\t/**\n\t\t * Host translate function, provided by CnAppRoot (identity by default)\n\t\t * so a library string localises through the consuming app's l10n.\n\t\t */\n\t\tcnTranslate: { default: () => (key) => key },\n\t\t/** The page's action dispatcher (CnPageRenderer), for `headerAction`. */\n\t\tcnDispatchAction: { default: null },\n\t},\n\n\tprops: {\n\t\t/**\n\t\t * The widget's persisted configuration blob.\n\t\t *\n\t\t * - `limit` — rows to request AND show (1–50, default 6). The total is\n\t\t * always reported honestly regardless of this cap.\n\t\t * - `pollSeconds` — refetch interval (default 15; `0` disables polling).\n\t\t * - `rowRoute` — vue-router route NAME to open on a row click, receiving\n\t\t * the run's flow id as `:id` and the clicked run's uuid as `?run=`, so\n\t\t * the flow opens with that run inspected rather than merely open.\n\t\t * Omitted = rows are not clickable, which is correct for an app that\n\t\t * has no flow-detail page.\n\t\t * - `runRoute` — vue-router route NAME to open on a row click, receiving\n\t\t * the RUN's uuid as `:id`. Takes precedence over `rowRoute`; a row\n\t\t * without a run uuid falls back to the `rowRoute` flow-id behaviour.\n\t\t * - `subject` — a subject object uuid, or an object-context token\n\t\t * (`@objectId`, `@object.<field>`) a detail placement authors. When\n\t\t * set, the live list is filtered to that subject server-side and the\n\t\t * subject's finished runs render below it. Absent = today's org-wide\n\t\t * widget, unchanged.\n\t\t * - `emptyText` — override for the \"nothing running\" line.\n\t\t * - `quietLineWithHistory` — `false` leaves out the \"nothing running\"\n\t\t * line while the subject has finished runs to list.\n\t\t * - `historyTitle` — `false` leaves out the \"Earlier runs\" heading.\n\t\t * - `statusPill` — `true` shows the status as a pill on each row\n\t\t * (no dot, and the meta line leaves the status out), rows ruled.\n\t\t * - `statusLabels` — words per status (`{ completed: 'Succeeded' }`),\n\t\t * translated, over the built-in ones.\n\t\t * - `triggerLabels` — the meta line per trigger in words\n\t\t * (`{ 'object.created': 'Started when the case was created' }`), translated.\n\t\t * - `age` — `'datetime'` shows when the run started (\"3 okt, 14:32\")\n\t\t * instead of how long ago (\"13d\").\n\t\t * - `headerAction` — an action descriptor drawn in the card header\n\t\t * (`{ label, icon?, ...action }`, \"Flow uitvoeren\"), reported through\n\t\t * the `header` event and dispatched with the page's dispatcher; its\n\t\t * tokens resolve against the record. The runs are read again after it.\n\t\t *\n\t\t * @type {{limit?: number, pollSeconds?: number, rowRoute?: string, runRoute?: string, subject?: string, emptyText?: string, title?: string}}\n\t\t */\n\t\tcontent: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({}),\n\t\t},\n\n\t\t/**\n\t\t * Widget placement id, so the per-widget Refresh action\n\t\t * (`cn:widget:refresh`) reaches this instance's fetch.\n\t\t */\n\t\twidgetId: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Translate function. Falls back to the injected `cnTranslate`.\n\t\t * Provide explicitly when mounting outside a CnAppRoot ancestor.\n\t\t *\n\t\t * @type {((key: string) => string)|null}\n\t\t */\n\t\ttranslate: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\t},\n\n\temits: ['header'],\n\n\tsetup(props) {\n\t\t// The shared endpoint engine owns request dedup, the short-TTL cache\n\t\t// and the cn:page:refresh / cn:widget:refresh subscriptions — the same\n\t\t// binding CnStatWidget's endpoint mode uses, so a page-level Refresh\n\t\t// updates this widget with everything else on the page.\n\t\tconst widgetIdRef = ref(props.widgetId)\n\n\t\t// The detail surface's object context, injected the same way the other\n\t\t// endpoint-bound widgets (stat / chart / audit-trail) receive it, so a\n\t\t// `subject: '@objectId'` placement binds the CURRENT object without the\n\t\t// manifest hardcoding a uuid. Null on plain dashboards — the token then\n\t\t// stays unresolved and the endpoint engine's `blocked` semantics hold\n\t\t// the fetch instead of sending a literal `@objectId` to the server.\n\t\tconst objectCtxRaw = inject('cnObjectContext', null)\n\t\tconst detailCtxRaw = inject('cnDetailObjectContext', null)\n\t\tconst tokenCtx = () => ({\n\t\t\tworkspace: {},\n\t\t\tconfig: {},\n\t\t\t...(resolveObjectTokenContext(objectCtxRaw, detailCtxRaw) || {}),\n\t\t})\n\n\t\tconst configuredSubject = () => {\n\t\t\tconst subject = props.content && props.content.subject\n\t\t\treturn (typeof subject === 'string' && subject !== '') ? subject : ''\n\t\t}\n\n\t\t/**\n\t\t * The subject uuid after token resolution: `''` when no subject is\n\t\t * configured, `null` while a token still waits on the object context,\n\t\t * else the concrete uuid.\n\t\t */\n\t\tconst resolvedSubject = computed(() => {\n\t\t\tconst subject = configuredSubject()\n\t\t\tif (subject === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tconst value = resolveFilterValue(subject, tokenCtx())\n\t\t\tif (typeof value === 'string' && value.charAt(0) === '@') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn (value === undefined || value === null) ? null : String(value)\n\t\t})\n\n\t\tconst source = () => {\n\t\t\tconst params = { limit: normaliseLimit(props.content && props.content.limit) }\n\t\t\tconst subject = configuredSubject()\n\t\t\tif (subject !== '') {\n\t\t\t\tparams.subject = subject\n\t\t\t}\n\t\t\treturn { url: ACTIVE_RUNS_URL, method: 'GET', params }\n\t\t}\n\t\tconst { data, loading, error, refetch } = useEndpointSource(source, {\n\t\t\twidgetId: widgetIdRef,\n\t\t\tctx: tokenCtx,\n\t\t})\n\n\t\t// The history half of the subject view. A null config (no subject)\n\t\t// means the composable never queries: the org-wide widget stays a\n\t\t// single-request surface, bit-identical to before.\n\t\tconst completedSource = () => {\n\t\t\tconst subject = configuredSubject()\n\t\t\tif (subject === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\treturn {\n\t\t\t\turl: COMPLETED_RUNS_URL,\n\t\t\t\tmethod: 'GET',\n\t\t\t\tparams: { subject, limit: normaliseLimit(props.content && props.content.limit) },\n\t\t\t}\n\t\t}\n\t\tconst {\n\t\t\tdata: completedData,\n\t\t\tloading: completedLoading,\n\t\t\terror: completedError,\n\t\t\trefetch: refetchCompleted,\n\t\t} = useEndpointSource(completedSource, {\n\t\t\twidgetId: widgetIdRef,\n\t\t\tctx: tokenCtx,\n\t\t})\n\n\t\t// `inject` is re-read in setup so Vue 2.7 and Vue 3 resolve it\n\t\t// identically to the Options `inject` block (CnStatWidget precedent).\n\t\tconst injectedTranslate = inject('cnTranslate', null)\n\n\t\treturn {\n\t\t\tpayload: data,\n\t\t\tloading,\n\t\t\terror,\n\t\t\trefetch,\n\t\t\tcompletedPayload: completedData,\n\t\t\tcompletedLoading,\n\t\t\tcompletedError,\n\t\t\trefetchCompleted,\n\t\t\tresolvedSubject,\n\t\t\tinjectedTranslate,\n\t\t\ttokenCtx,\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tpollTimer: null,\n\t\t}\n\t},\n\n\tcomputed: {\n\t\t/**\n\t\t * Effective translate function: the explicit prop, then the injected\n\t\t * host one, then `@nextcloud/l10n` under the library's own app id.\n\t\t *\n\t\t * @return {(key: string) => string}\n\t\t */\n\t\ttr() {\n\t\t\tconst fn = this.translate ?? this.injectedTranslate ?? this.cnTranslate\n\t\t\tif (typeof fn === 'function') {\n\t\t\t\treturn (key) => fn(key)\n\t\t\t}\n\t\t\treturn (key) => t('nextcloud-vue', key)\n\t\t},\n\n\t\t/**\n\t\t * The rows to render — the endpoint's bounded page, defensively\n\t\t * re-capped so a wider server default can never overflow the cell.\n\t\t *\n\t\t * @return {Array<object>} The run rows.\n\t\t */\n\t\trows() {\n\t\t\tconst results = (this.payload && this.payload.results) || []\n\t\t\tif (Array.isArray(results) === false) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn results.slice(0, normaliseLimit(this.content.limit))\n\t\t},\n\n\t\t/**\n\t\t * How many live runs exist beyond the rendered rows.\n\t\t *\n\t\t * Read off the server's `total`, NOT the array length — the point of\n\t\t * the total is to be honest about what the cell could not fit.\n\t\t *\n\t\t * @return {number} The hidden run count (never negative).\n\t\t */\n\t\thiddenCount() {\n\t\t\tconst total = Number((this.payload && this.payload.total) ?? this.rows.length)\n\t\t\tif (Number.isFinite(total) === false) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.max(0, total - this.rows.length)\n\t\t},\n\n\t\t/** The \"+N more\" line. */\n\t\tmoreLabel() {\n\t\t\treturn this.tr('+{count} more').replace('{count}', String(this.hiddenCount))\n\t\t},\n\n\t\t/** Whether each row shows its status as a pill (`content.statusPill`). */\n\t\tpills() {\n\t\t\treturn this.content.statusPill === true\n\t\t},\n\n\t\t/** The nothing-running line. */\n\t\temptyLabel() {\n\t\t\tconst override = this.content.emptyText\n\t\t\tif (typeof override === 'string' && override !== '') {\n\t\t\t\treturn this.tr(override)\n\t\t\t}\n\t\t\treturn this.tr('No flows are running')\n\t\t},\n\n\t\t/** Whether this placement is scoped to one subject object. */\n\t\thasSubject() {\n\t\t\treturn typeof this.content.subject === 'string' && this.content.subject !== ''\n\t\t},\n\n\t\t/**\n\t\t * Whether a configured subject token still waits on the object\n\t\t * context. The widget shows its loading state instead of an empty\n\t\t * line then: \"no runs\" would be a claim about a case it has not\n\t\t * identified yet.\n\t\t *\n\t\t * @return {boolean} True while the subject is configured but unresolved.\n\t\t */\n\t\tsubjectPending() {\n\t\t\treturn this.hasSubject && this.resolvedSubject === null\n\t\t},\n\n\t\t/**\n\t\t * The subject's finished runs — the completed-runs read's bounded\n\t\t * page, re-capped like the live rows.\n\t\t *\n\t\t * @return {Array<object>} The terminal run rows (empty without a subject).\n\t\t */\n\t\tcompletedRows() {\n\t\t\tif (this.hasSubject === false) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst results = (this.completedPayload && this.completedPayload.results) || []\n\t\t\tif (Array.isArray(results) === false) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\treturn results.slice(0, normaliseLimit(this.content.limit))\n\t\t},\n\n\t\t/**\n\t\t * How many finished runs exist beyond the rendered history rows, read\n\t\t * off the completed read's honest total.\n\t\t *\n\t\t * @return {number} The hidden finished-run count (never negative).\n\t\t */\n\t\tcompletedHiddenCount() {\n\t\t\tconst total = Number((this.completedPayload && this.completedPayload.total) ?? this.completedRows.length)\n\t\t\tif (Number.isFinite(total) === false) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.max(0, total - this.completedRows.length)\n\t\t},\n\n\t\t/** The \"+N earlier\" line under the history section. */\n\t\tcompletedMoreLabel() {\n\t\t\treturn this.tr('+{count} earlier').replace('{count}', String(this.completedHiddenCount))\n\t\t},\n\n\t\t/**\n\t\t * Whether this subject has NO runs at all, live or finished. Rendered\n\t\t * as its own line: a case where nothing ever ran reads differently\n\t\t * from a case that is merely quiet right now.\n\t\t *\n\t\t * @return {boolean} True when both reads settled empty for a subject.\n\t\t */\n\t\tneverRan() {\n\t\t\treturn this.hasSubject\n\t\t\t\t&& this.subjectPending === false\n\t\t\t\t&& this.loading === false\n\t\t\t\t&& this.completedLoading === false\n\t\t\t\t&& this.completedError === ''\n\t\t\t\t&& this.rows.length === 0\n\t\t\t\t&& this.completedRows.length === 0\n\t\t},\n\n\t\t/** Whether the history section renders (rows or a failed history read). */\n\t\tshowHistory() {\n\t\t\treturn this.hasSubject\n\t\t\t\t&& this.subjectPending === false\n\t\t\t\t&& (this.completedRows.length > 0 || this.completedError !== '')\n\t\t},\n\n\t\t/** Whether a row click navigates (a `runRoute` or `rowRoute` is configured). */\n\t\tisLinked() {\n\t\t\treturn (typeof this.content.rowRoute === 'string' && this.content.rowRoute !== '')\n\t\t\t\t|| (typeof this.content.runRoute === 'string' && this.content.runRoute !== '')\n\t\t},\n\n\t\t/**\n\t\t * Poll interval in ms, or 0 when polling is off.\n\t\t *\n\t\t * Floored at 5s so a mis-authored `pollSeconds: 0.1` cannot turn a\n\t\t * dashboard into a request storm; `0` remains an explicit opt-out.\n\t\t *\n\t\t * @return {number} The interval in milliseconds.\n\t\t */\n\t\tpollMs() {\n\t\t\tconst raw = this.content.pollSeconds\n\t\t\tconst seconds = (raw === undefined || raw === null) ? 15 : Number(raw)\n\t\t\tif (Number.isFinite(seconds) === false || seconds <= 0) {\n\t\t\t\treturn 0\n\t\t\t}\n\t\t\treturn Math.max(5, seconds) * 1000\n\t\t},\n\t},\n\n\twatch: {\n\t\t'content.headerAction': {\n\t\t\tdeep: true,\n\t\t\thandler() {\n\t\t\t\tthis.emitHeader()\n\t\t\t},\n\t\t},\n\t},\n\n\tmounted() {\n\t\tthis.emitHeader()\n\t\tthis.startPolling()\n\t\tdocument.addEventListener('visibilitychange', this.onVisibilityChange)\n\t},\n\n\tbeforeUnmount() {\n\t\tthis.teardown()\n\t},\n\n\tmethods: {\n\t\t/**\n\t\t * Tell the card around the runs what its header shows: the header\n\t\t * action, if any.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\temitHeader() {\n\t\t\tconst action = this.content && this.content.headerAction\n\t\t\tconst usable = action && typeof action === 'object' && typeof action.label === 'string' && action.label !== ''\n\t\t\t/**\n\t\t\t * @event header The card header's parts: `{ link, note, action, pill }`, `action` being `{ label, icon, run }` or null.\n\t\t\t */\n\t\t\tthis.$emit('header', {\n\t\t\t\tlink: null,\n\t\t\t\tnote: '',\n\t\t\t\taction: usable ? { label: this.tr(action.label), icon: action.icon || '', run: () => this.runHeaderAction() } : null,\n\t\t\t\tpill: null,\n\t\t\t})\n\t\t},\n\n\t\t/**\n\t\t * Run the header action with the record's tokens resolved, then read the\n\t\t * runs again so a started run shows.\n\t\t *\n\t\t * @return {Promise<void>}\n\t\t */\n\t\tasync runHeaderAction() {\n\t\t\tconst { label, icon, ...action } = resolveDeepTokens(this.content.headerAction, this.tokenCtx())\n\t\t\ttry {\n\t\t\t\tconst outcome = await (typeof this.cnDispatchAction === 'function'\n\t\t\t\t\t? this.cnDispatchAction(action)\n\t\t\t\t\t: dispatchAction(action, { router: this.$router || null }))\n\t\t\t\tif (outcome === false) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.refetchAll()\n\t\t},\n\n\t\t/**\n\t\t * Start (or restart) the refetch interval, unless polling is disabled.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tstartPolling() {\n\t\t\tthis.stopPolling()\n\t\t\tif (this.pollMs === 0 || document.hidden === true) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.pollTimer = setInterval(() => {\n\t\t\t\tthis.refetchAll()\n\t\t\t}, this.pollMs)\n\t\t},\n\n\t\t/**\n\t\t * Refetch the live read, and the history read when a subject is\n\t\t * configured — a run that finishes between polls must MOVE to the\n\t\t * history section, not vanish from the widget.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\trefetchAll() {\n\t\t\tthis.refetch(true)\n\t\t\tif (this.hasSubject) {\n\t\t\t\tthis.refetchCompleted(true)\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Clear the refetch interval.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tstopPolling() {\n\t\t\tif (this.pollTimer !== null) {\n\t\t\t\tclearInterval(this.pollTimer)\n\t\t\t\tthis.pollTimer = null\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Remove the timer and the visibility listener.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tteardown() {\n\t\t\tthis.stopPolling()\n\t\t\tdocument.removeEventListener('visibilitychange', this.onVisibilityChange)\n\t\t},\n\n\t\t/**\n\t\t * Pause polling while the tab is hidden; refetch once and resume when\n\t\t * it comes back, so returning to the dashboard shows current state\n\t\t * rather than whatever was true when the tab was backgrounded.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tonVisibilityChange() {\n\t\t\tif (document.hidden === true) {\n\t\t\t\tthis.stopPolling()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.refetchAll()\n\t\t\tthis.startPolling()\n\t\t},\n\n\t\t/**\n\t\t * Whether a run's status is terminal — the history half of the\n\t\t * subject view. Drives the hollow-dot / muted-name row treatment.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {boolean} True for a finished run.\n\t\t */\n\t\tisTerminal(run) {\n\t\t\treturn TERMINAL_STATUSES.includes(run && run.status)\n\t\t},\n\n\t\t/**\n\t\t * The human label for a status, falling back to the raw value so an\n\t\t * engine that gains a status still renders something truthful.\n\t\t *\n\t\t * @param {string} status The run status.\n\t\t * @return {string} The label.\n\t\t */\n\t\tstatusLabel(status) {\n\t\t\tconst own = this.content.statusLabels && this.content.statusLabels[status]\n\t\t\tconst key = (typeof own === 'string' && own !== '') ? own : STATUS_LABELS[status]\n\t\t\treturn key ? this.tr(key) : String(status || '')\n\t\t},\n\n\t\t/**\n\t\t * The pill tone of a status: finished well is success, failed is error,\n\t\t * anything still going is info.\n\t\t *\n\t\t * @param {string} status The run status.\n\t\t * @return {string} A CnStatusBadge variant.\n\t\t * @spec openspec/changes/flow-runs-ruled-with-pills/specs/cn-flow-runs-widget/spec.md\n\t\t */\n\t\tstatusVariant(status) {\n\t\t\tif (status === 'completed') {\n\t\t\t\treturn 'success'\n\t\t\t}\n\t\t\tif (status === 'failed' || status === 'dead_letter') {\n\t\t\t\treturn 'error'\n\t\t\t}\n\t\t\treturn status === 'stopped' ? 'default' : 'info'\n\t\t},\n\n\t\t/**\n\t\t * The secondary line: status, the step the run sits on, and what\n\t\t * triggered it — whichever of those the run actually carries.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {string} The meta line.\n\t\t */\n\t\tmetaLine(run) {\n\t\t\tconst words = this.content.triggerLabels && this.content.triggerLabels[run.trigger]\n\t\t\tif (typeof words === 'string' && words !== '') {\n\t\t\t\treturn this.tr(words)\n\t\t\t}\n\t\t\tconst parts = this.pills ? [] : [this.statusLabel(run.status)]\n\t\t\tif (run.step) {\n\t\t\t\tparts.push(String(run.step))\n\t\t\t}\n\t\t\tif (run.trigger) {\n\t\t\t\tparts.push(String(run.trigger))\n\t\t\t}\n\t\t\treturn parts.join(' · ')\n\t\t},\n\n\t\t/**\n\t\t * How long the run has been going, as a coarse relative label.\n\t\t *\n\t\t * Coarse on purpose: a dashboard reader wants \"8m\", not a timestamp,\n\t\t * and a second-precision label on a 15s poll would read as stale.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {string} The age label, or '' when the run has no start time.\n\t\t */\n\t\tageLabel(run) {\n\t\t\tconst started = Date.parse(run.created || '')\n\t\t\tif (Number.isFinite(started) === false) {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\tif (this.content.age === 'datetime') {\n\t\t\t\tconst at = new Date(started)\n\t\t\t\tconst pad = (value) => String(value).padStart(2, '0')\n\t\t\t\treturn `${formatBoardDate(at)}, ${pad(at.getHours())}:${pad(at.getMinutes())}`\n\t\t\t}\n\t\t\tconst seconds = Math.max(0, Math.round((Date.now() - started) / 1000))\n\t\t\tif (seconds < 60) {\n\t\t\t\treturn this.tr('now')\n\t\t\t}\n\t\t\tconst minutes = Math.round(seconds / 60)\n\t\t\tif (minutes < 60) {\n\t\t\t\treturn `${minutes}m`\n\t\t\t}\n\t\t\tconst hours = Math.round(minutes / 60)\n\t\t\tif (hours < 24) {\n\t\t\t\treturn `${hours}h`\n\t\t\t}\n\t\t\treturn `${Math.round(hours / 24)}d`\n\t\t},\n\n\t\t/**\n\t\t * The route a run row links to, or null when it links nowhere.\n\t\t *\n\t\t * `runRoute` wins when the row carries a run uuid: on a case page a\n\t\t * click means \"show me THIS run\", and the run uuid is the deep link\n\t\t * the row contract carries. Without a `runRoute` (or on a row with no\n\t\t * uuid) `rowRoute` receives the FLOW id, the surface every\n\t\t * flow-authoring app has.\n\t\t *\n\t\t * The flow id alone answers the wrong question, so the run travels as\n\t\t * `?run=`, the address CnFlowDetail documents its `run` prop as\n\t\t * reading: a `rowRoute` click and a pasted run link open the same\n\t\t * screen.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {object|null} A vue-router location, or null.\n\t\t */\n\t\trunTarget(run) {\n\t\t\tif (this.isLinked === false || !this.$router) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst hasUuid = run.uuid !== undefined && run.uuid !== null && run.uuid !== ''\n\t\t\tconst runRoute = this.content.runRoute\n\t\t\tif (typeof runRoute === 'string' && runRoute !== '' && hasUuid) {\n\t\t\t\treturn { name: runRoute, params: { id: String(run.uuid) } }\n\t\t\t}\n\t\t\tif (typeof this.content.rowRoute !== 'string' || this.content.rowRoute === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst id = run.flowId\n\t\t\tif (id === undefined || id === null || id === '') {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\tconst target = { name: this.content.rowRoute, params: { id: String(id) } }\n\t\t\t// An empty `?run=` is not a deep link; CnFlowDetail's `run` prop\n\t\t\t// defaults to '' so \"no run named\" stays one value.\n\t\t\tif (hasUuid) {\n\t\t\t\ttarget.query = { run: String(run.uuid) }\n\t\t\t}\n\t\t\treturn target\n\t\t},\n\n\t\t/**\n\t\t * The href of a run row's link, or '' when the row links nowhere.\n\t\t *\n\t\t * @param {object} run The run row.\n\t\t * @return {string} The resolved href.\n\t\t */\n\t\trunHref(run) {\n\t\t\treturn resolveHref(this.runTarget(run), this.$router)\n\t\t},\n\n\t\t/**\n\t\t * Route a plain click on a run row's link in-app; modified clicks\n\t\t * are left to the browser.\n\t\t *\n\t\t * @param {MouseEvent} event The click event.\n\t\t * @param {object} run The clicked run row.\n\t\t * @return {void}\n\t\t */\n\t\tonRowClick(event, run) {\n\t\t\tfollowLinkClick(event, this.runTarget(run), this.$router)\n\t\t},\n\t},\n}\n\n/**\n * Clamp a configured row limit into the range the endpoint accepts.\n *\n * @param {number|string|undefined} raw The configured limit.\n * @return {number} A limit between 1 and 50 (default 6).\n */\nfunction normaliseLimit(raw) {\n\tconst n = Number(raw)\n\tif (Number.isFinite(n) === false || n <= 0) {\n\t\treturn 6\n\t}\n\treturn Math.min(50, Math.round(n))\n}\n</script>\n\n<style scoped>\n.cn-flow-runs-widget {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px;\n\tmin-width: 0;\n}\n\n.cn-flow-runs-widget__loading {\n\tdisplay: flex;\n\tjustify-content: center;\n\tpadding: 8px 0;\n}\n\n.cn-flow-runs-widget__empty,\n.cn-flow-runs-widget__error,\n.cn-flow-runs-widget__more {\n\tmargin: 0;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 13px;\n}\n\n.cn-flow-runs-widget__more {\n\tpadding-top: 4px;\n}\n\n.cn-flow-runs-widget__list {\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tmin-width: 0;\n}\n\n.cn-flow-runs-widget__row {\n\tborder-bottom: 1px solid var(--color-border);\n\tmin-width: 0;\n}\n\n.cn-flow-runs-widget__row:last-child {\n\tborder-bottom: none;\n}\n\n.cn-flow-runs-widget__row-content {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tpadding: 6px 0;\n\tmin-width: 0;\n\tcolor: inherit;\n\ttext-decoration: none;\n}\n\na.cn-flow-runs-widget__row-content {\n\tcursor: pointer;\n}\n\n.cn-flow-runs-widget__dot {\n\tflex: 0 0 auto;\n\twidth: 8px;\n\theight: 8px;\n\tborder-radius: 50%;\n\tbackground: var(--color-text-maxcontrast);\n}\n\n/* Executing now — the primary colour, and the only row that animates. */\n.cn-flow-runs-widget__dot--running {\n\tbackground: var(--color-primary-element, #0082c9);\n\tanimation: cn-flow-runs-pulse 1.6s ease-in-out infinite;\n}\n\n.cn-flow-runs-widget__dot--queued {\n\tbackground: var(--color-warning, #c28900);\n}\n\n.cn-flow-runs-widget__dot--suspended {\n\tbackground: var(--color-text-maxcontrast);\n}\n\n/* Terminal rows: the dot is a hollow RING, so live (filled) and finished\n (hollow) never differ by colour alone. The per-status colour still rides\n on the ring's border. */\n.cn-flow-runs-widget__dot--terminal {\n\twidth: 6px;\n\theight: 6px;\n\tbackground: transparent;\n\tborder: 2px solid var(--color-text-maxcontrast);\n}\n\n.cn-flow-runs-widget__dot--terminal.cn-flow-runs-widget__dot--completed {\n\tborder-color: var(--color-success, #2d7b41);\n}\n\n.cn-flow-runs-widget__dot--terminal.cn-flow-runs-widget__dot--failed,\n.cn-flow-runs-widget__dot--terminal.cn-flow-runs-widget__dot--dead_letter {\n\tborder-color: var(--color-error, #d91f2d);\n}\n\n.cn-flow-runs-widget__body {\n\tdisplay: flex;\n\tflex-direction: column;\n\tmin-width: 0;\n\tflex: 1 1 auto;\n}\n\n.cn-flow-runs-widget__name {\n\tfont-weight: 600;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n/* Finished runs read as history: regular weight, muted colour. The hollow\n dot and the section label carry the distinction for anyone who cannot\n rely on colour. */\n.cn-flow-runs-widget__row--terminal .cn-flow-runs-widget__name {\n\tfont-weight: 400;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n/* Must sit AFTER the plain `__name` rule: the compound selector is more\n specific, and stylelint's no-descending-specificity flags the reverse\n order because the cascade then depends on specificity rather than\n source order — the shape that quietly stops working when someone adds\n a competing rule. */\na.cn-flow-runs-widget__row-content:hover .cn-flow-runs-widget__name {\n\ttext-decoration: underline;\n}\n\n.cn-flow-runs-widget__meta {\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.cn-flow-runs-widget__age {\n\tflex: 0 0 auto;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-variant-numeric: tabular-nums;\n}\n\n/* The history section label. Small caps text, not a colour: the section\n boundary must survive monochrome. */\n.cn-flow-runs-widget__history-title {\n\tmargin: 0;\n\tpadding-top: 8px;\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: 12px;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n}\n\n/* Status pills: each row ruled on top, the name over its meta line, the pill\n and the start moment at the end, as the Dq case boards draw the Flows card. */\n.cn-flow-runs-widget--pills .cn-flow-runs-widget__row {\n\tborder-top: 1px solid var(--color-border);\n\tborder-bottom: none;\n}\n\n.cn-flow-runs-widget--pills .cn-flow-runs-widget__row-content {\n\tflex-wrap: wrap;\n\tgap: 6px 16px;\n\tpadding: 11px 0;\n}\n\n.cn-flow-runs-widget--pills .cn-flow-runs-widget__body {\n\tflex: 1 1 260px;\n\tgap: 2px;\n}\n\n.cn-flow-runs-widget--pills .cn-flow-runs-widget__name,\n.cn-flow-runs-widget--pills .cn-flow-runs-widget__row--terminal .cn-flow-runs-widget__name {\n\tfont-size: 15px;\n\tfont-weight: 500;\n\tcolor: var(--color-main-text);\n\twhite-space: normal;\n}\n\n.cn-flow-runs-widget--pills .cn-flow-runs-widget__meta {\n\tfont-size: 13px;\n\twhite-space: normal;\n}\n\n.cn-flow-runs-widget--pills .cn-flow-runs-widget__age {\n\tflex: 0 0 104px;\n\tfont-size: 13px;\n\ttext-align: end;\n}\n\n@keyframes cn-flow-runs-pulse {\n\t0%, 100% { opacity: 1; }\n\t50% { opacity: 0.35; }\n}\n\n/* Respect a reduced-motion preference: the pulse is decoration, and the dot\n colour already carries the status. */\n@media (prefers-reduced-motion: reduce) {\n\t.cn-flow-runs-widget__dot--running {\n\t\tanimation: none;\n\t}\n}\n</style>\n"],"names":["CnStatusBadge","t"],"mappings":"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"}
@@ -1,78 +1,83 @@
1
- import { resolveComponent, openBlock, createElementBlock, toDisplayString, createVNode, Fragment, renderList, normalizeClass, createBlock, resolveDynamicComponent, withCtx, createElementVNode, createCommentVNode } from 'vue';
1
+ import { resolveComponent, openBlock, createElementBlock, normalizeClass, toDisplayString, createVNode, Fragment, renderList, createBlock, resolveDynamicComponent, withCtx, createCommentVNode, createElementVNode } from 'vue';
2
2
 
3
- const _hoisted_1 = { class: "cn-flow-runs-widget" };
4
- const _hoisted_2 = {
3
+ const _hoisted_1 = {
5
4
  key: 0,
6
5
  class: "cn-flow-runs-widget__error"
7
6
  };
8
- const _hoisted_3 = {
7
+ const _hoisted_2 = {
9
8
  key: 1,
10
9
  class: "cn-flow-runs-widget__loading"
11
10
  };
12
- const _hoisted_4 = {
11
+ const _hoisted_3 = {
13
12
  key: 2,
14
13
  class: "cn-flow-runs-widget__empty"
15
14
  };
16
- const _hoisted_5 = {
15
+ const _hoisted_4 = {
17
16
  key: 3,
18
17
  class: "cn-flow-runs-widget__empty"
19
18
  };
20
- const _hoisted_6 = {
19
+ const _hoisted_5 = {
21
20
  key: 0,
22
21
  class: "cn-flow-runs-widget__empty"
23
22
  };
24
- const _hoisted_7 = {
23
+ const _hoisted_6 = {
25
24
  key: 1,
26
25
  class: "cn-flow-runs-widget__list"
27
26
  };
28
- const _hoisted_8 = ["data-status"];
29
- const _hoisted_9 = ["title"];
30
- const _hoisted_10 = { class: "cn-flow-runs-widget__body" };
31
- const _hoisted_11 = { class: "cn-flow-runs-widget__name" };
32
- const _hoisted_12 = { class: "cn-flow-runs-widget__meta" };
33
- const _hoisted_13 = { class: "cn-flow-runs-widget__age" };
34
- const _hoisted_14 = {
27
+ const _hoisted_7 = ["data-status"];
28
+ const _hoisted_8 = ["title"];
29
+ const _hoisted_9 = { class: "cn-flow-runs-widget__body" };
30
+ const _hoisted_10 = { class: "cn-flow-runs-widget__name" };
31
+ const _hoisted_11 = { class: "cn-flow-runs-widget__meta" };
32
+ const _hoisted_12 = { class: "cn-flow-runs-widget__age" };
33
+ const _hoisted_13 = {
35
34
  key: 2,
36
35
  class: "cn-flow-runs-widget__more"
37
36
  };
38
- const _hoisted_15 = { class: "cn-flow-runs-widget__history-title" };
39
- const _hoisted_16 = {
37
+ const _hoisted_14 = {
40
38
  key: 0,
41
- class: "cn-flow-runs-widget__error"
39
+ class: "cn-flow-runs-widget__history-title"
42
40
  };
43
- const _hoisted_17 = {
41
+ const _hoisted_15 = {
44
42
  key: 1,
45
- class: "cn-flow-runs-widget__list"
43
+ class: "cn-flow-runs-widget__error"
46
44
  };
47
- const _hoisted_18 = ["data-status"];
48
- const _hoisted_19 = ["title"];
49
- const _hoisted_20 = { class: "cn-flow-runs-widget__body" };
50
- const _hoisted_21 = { class: "cn-flow-runs-widget__name" };
51
- const _hoisted_22 = { class: "cn-flow-runs-widget__meta" };
52
- const _hoisted_23 = { class: "cn-flow-runs-widget__age" };
53
- const _hoisted_24 = {
45
+ const _hoisted_16 = {
54
46
  key: 2,
47
+ class: "cn-flow-runs-widget__list"
48
+ };
49
+ const _hoisted_17 = ["data-status"];
50
+ const _hoisted_18 = ["title"];
51
+ const _hoisted_19 = { class: "cn-flow-runs-widget__body" };
52
+ const _hoisted_20 = { class: "cn-flow-runs-widget__name" };
53
+ const _hoisted_21 = { class: "cn-flow-runs-widget__meta" };
54
+ const _hoisted_22 = { class: "cn-flow-runs-widget__age" };
55
+ const _hoisted_23 = {
56
+ key: 3,
55
57
  class: "cn-flow-runs-widget__more"
56
58
  };
57
59
 
58
60
  function render(_ctx, _cache, $props, $setup, $data, $options) {
59
61
  const _component_NcLoadingIcon = resolveComponent("NcLoadingIcon");
62
+ const _component_CnStatusBadge = resolveComponent("CnStatusBadge");
60
63
 
61
- return (openBlock(), createElementBlock("div", _hoisted_1, [
64
+ return (openBlock(), createElementBlock("div", {
65
+ class: normalizeClass(["cn-flow-runs-widget", { 'cn-flow-runs-widget--pills': $options.pills }])
66
+ }, [
62
67
  ($setup.error)
63
- ? (openBlock(), createElementBlock("p", _hoisted_2, toDisplayString($options.tr('Could not load the running flows')), 1 /* TEXT */))
68
+ ? (openBlock(), createElementBlock("p", _hoisted_1, toDisplayString($options.tr('Could not load the running flows')), 1 /* TEXT */))
64
69
  : (($setup.loading || $options.subjectPending) && $options.rows.length === 0)
65
- ? (openBlock(), createElementBlock("div", _hoisted_3, [
70
+ ? (openBlock(), createElementBlock("div", _hoisted_2, [
66
71
  createVNode(_component_NcLoadingIcon, { size: 24 })
67
72
  ]))
68
73
  : ($options.neverRan)
69
- ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString($options.tr('No flows have run yet')), 1 /* TEXT */))
74
+ ? (openBlock(), createElementBlock("p", _hoisted_3, toDisplayString($options.tr('No flows have run yet')), 1 /* TEXT */))
70
75
  : ($options.rows.length === 0 && $options.showHistory === false)
71
- ? (openBlock(), createElementBlock("p", _hoisted_5, toDisplayString($options.emptyLabel), 1 /* TEXT */))
76
+ ? (openBlock(), createElementBlock("p", _hoisted_4, toDisplayString($options.emptyLabel), 1 /* TEXT */))
72
77
  : (openBlock(), createElementBlock(Fragment, { key: 4 }, [
73
- ($options.rows.length === 0)
74
- ? (openBlock(), createElementBlock("p", _hoisted_6, toDisplayString($options.emptyLabel), 1 /* TEXT */))
75
- : (openBlock(), createElementBlock("ul", _hoisted_7, [
78
+ ($options.rows.length === 0 && $props.content.quietLineWithHistory !== false)
79
+ ? (openBlock(), createElementBlock("p", _hoisted_5, toDisplayString($options.emptyLabel), 1 /* TEXT */))
80
+ : (openBlock(), createElementBlock("ul", _hoisted_6, [
76
81
  (openBlock(true), createElementBlock(Fragment, null, renderList($options.rows, (run, index) => {
77
82
  return (openBlock(), createElementBlock("li", {
78
83
  key: run.uuid || `row-${index}`,
@@ -85,30 +90,44 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
85
90
  onClick: $event => ($options.onRowClick($event, run))
86
91
  }, {
87
92
  default: withCtx(() => [
88
- createElementVNode("span", {
89
- class: normalizeClass(["cn-flow-runs-widget__dot", `cn-flow-runs-widget__dot--${run.status}`]),
90
- title: $options.statusLabel(run.status)
91
- }, null, 10 /* CLASS, PROPS */, _hoisted_9),
92
- createElementVNode("span", _hoisted_10, [
93
- createElementVNode("span", _hoisted_11, toDisplayString(run.flowName), 1 /* TEXT */),
94
- createElementVNode("span", _hoisted_12, toDisplayString($options.metaLine(run)), 1 /* TEXT */)
93
+ (!$options.pills)
94
+ ? (openBlock(), createElementBlock("span", {
95
+ key: 0,
96
+ class: normalizeClass(["cn-flow-runs-widget__dot", `cn-flow-runs-widget__dot--${run.status}`]),
97
+ title: $options.statusLabel(run.status)
98
+ }, null, 10 /* CLASS, PROPS */, _hoisted_8))
99
+ : createCommentVNode("v-if", true),
100
+ createElementVNode("span", _hoisted_9, [
101
+ createElementVNode("span", _hoisted_10, toDisplayString(run.flowName), 1 /* TEXT */),
102
+ createElementVNode("span", _hoisted_11, toDisplayString($options.metaLine(run)), 1 /* TEXT */)
95
103
  ]),
96
- createElementVNode("span", _hoisted_13, toDisplayString($options.ageLabel(run)), 1 /* TEXT */)
104
+ ($options.pills)
105
+ ? (openBlock(), createBlock(_component_CnStatusBadge, {
106
+ key: 1,
107
+ class: "cn-flow-runs-widget__pill",
108
+ label: $options.statusLabel(run.status),
109
+ variant: $options.statusVariant(run.status),
110
+ size: "small"
111
+ }, null, 8 /* PROPS */, ["label", "variant"]))
112
+ : createCommentVNode("v-if", true),
113
+ createElementVNode("span", _hoisted_12, toDisplayString($options.ageLabel(run)), 1 /* TEXT */)
97
114
  ]),
98
115
  _: 2 /* DYNAMIC */
99
116
  }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["href", "onClick"]))
100
- ], 10 /* CLASS, PROPS */, _hoisted_8))
117
+ ], 10 /* CLASS, PROPS */, _hoisted_7))
101
118
  }), 128 /* KEYED_FRAGMENT */))
102
119
  ])),
103
120
  ($options.hiddenCount > 0)
104
- ? (openBlock(), createElementBlock("p", _hoisted_14, toDisplayString($options.moreLabel), 1 /* TEXT */))
121
+ ? (openBlock(), createElementBlock("p", _hoisted_13, toDisplayString($options.moreLabel), 1 /* TEXT */))
105
122
  : createCommentVNode("v-if", true),
106
123
  ($options.showHistory)
107
124
  ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [
108
- createElementVNode("p", _hoisted_15, toDisplayString($options.tr('Earlier runs')), 1 /* TEXT */),
125
+ ($props.content.historyTitle !== false)
126
+ ? (openBlock(), createElementBlock("p", _hoisted_14, toDisplayString($options.tr('Earlier runs')), 1 /* TEXT */))
127
+ : createCommentVNode("v-if", true),
109
128
  ($setup.completedError)
110
- ? (openBlock(), createElementBlock("p", _hoisted_16, toDisplayString($options.tr('Could not load the run history')), 1 /* TEXT */))
111
- : (openBlock(), createElementBlock("ul", _hoisted_17, [
129
+ ? (openBlock(), createElementBlock("p", _hoisted_15, toDisplayString($options.tr('Could not load the run history')), 1 /* TEXT */))
130
+ : (openBlock(), createElementBlock("ul", _hoisted_16, [
112
131
  (openBlock(true), createElementBlock(Fragment, null, renderList($options.completedRows, (run, index) => {
113
132
  return (openBlock(), createElementBlock("li", {
114
133
  key: run.uuid || `completed-${index}`,
@@ -121,28 +140,40 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
121
140
  onClick: $event => ($options.onRowClick($event, run))
122
141
  }, {
123
142
  default: withCtx(() => [
124
- createElementVNode("span", {
125
- class: normalizeClass(["cn-flow-runs-widget__dot cn-flow-runs-widget__dot--terminal", `cn-flow-runs-widget__dot--${run.status}`]),
126
- title: $options.statusLabel(run.status)
127
- }, null, 10 /* CLASS, PROPS */, _hoisted_19),
128
- createElementVNode("span", _hoisted_20, [
129
- createElementVNode("span", _hoisted_21, toDisplayString(run.flowName), 1 /* TEXT */),
130
- createElementVNode("span", _hoisted_22, toDisplayString($options.metaLine(run)), 1 /* TEXT */)
143
+ (!$options.pills)
144
+ ? (openBlock(), createElementBlock("span", {
145
+ key: 0,
146
+ class: normalizeClass(["cn-flow-runs-widget__dot cn-flow-runs-widget__dot--terminal", `cn-flow-runs-widget__dot--${run.status}`]),
147
+ title: $options.statusLabel(run.status)
148
+ }, null, 10 /* CLASS, PROPS */, _hoisted_18))
149
+ : createCommentVNode("v-if", true),
150
+ createElementVNode("span", _hoisted_19, [
151
+ createElementVNode("span", _hoisted_20, toDisplayString(run.flowName), 1 /* TEXT */),
152
+ createElementVNode("span", _hoisted_21, toDisplayString($options.metaLine(run)), 1 /* TEXT */)
131
153
  ]),
132
- createElementVNode("span", _hoisted_23, toDisplayString($options.ageLabel(run)), 1 /* TEXT */)
154
+ ($options.pills)
155
+ ? (openBlock(), createBlock(_component_CnStatusBadge, {
156
+ key: 1,
157
+ class: "cn-flow-runs-widget__pill",
158
+ label: $options.statusLabel(run.status),
159
+ variant: $options.statusVariant(run.status),
160
+ size: "small"
161
+ }, null, 8 /* PROPS */, ["label", "variant"]))
162
+ : createCommentVNode("v-if", true),
163
+ createElementVNode("span", _hoisted_22, toDisplayString($options.ageLabel(run)), 1 /* TEXT */)
133
164
  ]),
134
165
  _: 2 /* DYNAMIC */
135
166
  }, 1032 /* PROPS, DYNAMIC_SLOTS */, ["href", "onClick"]))
136
- ], 10 /* CLASS, PROPS */, _hoisted_18))
167
+ ], 10 /* CLASS, PROPS */, _hoisted_17))
137
168
  }), 128 /* KEYED_FRAGMENT */))
138
169
  ])),
139
170
  ($setup.completedError === '' && $options.completedHiddenCount > 0)
140
- ? (openBlock(), createElementBlock("p", _hoisted_24, toDisplayString($options.completedMoreLabel), 1 /* TEXT */))
171
+ ? (openBlock(), createElementBlock("p", _hoisted_23, toDisplayString($options.completedMoreLabel), 1 /* TEXT */))
141
172
  : createCommentVNode("v-if", true)
142
173
  ], 64 /* STABLE_FRAGMENT */))
143
174
  : createCommentVNode("v-if", true)
144
175
  ], 64 /* STABLE_FRAGMENT */))
145
- ]))
176
+ ], 2 /* CLASS */))
146
177
  }
147
178
 
148
179
  export { render };