Skip to content

Commit 2c21828

Browse files
committed
Cleanup ExecutionDetails
1 parent 44309e3 commit 2c21828

File tree

2 files changed

+107
-154
lines changed

2 files changed

+107
-154
lines changed

src/components/shared/ExecutionDetails/ExecutionDetails.tsx

Lines changed: 106 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
import { ChevronsUpDown, ExternalLink } from "lucide-react";
1+
import { useMemo } from "react";
22

33
import type { GetContainerExecutionStateResponse } from "@/api/types.gen";
4-
import { Button } from "@/components/ui/button";
5-
import {
6-
Collapsible,
7-
CollapsibleContent,
8-
CollapsibleTrigger,
9-
} from "@/components/ui/collapsible";
10-
import { Link } from "@/components/ui/link";
4+
import { BlockStack, InlineStack } from "@/components/ui/layout";
115
import { Skeleton } from "@/components/ui/skeleton";
126
import { useBackend } from "@/providers/BackendProvider";
137
import { useFetchContainerExecutionState } from "@/services/executionService";
@@ -18,16 +12,23 @@ import {
1812
import { EXIT_CODE_OOM } from "@/utils/constants";
1913
import { formatDate, formatDuration } from "@/utils/date";
2014

15+
import { ContentBlock } from "../ContextPanel/Blocks/ContentBlock";
16+
import {
17+
ListBlock,
18+
type ListBlockItemProps,
19+
} from "../ContextPanel/Blocks/ListBlock";
2120
import { InfoBox } from "../InfoBox";
2221

2322
interface ExecutionDetailsProps {
2423
executionId: string;
2524
componentSpec?: ComponentSpec;
25+
className?: string;
2626
}
2727

2828
export const ExecutionDetails = ({
2929
executionId,
3030
componentSpec,
31+
className,
3132
}: ExecutionDetailsProps) => {
3233
const { backendUrl } = useBackend();
3334

@@ -38,155 +39,106 @@ export const ExecutionDetails = ({
3839
data: containerState,
3940
isLoading: isLoadingContainerState,
4041
error: containerStateError,
41-
} = useFetchContainerExecutionState(executionId || "", backendUrl);
42-
43-
// Don't render if no execution data is available
44-
const hasExecutionData =
45-
executionId ||
46-
containerState ||
47-
isLoadingContainerState ||
48-
containerStateError;
49-
if (!hasExecutionData) {
50-
return null;
51-
}
42+
} = useFetchContainerExecutionState(executionId, backendUrl);
43+
44+
const loadingMarkup = (
45+
<BlockStack gap="2">
46+
<InlineStack gap="2" blockAlign="center">
47+
<Skeleton className="h-3 w-12" />
48+
<Skeleton className="h-3 w-32" />
49+
</InlineStack>
50+
<InlineStack gap="2" blockAlign="center">
51+
<Skeleton className="h-3 w-20" />
52+
<Skeleton className="h-3 w-24" />
53+
<Skeleton className="h-3 w-40" />
54+
</InlineStack>
55+
</BlockStack>
56+
);
5257

53-
const podName = executionPodName(containerState);
54-
const executionJobLinks = getExecutionJobLinks(containerState);
58+
const executionItems = useMemo(() => {
59+
const items: ListBlockItemProps[] = [
60+
{ name: "Execution ID", value: executionId },
61+
];
62+
63+
if (isSubgraph) {
64+
return items;
65+
}
66+
67+
if (containerState?.exit_code && containerState.exit_code > 0) {
68+
const exitCodeValue =
69+
containerState.exit_code === EXIT_CODE_OOM
70+
? `${containerState.exit_code} (Out of Memory)`
71+
: `${containerState.exit_code}`;
72+
73+
items.push({
74+
name: "Exit Code",
75+
value: exitCodeValue,
76+
critical: true,
77+
});
78+
}
79+
80+
if (containerState?.started_at) {
81+
items.push({
82+
name: "Started",
83+
value: formatDate(containerState.started_at),
84+
});
85+
}
86+
87+
if (containerState?.ended_at && containerState?.started_at) {
88+
items.push({
89+
name: "Completed in",
90+
value: `${formatDuration(
91+
containerState.started_at,
92+
containerState.ended_at,
93+
)} (${formatDate(containerState.ended_at)})`,
94+
});
95+
}
96+
97+
const podName = executionPodName(containerState);
98+
if (podName) {
99+
items.push({ name: "Pod Name", value: podName });
100+
}
101+
102+
const executionJobLinks = getExecutionJobLinks(containerState);
103+
if (executionJobLinks) {
104+
executionJobLinks.forEach((linkInfo) => {
105+
if (!linkInfo.url) {
106+
return;
107+
}
108+
109+
items.push({
110+
name: linkInfo.name,
111+
value: { text: linkInfo.value, href: linkInfo.url },
112+
});
113+
});
114+
}
115+
116+
return items;
117+
}, [executionId, isSubgraph, containerState]);
55118

56119
return (
57-
<div className="flex flex-col px-3 py-2">
58-
<Collapsible defaultOpen>
59-
<div className="font-medium text-sm text-foreground flex items-center gap-1">
60-
Execution Details
61-
<CollapsibleTrigger asChild>
62-
<Button variant="ghost" size="sm">
63-
<ChevronsUpDown className="h-4 w-4" />
64-
<span className="sr-only">Toggle</span>
65-
</Button>
66-
</CollapsibleTrigger>
67-
</div>
68-
69-
<CollapsibleContent className="mt-2 space-y-2">
70-
<div className="flex items-center gap-2">
71-
<span className="font-medium text-xs text-foreground min-w-fit">
72-
Execution ID:
73-
</span>
74-
<span className="text-xs text-muted-foreground font-mono truncate">
75-
{executionId}
76-
</span>
77-
</div>
78-
79-
{!isSubgraph && (
80-
<>
81-
{isLoadingContainerState && (
82-
<div className="space-y-2">
83-
<div className="flex items-center gap-2">
84-
<Skeleton className="h-3 w-12" />
85-
<Skeleton className="h-3 w-32" />
86-
</div>
87-
<div className="flex items-center gap-2">
88-
<Skeleton className="h-3 w-20" />
89-
<Skeleton className="h-3 w-24" />
90-
<Skeleton className="h-3 w-40" />
91-
</div>
92-
</div>
93-
)}
94-
95-
{containerStateError && (
96-
<InfoBox title="Failed to load container state" variant="error">
97-
{containerStateError.message}
98-
</InfoBox>
99-
)}
100-
101-
{!!containerState?.exit_code && (
102-
<div className="flex flex-wrap items-center gap-1">
103-
<span className="font-medium text-xs text-destructive">
104-
Exit Code:
105-
</span>
106-
<span className="text-xs text-destructive">
107-
{containerState.exit_code}
108-
</span>
109-
{containerState.exit_code === EXIT_CODE_OOM && (
110-
<span className="text-xs text-destructive">
111-
(Out of Memory)
112-
</span>
113-
)}
114-
</div>
115-
)}
116-
117-
{containerState?.started_at && (
118-
<div className="flex items-center gap-2">
119-
<span className="font-medium text-xs text-foreground min-w-fit">
120-
Started:
121-
</span>
122-
<span className="text-xs text-muted-foreground">
123-
{formatDate(containerState.started_at)}
124-
</span>
125-
</div>
126-
)}
127-
128-
{containerState?.ended_at && containerState?.started_at && (
129-
<div className="flex items-center gap-2">
130-
<span className="font-medium text-xs text-foreground min-w-fit">
131-
Completed in:
132-
</span>
133-
<span className="text-xs text-muted-foreground">
134-
{formatDuration(
135-
containerState.started_at,
136-
containerState.ended_at,
137-
)}
138-
</span>
139-
<span className="text-xs text-muted-foreground">
140-
({formatDate(containerState.ended_at)})
141-
</span>
142-
</div>
143-
)}
144-
145-
{podName && (
146-
<div className="flex items-center gap-2">
147-
<span className="font-medium text-xs text-foreground min-w-fit">
148-
Pod Name:
149-
</span>
150-
<span className="text-xs text-muted-foreground">
151-
{podName}
152-
</span>
153-
</div>
154-
)}
155-
{executionJobLinks && (
156-
<>
157-
{executionJobLinks.map((linkInfo) => (
158-
<div
159-
key={linkInfo.name}
160-
className="flex text-xs items-center gap-2"
161-
>
162-
<span className="font-medium text-foreground min-w-fit">
163-
{linkInfo.name}:
164-
</span>
165-
<Link
166-
href={linkInfo.url}
167-
target="_blank"
168-
rel="noopener noreferrer"
169-
>
170-
{linkInfo.value}
171-
<ExternalLink className="size-3 shrink-0" />
172-
</Link>
173-
</div>
174-
))}
175-
</>
176-
)}
177-
178-
{!isLoadingContainerState &&
179-
!containerState &&
180-
!containerStateError && (
181-
<div className="text-xs text-muted-foreground">
182-
Container state not available
183-
</div>
184-
)}
185-
</>
186-
)}
187-
</CollapsibleContent>
188-
</Collapsible>
189-
</div>
120+
<ContentBlock
121+
title="Execution Details"
122+
collapsible
123+
defaultOpen
124+
className={className}
125+
>
126+
<BlockStack gap="2">
127+
<ListBlock items={executionItems} marker="none" />
128+
129+
{!isSubgraph && isLoadingContainerState && loadingMarkup}
130+
131+
{!isSubgraph && containerStateError && (
132+
<InfoBox
133+
title="Failed to load container state"
134+
variant="error"
135+
className="wrap-anywhere"
136+
>
137+
{containerStateError.message}
138+
</InfoBox>
139+
)}
140+
</BlockStack>
141+
</ContentBlock>
190142
);
191143
};
192144

src/components/shared/TaskDetails/Details.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ const TaskDetails = ({
169169
<ExecutionDetails
170170
executionId={executionId}
171171
componentSpec={componentSpec}
172+
className="px-3 py-2"
172173
/>
173174
)}
174175

0 commit comments

Comments
 (0)