Skip to content

Commit af70e19

Browse files
committed
feat: wire up backlinks
1 parent 9695ffa commit af70e19

File tree

10 files changed

+269
-173
lines changed

10 files changed

+269
-173
lines changed

api-contracts/openapi/components/schemas/v2/task.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ V2Task:
136136
errorMessage:
137137
type: string
138138
description: The error message of the task run (for the latest run)
139+
workflowRunExternalId:
140+
type: string
141+
description: The external ID of the workflow run.
142+
format: uuid
143+
minLength: 36
144+
maxLength: 36
139145
required:
140146
- metadata
141147
- id

api/v1/server/handlers/v2/tasks/get.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import (
1111
func (t *TasksService) V2TaskGet(ctx echo.Context, request gen.V2TaskGetRequestObject) (gen.V2TaskGetResponseObject, error) {
1212
task := ctx.Get("task").(*timescalev2.V2TasksOlap)
1313

14-
taskWithData, err := t.config.EngineRepository.OLAP().ReadTaskRunData(ctx.Request().Context(), task.TenantID, task.ID, task.InsertedAt)
14+
taskWithData, workflowRunExternalId, err := t.config.EngineRepository.OLAP().ReadTaskRunData(ctx.Request().Context(), task.TenantID, task.ID, task.InsertedAt)
1515

1616
if err != nil {
1717
return nil, err
1818
}
1919

20-
result := transformers.ToTask(taskWithData)
20+
result := transformers.ToTask(taskWithData, workflowRunExternalId)
2121

2222
return gen.V2TaskGet200JSONResponse(
2323
result,

api/v1/server/oas/gen/openapi.gen.go

Lines changed: 144 additions & 141 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1/server/oas/transformers/v2/tasks.go

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ func ToTaskRunMetrics(metrics *[]olap.TaskRunMetric) gen.V2TaskRunMetrics {
217217
return toReturn
218218
}
219219

220-
func ToTask(taskWithData *timescalev2.PopulateSingleTaskRunDataRow) gen.V2Task {
220+
func ToTask(taskWithData *timescalev2.PopulateSingleTaskRunDataRow, workflowRunExternalId *pgtype.UUID) gen.V2Task {
221221
additionalMetadata := jsonToMap(taskWithData.AdditionalMetadata)
222222

223223
var finishedAt *time.Time
@@ -246,25 +246,33 @@ func ToTask(taskWithData *timescalev2.PopulateSingleTaskRunDataRow) gen.V2Task {
246246
output = &outputStr
247247
}
248248

249+
var parsedWorkflowRunUUID *uuid.UUID
250+
251+
if workflowRunExternalId != nil && workflowRunExternalId.Valid {
252+
id := uuid.MustParse(sqlchelpers.UUIDToStr(*workflowRunExternalId))
253+
parsedWorkflowRunUUID = &id
254+
}
255+
249256
return gen.V2Task{
250257
Metadata: gen.APIResourceMeta{
251258
Id: sqlchelpers.UUIDToStr(taskWithData.ExternalID),
252259
CreatedAt: taskWithData.InsertedAt.Time,
253260
UpdatedAt: taskWithData.InsertedAt.Time,
254261
},
255-
TaskId: int(taskWithData.ID),
256-
TaskInsertedAt: taskWithData.InsertedAt.Time,
257-
DisplayName: taskWithData.DisplayName,
258-
AdditionalMetadata: &additionalMetadata,
259-
Duration: durationPtr,
260-
StartedAt: startedAt,
261-
FinishedAt: finishedAt,
262-
Output: output,
263-
Status: gen.V2TaskStatus(taskWithData.Status),
264-
Input: string(taskWithData.Input),
265-
TenantId: uuid.MustParse(sqlchelpers.UUIDToStr(taskWithData.TenantID)),
266-
WorkflowId: uuid.MustParse(sqlchelpers.UUIDToStr(taskWithData.WorkflowID)),
267-
ErrorMessage: &taskWithData.ErrorMessage.String,
262+
TaskId: int(taskWithData.ID),
263+
TaskInsertedAt: taskWithData.InsertedAt.Time,
264+
DisplayName: taskWithData.DisplayName,
265+
AdditionalMetadata: &additionalMetadata,
266+
Duration: durationPtr,
267+
StartedAt: startedAt,
268+
FinishedAt: finishedAt,
269+
Output: output,
270+
Status: gen.V2TaskStatus(taskWithData.Status),
271+
Input: string(taskWithData.Input),
272+
TenantId: uuid.MustParse(sqlchelpers.UUIDToStr(taskWithData.TenantID)),
273+
WorkflowId: uuid.MustParse(sqlchelpers.UUIDToStr(taskWithData.WorkflowID)),
274+
ErrorMessage: &taskWithData.ErrorMessage.String,
275+
WorkflowRunExternalId: parsedWorkflowRunUUID,
268276
}
269277
}
270278

frontend/app/src/lib/api/generated/data-contracts.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,13 @@ export interface V2Task {
186186
output?: string;
187187
/** The error message of the task run (for the latest run) */
188188
errorMessage?: string;
189+
/**
190+
* The external ID of the workflow run.
191+
* @format uuid
192+
* @minLength 36
193+
* @maxLength 36
194+
*/
195+
workflowRunExternalId?: string;
189196
}
190197

191198
export enum V2TaskEventType {

frontend/app/src/pages/main/workflow-runs-v2/$run/v2components/step-run-detail/step-run-detail.tsx

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import {
33
StepRun,
44
StepRunStatus,
5+
V2Task,
56
V2TaskStatus,
67
WorkflowRun,
78
queries,
@@ -48,6 +49,36 @@ export const STEP_RUN_TERMINAL_STATUSES = [
4849
StepRunStatus.SUCCEEDED,
4950
];
5051

52+
const TaskRunPermalinkOrBacklink = ({
53+
taskRun,
54+
showViewTaskRunButton,
55+
}: {
56+
taskRun: V2Task;
57+
showViewTaskRunButton: boolean;
58+
}) => {
59+
if (showViewTaskRunButton) {
60+
return (
61+
<Link to={`/task-runs/${taskRun.metadata.id}`}>
62+
<Button size={'sm'} className="px-2 py-2 gap-2" variant={'outline'}>
63+
<LinkIcon className="w-4 h-4" />
64+
View Task Run
65+
</Button>
66+
</Link>
67+
);
68+
} else if (taskRun.workflowRunExternalId) {
69+
return (
70+
<Link to={`/workflow-runs/${taskRun.workflowRunExternalId}`}>
71+
<Button size={'sm'} className="px-2 py-2 gap-2" variant={'outline'}>
72+
<LinkIcon className="w-4 h-4" />
73+
View Workflow Run
74+
</Button>
75+
</Link>
76+
);
77+
} else {
78+
return null;
79+
}
80+
};
81+
5182
const StepRunDetail: React.FC<StepRunDetailProps> = ({
5283
taskRunId,
5384
defaultOpenTab = TabOption.Output,
@@ -121,18 +152,10 @@ const StepRunDetail: React.FC<StepRunDetailProps> = ({
121152
<XCircleIcon className="w-4 h-4" />
122153
Cancel
123154
</Button>
124-
<Link
125-
to={
126-
showViewTaskRunButton
127-
? `/task-runs/${taskRunId}`
128-
: `/workflow-runs/${taskRunId}`
129-
}
130-
>
131-
<Button size={'sm'} className="px-2 py-2 gap-2" variant={'outline'}>
132-
<LinkIcon className="w-4 h-4" />
133-
View Task Run
134-
</Button>
135-
</Link>
155+
<TaskRunPermalinkOrBacklink
156+
taskRun={taskRun}
157+
showViewTaskRunButton={showViewTaskRunButton || false}
158+
/>
136159
</div>
137160
<div className="flex flex-row gap-2 items-center">
138161
<V2StepRunSummary taskRunId={taskRunId} />

pkg/client/rest/gen.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/repository/olap.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ type WorkflowRunData struct {
9393
type OLAPEventRepository interface {
9494
ReadTaskRun(ctx context.Context, taskExternalId string) (*timescalev2.V2TasksOlap, error)
9595
ReadWorkflowRun(ctx context.Context, tenantId, workflowRunExternalId pgtype.UUID) (*WorkflowRunData, []TaskMetadata, error)
96-
ReadTaskRunData(ctx context.Context, tenantId pgtype.UUID, taskId int64, taskInsertedAt pgtype.Timestamptz) (*timescalev2.PopulateSingleTaskRunDataRow, error)
96+
ReadTaskRunData(ctx context.Context, tenantId pgtype.UUID, taskId int64, taskInsertedAt pgtype.Timestamptz) (*timescalev2.PopulateSingleTaskRunDataRow, *pgtype.UUID, error)
9797
ListTasks(ctx context.Context, tenantId string, opts ListTaskRunOpts) ([]*timescalev2.PopulateTaskRunDataRow, int, error)
9898
ListWorkflowRuns(ctx context.Context, tenantId string, opts ListWorkflowRunOpts) ([]*WorkflowRunData, int, error)
9999
ListTaskRunEvents(ctx context.Context, tenantId string, taskId int64, taskInsertedAt pgtype.Timestamptz, limit, offset int64) ([]*timescalev2.ListTaskEventsRow, error)
@@ -352,12 +352,30 @@ func (r *olapEventRepository) ReadWorkflowRun(ctx context.Context, tenantId, wor
352352
}, taskMetadata, nil
353353
}
354354

355-
func (r *olapEventRepository) ReadTaskRunData(ctx context.Context, tenantId pgtype.UUID, taskId int64, taskInsertedAt pgtype.Timestamptz) (*timescalev2.PopulateSingleTaskRunDataRow, error) {
356-
return r.queries.PopulateSingleTaskRunData(ctx, r.pool, timescalev2.PopulateSingleTaskRunDataParams{
355+
func (r *olapEventRepository) ReadTaskRunData(ctx context.Context, tenantId pgtype.UUID, taskId int64, taskInsertedAt pgtype.Timestamptz) (*timescalev2.PopulateSingleTaskRunDataRow, *pgtype.UUID, error) {
356+
taskRun, err := r.queries.PopulateSingleTaskRunData(ctx, r.pool, timescalev2.PopulateSingleTaskRunDataParams{
357357
Taskid: taskId,
358358
Tenantid: tenantId,
359359
Taskinsertedat: taskInsertedAt,
360360
})
361+
362+
if err != nil {
363+
return nil, nil, err
364+
}
365+
366+
dagId := taskRun.DagID.Int64
367+
dagInsertedAt := taskRun.DagInsertedAt
368+
369+
workflowRunId, err := r.queries.GetWorkflowRunIdFromDagIdInsertedAt(ctx, r.pool, timescalev2.GetWorkflowRunIdFromDagIdInsertedAtParams{
370+
Dagid: dagId,
371+
Daginsertedat: dagInsertedAt,
372+
})
373+
374+
if err != nil {
375+
return nil, nil, err
376+
}
377+
378+
return taskRun, &workflowRunId, nil
361379
}
362380

363381
func (r *olapEventRepository) ListTasks(ctx context.Context, tenantId string, opts ListTaskRunOpts) ([]*timescalev2.PopulateTaskRunDataRow, int, error) {

pkg/repository/v2/timescalev2/queries.sql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -953,4 +953,12 @@ SELECT
953953
FROM runs r
954954
LEFT JOIN metadata m ON r.run_id = m.run_id
955955
LEFT JOIN error_message e ON r.run_id = e.run_id
956-
ORDER BY r.inserted_at DESC, r.run_id DESC;
956+
ORDER BY r.inserted_at DESC, r.run_id DESC;
957+
958+
-- name: GetWorkflowRunIdFromDagIdInsertedAt :one
959+
SELECT external_id
960+
FROM v2_dags_olap
961+
WHERE
962+
id = @dagId::bigint
963+
AND inserted_at = @dagInsertedAt::timestamptz
964+
;

pkg/repository/v2/timescalev2/queries.sql.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)