Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display Status of latest run in Editor #40

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
6 changes: 4 additions & 2 deletions admyral/server/endpoints/workflow_run_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@

@router.get("/{workflow_id}", status_code=status.HTTP_200_OK)
async def list_workflow_runs(
workflow_id: str, authenticated_user: AuthenticatedUser = Depends(authenticate)
workflow_id: str,
limit: int | None = 100,
authenticated_user: AuthenticatedUser = Depends(authenticate),
leon-schmid marked this conversation as resolved.
Show resolved Hide resolved
) -> list[WorkflowRunMetadata]:
"""
List all workflow runs.
Expand All @@ -27,7 +29,7 @@ async def list_workflow_runs(
A list of workflow runs.
"""
return await get_admyral_store().list_workflow_runs(
authenticated_user.user_id, workflow_id
authenticated_user.user_id, workflow_id, limit=limit
)


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useListWorkflowRunsApi } from "@/hooks/use-list-workflow-runs-api";
import { Flex } from "@radix-ui/themes";
import { useEffect, useState } from "react";
import type { TWorkflowRunMetadata } from "@/types/workflow-runs";
import WorkflowRunStatusIndicator from "./workflow-run-status-indicator";

export function WorkflowRunStatus({ workflowId }: { workflowId: string }) {
const { data, isPending, error } = useListWorkflowRunsApi(workflowId, 1);
const [latestRun, setLatestRun] = useState<TWorkflowRunMetadata>();

useEffect(() => {
if (data && data.length > 0) {
setLatestRun(data[0]);
}
}, [data]);

if (error || isPending || !latestRun) {
return null;
}

return (
<Flex align="center" gap="2" height="25px">
<WorkflowRunStatusIndicator workflowRun={latestRun} />
</Flex>
);
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,26 @@
import { useListWorkflowRunsApi } from "@/hooks/use-list-workflow-runs-api";
import { useToast } from "@/providers/toast";
import { Box, Flex, Spinner, ScrollArea, Text } from "@radix-ui/themes";
import { Box, Flex, ScrollArea, Text } from "@radix-ui/themes";
import { useEffect, useState } from "react";
import WorkflowRunTrace from "./workflow-run-trace";
import Row from "./row";
import ErrorCallout from "@/components/utils/error-callout";
import { CheckCircledIcon, CrossCircledIcon } from "@radix-ui/react-icons";
import { TWorkflowRunMetadata } from "@/types/workflow-runs";
import WorkflowRunStatusIndicator from "./workflow-run-status-indicator";

function WorkflowRunRow({
workflowRun: { createdAt, failedAt, completedAt },
workflowRun,
}: {
workflowRun: TWorkflowRunMetadata;
}) {
if (failedAt === null && completedAt === null) {
// In Progress
return (
<Flex align="center" justify="between" width="100%">
<Text size="1">{createdAt}</Text>
<Spinner size="1" />
</Flex>
);
}

if (completedAt === null) {
// Failure
return (
<Flex align="center" justify="between" width="100%">
<Text size="1">{createdAt}</Text>
<CrossCircledIcon color="red" />
</Flex>
);
}
const createdAtAsReadableString = new Date(
workflowRun.createdAt,
).toLocaleString("en-US");

// Success
return (
<Flex align="center" justify="between" width="100%">
<Text size="1">{createdAt}</Text>
<CheckCircledIcon color="green" />
<Text size="1">{createdAtAsReadableString}</Text>
<WorkflowRunStatusIndicator workflowRun={workflowRun} />
</Flex>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Spinner, Flex } from "@radix-ui/themes";
import { CheckCircledIcon, CrossCircledIcon } from "@radix-ui/react-icons";
import type { TWorkflowRunMetadata } from "@/types/workflow-runs";

export default function WorkflowRunStatusIndicator({
workflowRun: { failedAt, completedAt },
}: {
workflowRun: TWorkflowRunMetadata;
}) {
if (failedAt === null && completedAt === null) {
// In Progress
return (
<Flex align="center" gap="2">
<Spinner size="1" aria-label="Workflow run in progress" />
</Flex>
);
}

if (completedAt === null) {
// Failure
return (
<Flex align="center" gap="2">
<CrossCircledIcon
color="red"
aria-label="Workflow run failed"
/>
</Flex>
);
}

// Success
return (
<Flex align="center" gap="2">
<CheckCircledIcon
color="green"
aria-label="Workflow run succeeded"
/>
</Flex>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,18 @@ export default function WorkflowRunTrace({
selected={idx === selectedStepIdx}
onClickOnUnselectedRow={() => handleClickStep(idx)}
>
<Flex align="center" justify="between" width="100%">
<ActionIcon
actionType={workflowStep.actionType}
/>
<Flex align="center" width="100%" gap="2">
<Flex
width="24px"
height="24px"
justify="center"
>
<ActionIcon
actionType={workflowStep.actionType}
/>
</Flex>
<Flex align="center" justify="center" gap="1">
<Text size="1">
<Text size="1" align="left">
{workflowStep.actionType === "start"
? "Start"
: actionsIndex[
Expand Down
36 changes: 21 additions & 15 deletions web/src/components/workflow-editor/workflow-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { AxiosError } from "axios";
import { useRouter } from "next/navigation";
import { SaveWorkflowProvider } from "@/providers/save-workflow";
import NewWorkflowModal from "./new-workflow-modal";
import { WorkflowRunStatus } from "./run-history/latest-workflow-run-status";

type View = "workflowBuilder" | "runHistory";

Expand Down Expand Up @@ -162,7 +163,7 @@ export default function WorkflowEditor({
pt="2"
pl="4"
pr="4"
columns="1fr 200px 1fr"
columns="1fr auto 1fr"
className="border-b-2 border-gray-200"
align="center"
height="56px"
Expand All @@ -188,20 +189,25 @@ export default function WorkflowEditor({
value={view}
onValueChange={(page) => setView(page as View)}
>
<Tabs.List size="1">
<Tabs.Trigger
value="workflowBuilder"
style={{ cursor: "pointer" }}
>
Workflow Builder
</Tabs.Trigger>
<Tabs.Trigger
value="runHistory"
style={{ cursor: "pointer" }}
>
Run History
</Tabs.Trigger>
</Tabs.List>
<Flex align="center">
<Tabs.List size="1">
<Tabs.Trigger
value="workflowBuilder"
style={{ cursor: "pointer" }}
>
Workflow Builder
</Tabs.Trigger>
<Tabs.Trigger
value="runHistory"
style={{ cursor: "pointer" }}
>
Run History
</Tabs.Trigger>
</Tabs.List>
<WorkflowRunStatus
workflowId={workflowId}
/>
</Flex>
</Tabs.Root>
</Flex>

Expand Down
12 changes: 7 additions & 5 deletions web/src/hooks/use-list-workflow-runs-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { WorkflowRunMetadata } from "@/types/workflow-runs";
import { HTTPMethod } from "@/types/api";

// GET /api/v1/runs/<workflow-id>
const ListWorkflowRunsRequest = z.void();
const ListWorkflowRunsRequest = z.object({
limit: z.number().optional(),
});
const ListWorkflowRunsResponse = z.array(WorkflowRunMetadata);

const buildListWorkflowRunsApi = (workflowId: string) =>
const buildListWorkflowRunsApi = (workflowId: string, limit?: number) =>
api<
z.infer<typeof ListWorkflowRunsRequest>,
z.infer<typeof ListWorkflowRunsResponse>
Expand All @@ -23,10 +25,10 @@ const buildListWorkflowRunsApi = (workflowId: string) =>

const REFETCH_INTERVAL_1_SECOND = 1_000; // in ms

export const useListWorkflowRunsApi = (workflowId: string) => {
export const useListWorkflowRunsApi = (workflowId: string, limit?: number) => {
return useQuery({
queryKey: ["workflowRuns", workflowId],
queryFn: () => buildListWorkflowRunsApi(workflowId)(),
queryKey: ["workflowRuns", workflowId, limit],
queryFn: () => buildListWorkflowRunsApi(workflowId, limit)({}),
refetchInterval: REFETCH_INTERVAL_1_SECOND,
});
};
Loading