Skip to content

Commit dc3f99b

Browse files
Show run detail action on flow rows
1 parent a411fe7 commit dc3f99b

6 files changed

Lines changed: 100 additions & 5 deletions

File tree

app/Http/Controllers/WorkflowsController.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -628,10 +628,31 @@ private function listItemView(WorkflowRunSummary $summary): array
628628
$item['history_budget_indicator'] = $this->historyBudgetIndicator($item);
629629
$item = CompatibilitySemantics::annotateListItem($item);
630630
$item['actionability'] = ActionabilityContract::annotateRun($item)['actionability'];
631+
$item['detail_action'] = $this->detailAction($item);
631632

632633
return $item;
633634
}
634635

636+
/**
637+
* @param array<string, mixed> $item
638+
* @return array<string, mixed>
639+
*/
640+
private function detailAction(array $item): array
641+
{
642+
$historyEventCount = $this->intValue($item['history_event_count'] ?? null);
643+
$hasTypedHistory = $historyEventCount !== null && $historyEventCount > 0;
644+
645+
return [
646+
'label' => 'Run Detail',
647+
'available' => true,
648+
'history_available' => $hasTypedHistory,
649+
'unavailable_label' => $hasTypedHistory ? null : 'No typed history',
650+
'description' => $hasTypedHistory
651+
? 'Open the selected run detail, including history, tasks, commands, activities, metadata, and timeline data.'
652+
: 'Open the selected run detail. This row has no typed history events, so history-specific diagnostics may be unavailable.',
653+
];
654+
}
655+
635656
/**
636657
* @param array<string, mixed> $item
637658
* @return array<string, mixed>

public/app.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/mix-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"/app.js": "/app.js?id=9fa8a41ec214053e2b1281a730b0d187",
2+
"/app.js": "/app.js?id=636e2d282c73577fb3b6664300d489e3",
33
"/app-dark.css": "/app-dark.css?id=64d24ee96944ffdb4b26a9be1658c1e3",
44
"/app.css": "/app.css?id=d525454610dfd3c5a581fc49676f8a37",
55
"/img/favicon.png": "/img/favicon.png?id=7c006241b093796d6abfa3049df93a59",

resources/js/screens/flows/flow-row.vue

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,24 @@
7474
<td v-if="isTerminalCollection() && columnEnabled('duration')" class="table-fit">
7575
<span>{{ duration(flow.started_at || flow.created_at, flow.closed_at || flow.updated_at) }}</span>
7676
</td>
77+
78+
<td v-if="columnEnabled('actions')" class="table-fit text-right">
79+
<router-link
80+
class="btn btn-outline-secondary btn-sm"
81+
:title="detailActionTitle(flow)"
82+
:to="detailRoute(flow)"
83+
>
84+
{{ detailActionLabel(flow) }}
85+
</router-link>
86+
87+
<div
88+
v-if="showDetailActionUnavailableState(flow)"
89+
class="small text-muted mt-1"
90+
:title="detailActionTitle(flow)"
91+
>
92+
{{ detailActionUnavailableLabel(flow) }}
93+
</div>
94+
</td>
7795
</tr>
7896
</template>
7997

@@ -127,6 +145,51 @@
127145
}
128146
},
129147
148+
detailAction(flow) {
149+
return flow && flow.detail_action
150+
? flow.detail_action
151+
: null
152+
},
153+
154+
detailActionLabel(flow) {
155+
const action = this.detailAction(flow)
156+
157+
return action && action.label
158+
? action.label
159+
: 'Run Detail'
160+
},
161+
162+
detailActionTitle(flow) {
163+
const action = this.detailAction(flow)
164+
165+
return action && action.description
166+
? action.description
167+
: 'Open the selected run detail.'
168+
},
169+
170+
showDetailActionUnavailableState(flow) {
171+
const action = this.detailAction(flow)
172+
173+
return action
174+
? action.history_available === false
175+
: !this.hasTypedHistory(flow)
176+
},
177+
178+
detailActionUnavailableLabel(flow) {
179+
const action = this.detailAction(flow)
180+
181+
return action && action.unavailable_label
182+
? action.unavailable_label
183+
: 'No typed history'
184+
},
185+
186+
hasTypedHistory(flow) {
187+
return flow
188+
&& flow.history_event_count !== null
189+
&& flow.history_event_count !== undefined
190+
&& Number(flow.history_event_count) > 0
191+
},
192+
130193
isTerminalCollection() {
131194
return ['completed', 'failed', 'cancelled', 'terminated'].includes(this.$route.params.type)
132195
},

resources/js/screens/flows/index.vue

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@
394394
},
395395
396396
defaultWorkflowListColumns() {
397-
return ['flow', 'started_at', 'closed_at', 'duration']
397+
return ['flow', 'started_at', 'closed_at', 'duration', 'actions']
398398
},
399399
400400
workflowListColumnOptions() {
@@ -408,6 +408,8 @@
408408
options.push({key: 'duration', label: 'Duration'})
409409
}
410410
411+
options.push({key: 'actions', label: 'Actions'})
412+
411413
return options
412414
},
413415
@@ -420,6 +422,10 @@
420422
normalized.unshift('flow')
421423
}
422424
425+
if (!normalized.includes('actions')) {
426+
normalized.push('actions')
427+
}
428+
423429
return normalized.length > 0
424430
? normalized
425431
: this.defaultWorkflowListColumns().filter((column) => allowed.includes(column))
@@ -464,7 +470,7 @@
464470
class="mr-2 waterline-column-option"
465471
value="${this.escapeHtml(column.key)}"
466472
${columns.includes(column.key) ? 'checked' : ''}
467-
${column.key === 'flow' ? 'disabled' : ''}>
473+
${['flow', 'actions'].includes(column.key) ? 'disabled' : ''}>
468474
<span>${this.escapeHtml(column.label)}</span>
469475
</label>
470476
`).join('')
@@ -1614,6 +1620,7 @@
16141620
</th>
16151621
<th v-if="isTerminalCollection() && columnEnabled('closed_at')">{{ closedAtLabel() }}</th>
16161622
<th v-if="isTerminalCollection() && columnEnabled('duration')" class="text-right">Duration</th>
1623+
<th v-if="columnEnabled('actions')" class="text-right">Actions</th>
16171624
</tr>
16181625
</thead>
16191626

tests/Feature/V2DashboardWorkflowListTest.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,11 @@ public function testTerminalListEndpointsFilterByRawStatus(): void
219219
->assertJsonCount(1, 'data')
220220
->assertJsonPath('data.0.id', $failed->id)
221221
->assertJsonPath('data.0.status', 'failed')
222-
->assertJsonPath('data.0.is_terminal', true);
222+
->assertJsonPath('data.0.is_terminal', true)
223+
->assertJsonPath('data.0.detail_action.label', 'Run Detail')
224+
->assertJsonPath('data.0.detail_action.available', true)
225+
->assertJsonPath('data.0.detail_action.history_available', false)
226+
->assertJsonPath('data.0.detail_action.unavailable_label', 'No typed history');
223227

224228
$this->get('/waterline/api/flows/cancelled')
225229
->assertStatus(200)

0 commit comments

Comments
 (0)