Skip to content

Commit 533c465

Browse files
committed
Cleanup ExecutionDetails
1 parent e6ea5d1 commit 533c465

File tree

2 files changed

+103
-154
lines changed

2 files changed

+103
-154
lines changed

src/components/shared/ExecutionDetails/ExecutionDetails.tsx

Lines changed: 102 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +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";
4+
import { BlockStack, InlineStack } from "@/components/ui/layout";
105
import { Skeleton } from "@/components/ui/skeleton";
116
import { useBackend } from "@/providers/BackendProvider";
127
import { useFetchContainerExecutionState } from "@/services/executionService";
@@ -17,16 +12,23 @@ import {
1712
import { EXIT_CODE_OOM } from "@/utils/constants";
1813
import { formatDate, formatDuration } from "@/utils/date";
1914

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

2222
interface ExecutionDetailsProps {
2323
executionId: string;
2424
componentSpec?: ComponentSpec;
25+
className?: string;
2526
}
2627

2728
export const ExecutionDetails = ({
2829
executionId,
2930
componentSpec,
31+
className,
3032
}: ExecutionDetailsProps) => {
3133
const { backendUrl } = useBackend();
3234

@@ -37,156 +39,102 @@ export const ExecutionDetails = ({
3739
data: containerState,
3840
isLoading: isLoadingContainerState,
3941
error: containerStateError,
40-
} = useFetchContainerExecutionState(executionId || "", backendUrl);
41-
42-
// Don't render if no execution data is available
43-
const hasExecutionData =
44-
executionId ||
45-
containerState ||
46-
isLoadingContainerState ||
47-
containerStateError;
48-
if (!hasExecutionData) {
49-
return null;
50-
}
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+
);
5157

52-
const podName = executionPodName(containerState);
53-
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+
items.push({
106+
name: linkInfo.name,
107+
value: { text: linkInfo.value, href: linkInfo.url },
108+
});
109+
});
110+
}
111+
112+
return items;
113+
}, [executionId, isSubgraph, containerState]);
54114

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

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)