Skip to content

Commit 1a2a79a

Browse files
improve runs UI
1 parent e06911b commit 1a2a79a

File tree

7 files changed

+98
-68
lines changed

7 files changed

+98
-68
lines changed

frontend/src/components/DagViewer.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,11 @@ export function TaskNode({
7474
<Handle type="source" position={Position.Right} />
7575
)}
7676

77-
{/* The target handle always exists as there's always a trigger that connects to it */}
78-
<Handle type="target" position={Position.Left} />
77+
{/* The target handle exists also if there's a trigger to show (in the run page) */}
78+
{((data.runs?.length ?? 0) > 0 ||
79+
data.task.upstream_task_ids.length > 0) && (
80+
<Handle type="target" position={Position.Left} />
81+
)}
7982

8083
{numberInstances > 1 && (
8184
<div className="absolute -top-2 -left-2 text-xs flex size-5 items-center justify-center rounded-full bg-sky-800 text-white">

frontend/src/components/ManualRunDialog.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@ import { useState } from 'react'
55
import { useNavigate } from 'react-router'
66

77
import { getPipelineInputSchema, runPipeline } from '../repository'
8-
import { Pipeline } from '../types'
8+
import { Pipeline, Trigger } from '../types'
99
import Dialog from './Dialog'
1010
import JsonSchemaForm from './JsonSchemaForm'
11+
import { MANUAL_TRIGGER } from '@/constants'
1112

1213
interface Props {
1314
pipeline: Pipeline
15+
trigger?: Trigger
1416
}
1517

16-
const ManualRunDialog: React.FC<Props> = ({ pipeline }) => {
18+
const ManualRunDialog: React.FC<Props> = ({ pipeline, trigger }) => {
1719
const [open, setOpen] = useState(false)
1820
const navigate = useNavigate()
1921

@@ -22,7 +24,12 @@ const ManualRunDialog: React.FC<Props> = ({ pipeline }) => {
2224
enabled: open,
2325
})
2426

25-
const runPipelineMutation = useMutation(runPipeline(pipeline.id))
27+
const runPipelineMutation = useMutation(
28+
runPipeline(
29+
pipeline.id,
30+
trigger && trigger.id !== MANUAL_TRIGGER.id ? trigger.id : undefined
31+
)
32+
)
2633

2734
const formErrors =
2835
runPipelineMutation.isError && runPipelineMutation.error.status === 422

frontend/src/components/PipelineRunDetails.tsx

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Card, Metric } from '@tremor/react'
1+
import { Card, Metric, Title } from '@tremor/react'
22

33
import StatusBadge from './StatusBadge'
44
import { Pipeline, PipelineRun } from '@/types'
@@ -12,45 +12,50 @@ interface Props {
1212
}
1313

1414
export default function PipelineRunDetails({ pipeline, run }: Props) {
15-
const runEndTime = addMilliseconds(run.start_time, run.duration)
16-
1715
return (
18-
<Card className="p-3">
19-
<div className="flex items-start">
20-
<div className="text-xs">Duration</div>
16+
<Card className="p-3 max-w-[350px]">
17+
<header className="flex items-start gap-4 justify-between">
18+
<Title className="mb-4">{pipeline.name}</Title>
2119
<StatusBadge status={run.status} />
22-
</div>
20+
</header>
2321

24-
<div className="flex justify-start items-baseline space-x-3 truncate">
22+
<div>
23+
<div className="text-xs">Duration</div>
2524
<Metric className="tabular-nums text-lg">
2625
{run.status !== 'running' ? (
2726
formatDuration(run.duration)
28-
) : (
27+
) : run.start_time ? (
2928
<Timer startTime={run.start_time} />
29+
) : (
30+
'-'
3031
)}
3132
</Metric>
3233
</div>
3334

34-
<div className="flex items-start mt-2 gap-4">
35+
<div className="space-y-4 mt-4">
3536
<div>
36-
<p
37-
className="font-medium"
38-
title={formatDateTime(run.start_time, true)}
39-
>
40-
{formatTime(run.start_time)}
41-
</p>
42-
43-
<p className="mt-1">{formatDate(run.start_time)}</p>
37+
<div className="text-xs">Started at</div>
38+
39+
<div className="flex gap-2 justify-between">
40+
<p className="tabular-nums">
41+
{run.start_time ? formatTime(run.start_time) : '-'}
42+
</p>
43+
<p>{run.end_time ? formatDate(run.end_time) : '-'}</p>
44+
</div>
4445
</div>
4546

46-
<div className="text-right">
47-
<p className="font-medium" title={formatDateTime(runEndTime, true)}>
48-
{formatTime(runEndTime)}
47+
<div>
48+
<div className="text-xs">Finished at</div>
49+
50+
<p className="tabular-nums">
51+
{run.end_time ? formatTime(run.end_time) : '-'}
4952
</p>
5053

51-
{!isSameDay(run.start_time, runEndTime) && (
52-
<p>{formatDate(runEndTime)}</p>
53-
)}
54+
{run.start_time &&
55+
run.end_time &&
56+
!isSameDay(run.start_time, run.end_time) && (
57+
<p>{formatDate(run.end_time)}</p>
58+
)}
5459
</div>
5560
</div>
5661
</Card>

frontend/src/components/TaskRunDetails.tsx

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,71 +19,75 @@ export default function TaskRunDetails({ pipeline, runs }: Props) {
1919

2020
const run = runs[0]
2121

22-
const runEndTime = addMilliseconds(run.start_time, run.duration)
2322
const mapping_index = runs.length > 1 ? `[${run.map_index}]` : ''
2423

2524
return (
26-
<Card className="p-3">
25+
<Card className="p-3 max-w-[350px]">
2726
<DataViewerDialog
2827
runId={run.id}
2928
taskId={viewDataDialog || ''}
3029
open={!!viewDataDialog}
3130
onClose={() => setViewDataDialog(undefined)}
3231
/>
3332

34-
<Title>
35-
{run.task_id}
36-
{mapping_index}
37-
</Title>
38-
39-
<div className="flex items-start">
40-
<div className="text-xs">Duration</div>
33+
<header className="flex items-start gap-4 justify-between">
34+
<Title className="mb-4">
35+
{run.task_id}
36+
{mapping_index}
37+
</Title>
4138
<StatusBadge status={run.status} />
42-
</div>
39+
</header>
4340

44-
<div className="flex justify-start items-baseline space-x-3 truncate">
41+
<div>
42+
<div className="text-xs">Duration</div>
4543
<Metric className="tabular-nums text-lg">
4644
{run.status !== 'running' ? (
4745
formatDuration(run.duration)
48-
) : (
46+
) : run.start_time ? (
4947
<Timer startTime={run.start_time} />
48+
) : (
49+
'-'
5050
)}
5151
</Metric>
5252
</div>
5353

54-
<div className="flex items-start mt-2 gap-4">
54+
<div className="space-y-4 mt-4">
5555
<div>
56-
<p
57-
className="font-medium"
58-
title={formatDateTime(run.start_time, true)}
59-
>
60-
{formatTime(run.start_time)}
61-
</p>
56+
<div className="text-xs">Started at</div>
6257

63-
<p className="mt-1">{formatDate(run.start_time)}</p>
58+
<div className="flex gap-2 justify-between">
59+
<p className="tabular-nums">
60+
{run.start_time ? formatTime(run.start_time) : '-'}
61+
</p>
62+
<p>{run.end_time ? formatDate(run.end_time) : '-'}</p>
63+
</div>
6464
</div>
6565

66-
<div className="text-right">
67-
<p className="font-medium" title={formatDateTime(runEndTime, true)}>
68-
{formatTime(runEndTime)}
66+
<div>
67+
<div className="text-xs">Finished at</div>
68+
69+
<p className="tabular-nums">
70+
{run.end_time ? formatTime(run.end_time) : '-'}
6971
</p>
7072

71-
{!isSameDay(run.start_time, runEndTime) && (
72-
<p>{formatDate(runEndTime)}</p>
73-
)}
73+
{run.start_time &&
74+
run.end_time &&
75+
!isSameDay(run.start_time, run.end_time) && (
76+
<p>{formatDate(run.end_time)}</p>
77+
)}
7478
</div>
7579
</div>
7680

7781
{run?.task_output_id && (
7882
<Button
79-
variant="light"
83+
variant="secondary"
8084
color="indigo"
8185
size="xs"
8286
icon={TableCellsIcon}
83-
tooltip="View task output data"
8487
onClick={() => setViewDataDialog(run.task_output_id)}
88+
className="w-full mt-4"
8589
>
86-
View data
90+
View output data
8791
</Button>
8892
)}
8993
</Card>

frontend/src/pages/pipelines/[pipelineId]/triggers/[triggerId]/runs/[runId]/index.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { socket } from '@/socket'
1212
import { Trigger } from '@/types'
1313
import DagViewer from '@/components/DagViewer'
1414
import DagDetailsPanel from '@/components/DagDetailsPanel'
15+
import ManualRunDialog from '@/components/ManualRunDialog'
1516

1617
const RunViewPage = () => {
1718
const queryClient = useQueryClient()
@@ -63,10 +64,14 @@ const RunViewPage = () => {
6364
return (
6465
<PageLayout
6566
header={
66-
<>
67-
<Title>Run #{runId}</Title>
68-
<Breadcrumbs pipeline={pipeline} trigger={trigger} run={run} />
69-
</>
67+
<div className="flex gap-4 items-start justify-between">
68+
<div>
69+
<Title>Run #{runId}</Title>
70+
<Breadcrumbs pipeline={pipeline} trigger={trigger} run={run} />
71+
</div>
72+
73+
<ManualRunDialog pipeline={pipeline} trigger={trigger} />
74+
</div>
7075
}
7176
>
7277
<Grid numItemsMd={2} className="gap-6 mt-6">

frontend/src/repository.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ export const listRuns = (
188188
})
189189

190190
runs.forEach((run) => {
191-
run.start_time = new Date(run.start_time)
191+
run.start_time = run.start_time ? new Date(run.start_time) : undefined
192+
run.end_time = run.end_time ? new Date(run.end_time) : undefined
192193
})
193194

194195
return runs as PipelineRun[]
@@ -208,8 +209,12 @@ export const getRun = (
208209
run.end_time = new Date(run.end_time)
209210

210211
run.task_runs.forEach((taskRun: any) => {
211-
taskRun.start_time = new Date(taskRun.start_time)
212-
taskRun.end_time = new Date(taskRun.end_time)
212+
taskRun.start_time = taskRun.start_time
213+
? new Date(taskRun.start_time)
214+
: undefined
215+
taskRun.end_time = taskRun.end_time
216+
? new Date(taskRun.end_time)
217+
: undefined
213218
})
214219

215220
return run as PipelineRun

frontend/src/types.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ export class Pipeline {
6565

6666
export interface TaskRun {
6767
duration: number
68-
start_time: Date
69-
end_time: Date
68+
start_time?: Date
69+
end_time?: Date
7070
id: string
7171
context: any
7272
status: PipelineRunStatus
@@ -81,7 +81,8 @@ export interface PipelineRun {
8181
status: PipelineRunStatus
8282
pipeline_id: string
8383
trigger_id: string
84-
start_time: Date
84+
start_time?: Date
85+
end_time?: Date
8586
duration: number
8687
task_runs: TaskRun[]
8788
input_params: Record<string, any>

0 commit comments

Comments
 (0)