Skip to content

Commit 381472a

Browse files
fix: consistency to steps and runs (#652)
1 parent d0d7b77 commit 381472a

File tree

14 files changed

+377
-170
lines changed

14 files changed

+377
-170
lines changed

src/app/runs/[id]/_Tabs/Configuration/CodeCollapsible.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Props = {
1414
};
1515

1616
export function CodeCollapsible({ runId }: Props) {
17-
const [open, setOpen] = useState(false);
17+
const [open, setOpen] = useState(true);
1818
const runCode = `from zenml.client import Client
1919
run = Client().get_pipeline_run('${runId}')
2020
config = run.config`;

src/app/runs/[id]/_Tabs/Configuration/EnvironmentCollapsible.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Props = {
1414
};
1515

1616
export function EnvironmentCollapsible({ run }: Props) {
17-
const [open, setOpen] = useState(false);
17+
const [open, setOpen] = useState(true);
1818

1919
return (
2020
<CollapsiblePanel open={open} onOpenChange={setOpen}>

src/app/runs/[id]/_Tabs/Configuration/index.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,19 @@ export function ConfigurationTab() {
3131

3232
return (
3333
<div className="grid grid-cols-1 gap-5">
34-
<NestedCollapsible title="Parameters" data={data.metadata?.config.parameters ?? undefined} />
34+
<NestedCollapsible
35+
isInitialOpen
36+
title="Parameters"
37+
data={data.metadata?.config.parameters ?? undefined}
38+
/>
3539
{(buildData?.metadata?.images as BuildItemMap)?.orchestrator && (
3640
<DockerImageCollapsible data={buildData?.metadata?.images?.orchestrator as BuildItem} />
3741
)}
3842
<CodeCollapsible runId={runId} />
3943
<EnvironmentCollapsible run={data} />
40-
<NestedCollapsible title="Extra" data={data.metadata?.config.extra} />
44+
<NestedCollapsible isInitialOpen title="Extra" data={data.metadata?.config.extra} />
4145
<NestedCollapsible
46+
isInitialOpen
4247
title="Resources"
4348
// eslint-disable-next-line @typescript-eslint/no-explicit-any
4449
data={(data.metadata?.config.settings as { [key: string]: any })?.resources || {}}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import File from "@/assets/icons/file.svg?react";
2+
import { EmptyState } from "@/components/EmptyState";
3+
import { MetadataCards, UncategorizedCard } from "@/components/MetadataCards";
4+
import { usePipelineRun } from "@/data/pipeline-runs/pipeline-run-detail-query";
5+
import { MetadataMap } from "@/types/common";
6+
import { Skeleton } from "@zenml-io/react-component-library";
7+
import { useParams } from "react-router-dom";
8+
9+
export function MetadataTab() {
10+
const { runId } = useParams() as { runId: string };
11+
const { data, isError } = usePipelineRun({ runId }, { throwOnError: true });
12+
13+
if (isError) return <p>Failed to fetch pipeline run</p>;
14+
15+
if (data && Object.entries(data.metadata?.run_metadata || {}).length < 1) {
16+
return (
17+
<EmptyState icon={<File className="h-[120px] w-[120px] fill-neutral-300" />}>
18+
<div className="text-center">
19+
<p className="mb-2 text-display-xs font-semibold">No metadata found</p>
20+
<p className="text-text-lg text-theme-text-secondary">There are no metadata available.</p>
21+
</div>
22+
</EmptyState>
23+
);
24+
}
25+
26+
return (
27+
<section className="flex flex-col gap-5">
28+
{data ? (
29+
<UncategorizedCard metadata={data.metadata?.run_metadata as any} />
30+
) : (
31+
<Skeleton className="h-[200px] w-full" />
32+
)}
33+
{data ? (
34+
<MetadataCards metadata={data.metadata?.run_metadata as MetadataMap} />
35+
) : (
36+
<Skeleton className="h-[200px] w-full" />
37+
)}
38+
</section>
39+
);
40+
}

src/app/runs/[id]/_Tabs/Overview/Details.tsx

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ExecutionStatusIcon, getExecutionStatusTagColor } from "@/components/Ex
66
import { InlineAvatar } from "@/components/InlineAvatar";
77
import { Key, Value } from "@/components/KeyValue";
88
import { usePipelineRun } from "@/data/pipeline-runs/pipeline-run-detail-query";
9+
import { calculateTimeDifference } from "@/lib/dates";
910
import { routes } from "@/router/routes";
1011
import {
1112
CollapsibleContent,
@@ -16,7 +17,7 @@ import {
1617
Tag
1718
} from "@zenml-io/react-component-library";
1819
import { useEffect, useState } from "react";
19-
import { useParams, useSearchParams, useNavigate, Link } from "react-router-dom";
20+
import { Link, useNavigate, useParams, useSearchParams } from "react-router-dom";
2021

2122
export function Details() {
2223
const { runId } = useParams() as { runId: string };
@@ -74,21 +75,25 @@ export function Details() {
7475
</Value>
7576
<Key>Pipeline</Key>
7677
<Value>
77-
<Link
78-
to={routes.pipelines.namespace(
79-
encodeURIComponent(data.body?.pipeline?.name as string)
80-
)}
81-
>
82-
<Tag
83-
color="purple"
84-
className="inline-flex items-center gap-0.5"
85-
rounded={false}
86-
emphasis="subtle"
78+
{data.body?.pipeline ? (
79+
<Link
80+
to={routes.pipelines.namespace(
81+
encodeURIComponent(data.body?.pipeline?.name as string)
82+
)}
8783
>
88-
<Pipelines className="h-4 w-4 fill-theme-text-brand" />
89-
{data.body?.pipeline?.name}
90-
</Tag>
91-
</Link>
84+
<Tag
85+
color="purple"
86+
className="inline-flex items-center gap-0.5"
87+
rounded={false}
88+
emphasis="subtle"
89+
>
90+
<Pipelines className="h-4 w-4 fill-theme-text-brand" />
91+
{data.body?.pipeline?.name}
92+
</Tag>
93+
</Link>
94+
) : (
95+
"Not available"
96+
)}
9297
</Value>
9398
<Key>Author</Key>
9499
<Value>
@@ -112,6 +117,12 @@ export function Details() {
112117
"Not available"
113118
)}
114119
</Value>
120+
<Key>Duration</Key>
121+
<Value>
122+
{data.metadata?.start_time && data.metadata?.end_time
123+
? calculateTimeDifference(data.metadata?.start_time, data.metadata?.end_time)
124+
: "Not available"}
125+
</Value>
115126
</dl>
116127
</CollapsibleContent>
117128
</CollapsiblePanel>
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import ChevronDown from "@/assets/icons/chevron-down.svg?react";
2+
import Info from "@/assets/icons/info.svg?react";
3+
import { Codesnippet } from "@/components/CodeSnippet";
4+
import { CopyButton } from "@/components/CopyButton";
5+
import { Key, Value } from "@/components/KeyValue";
6+
import { RepoBadge } from "@/components/repositories/RepoBadge";
7+
import { usePipelineRun } from "@/data/pipeline-runs/pipeline-run-detail-query";
8+
import { Metadata, MetadataMap } from "@/types/common";
9+
import {
10+
CollapsibleContent,
11+
CollapsibleHeader,
12+
CollapsiblePanel,
13+
CollapsibleTrigger,
14+
Tooltip,
15+
TooltipContent,
16+
TooltipProvider,
17+
TooltipTrigger
18+
} from "@zenml-io/react-component-library/components/client";
19+
import { Skeleton } from "@zenml-io/react-component-library/components/server";
20+
import { useState } from "react";
21+
import { useParams } from "react-router-dom";
22+
23+
export function InfoCollapsible() {
24+
const { runId } = useParams() as { runId: string };
25+
26+
const [open, setOpen] = useState(true);
27+
const { data, isError, isPending } = usePipelineRun({ runId });
28+
29+
const orchestrator_url: Metadata | undefined = (data?.metadata?.run_metadata as MetadataMap)
30+
?.orchestrator_url;
31+
const orchestrator_run_id = data?.metadata?.orchestrator_run_id;
32+
33+
if (isError) return null;
34+
if (isPending) return <Skeleton className="h-[200px]" />;
35+
36+
return (
37+
<CollapsiblePanel open={open} onOpenChange={setOpen}>
38+
<CollapsibleHeader className="flex items-center gap-[10px]">
39+
<CollapsibleTrigger className="flex w-full">
40+
<ChevronDown
41+
className={` ${
42+
open ? "" : "-rotate-90"
43+
} mr-2 h-5 w-5 rounded-md fill-neutral-500 transition-transform duration-200 hover:bg-neutral-200`}
44+
/>
45+
Info
46+
</CollapsibleTrigger>
47+
</CollapsibleHeader>
48+
<CollapsibleContent className="border-t border-theme-border-moderate bg-theme-surface-primary px-5 py-3">
49+
<dl className="grid grid-cols-1 gap-x-[10px] gap-y-2 md:grid-cols-3 md:gap-y-4">
50+
<Key>Orchestrator URL</Key>
51+
<Value>
52+
{orchestrator_url ? (
53+
<div className="group/copybutton flex items-center gap-0.5">
54+
<a
55+
className="truncate underline transition-all duration-200 hover:decoration-transparent"
56+
rel="noopener noreferrer"
57+
target="_blank"
58+
href={orchestrator_url.body.value}
59+
>
60+
{orchestrator_url.body.value}
61+
</a>
62+
<CopyButton copyText={orchestrator_url.body.value} />
63+
</div>
64+
) : (
65+
"Not available"
66+
)}
67+
</Value>
68+
<Key>Orchestrator Run ID</Key>
69+
<Value>
70+
{orchestrator_run_id ? (
71+
<div className="group/copybutton flex items-center gap-0.5">
72+
{orchestrator_run_id}
73+
<CopyButton copyText={orchestrator_run_id} />
74+
</div>
75+
) : (
76+
"Not available"
77+
)}
78+
</Value>
79+
<Key>
80+
<div className="flex items-center space-x-0.5 truncate">
81+
<span className="truncate">Repository/Commit</span>
82+
<TooltipProvider>
83+
<Tooltip>
84+
<TooltipTrigger className="cursor-default">
85+
<Info className="h-3 w-3 fill-theme-text-secondary" />
86+
<span className="sr-only">Info</span>
87+
</TooltipTrigger>
88+
<TooltipContent className="w-full max-w-md whitespace-normal">
89+
Git hash of code repository. Only set if pipeline was run in a clean git
90+
repository connected to your ZenML server.
91+
</TooltipContent>
92+
</Tooltip>
93+
</TooltipProvider>
94+
</div>
95+
</Key>
96+
<Value>
97+
{data.body?.code_reference ? (
98+
<RepoBadge
99+
repositoryId={data.body?.code_reference.body?.code_repository.id}
100+
commit={data.body.code_reference.body?.commit}
101+
/>
102+
) : (
103+
"Not available"
104+
)}
105+
</Value>
106+
<Key className={data.metadata?.code_path ? "col-span-3" : ""}>
107+
<div className="flex items-center space-x-0.5 truncate">
108+
<span>Code Path</span>
109+
<TooltipProvider>
110+
<Tooltip>
111+
<TooltipTrigger className="cursor-default">
112+
<Info className="h-3 w-3 fill-theme-text-secondary" />
113+
<span className="sr-only">Info</span>
114+
</TooltipTrigger>
115+
<TooltipContent className="w-full max-w-md whitespace-normal">
116+
Path to where code was uploaded in the artifact store. Only set on a pipeline
117+
with a non-local orchestrator and if Repository/Commit is not set
118+
</TooltipContent>
119+
</Tooltip>
120+
</TooltipProvider>
121+
</div>
122+
</Key>
123+
<Value className={data.metadata?.code_path ? "col-span-3 h-auto" : ""}>
124+
{data.metadata?.code_path ? (
125+
<Codesnippet code={data.metadata.code_path} />
126+
) : (
127+
"Not available"
128+
)}
129+
</Value>
130+
</dl>
131+
</CollapsibleContent>
132+
</CollapsiblePanel>
133+
);
134+
}

src/app/runs/[id]/_Tabs/Overview/Metadata.tsx

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { Details } from "./Details";
2-
import { Metadata } from "./Metadata";
2+
import { InfoCollapsible } from "./Info";
33
import { StackCollapsible } from "./Stack";
44

55
export function OverviewTab() {
66
return (
77
<div className="grid grid-cols-1 gap-5">
88
<Details />
9+
<InfoCollapsible />
910
<StackCollapsible />
10-
<Metadata />
1111
</div>
1212
);
1313
}

src/app/runs/[id]/_Tabs/index.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import MetadataIcon from "@/assets/icons/code-square.svg?react";
12
import Collapse from "@/assets/icons/collapse.svg?react";
23
import Info from "@/assets/icons/info.svg?react";
34
import Tools from "@/assets/icons/tool.svg?react";
@@ -13,6 +14,7 @@ import { useNavigate } from "react-router-dom";
1314
import { ConfigurationTab } from "./Configuration";
1415
import { OverviewTab } from "./Overview";
1516
import { useSelectedTab } from "./service";
17+
import { MetadataTab } from "./Metadata";
1618

1719
type TabsHeaderProps = {
1820
setIsPanelOpen: Dispatch<SetStateAction<boolean>>;
@@ -57,6 +59,10 @@ export function RunsDetailTabs() {
5759
<Tools className="h-5 w-5 shrink-0 fill-theme-text-tertiary group-data-[state=active]/trigger:fill-theme-surface-strong" />
5860
<span>Configuration</span>
5961
</TabsTrigger>
62+
<TabsTrigger className="flex items-center gap-2 text-text-md" value="metadata">
63+
<MetadataIcon className="h-5 w-5 fill-theme-text-tertiary group-data-[state=active]/trigger:fill-theme-surface-strong" />
64+
<span>Metadata</span>
65+
</TabsTrigger>
6066
</TabsList>
6167

6268
<TabsContent className="m-0 mt-5 border-0 bg-transparent p-0" value="overview">
@@ -65,6 +71,9 @@ export function RunsDetailTabs() {
6571
<TabsContent className="m-0 mt-5 border-0 bg-transparent p-0" value="configuration">
6672
<ConfigurationTab />
6773
</TabsContent>
74+
<TabsContent className="m-0 mt-5 border-0 bg-transparent p-0" value="metadata">
75+
<MetadataTab />
76+
</TabsContent>
6877
</Tabs>
6978
</div>
7079
);

src/app/runs/[id]/_Tabs/service.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { useSearchParams } from "react-router-dom";
22
import { z } from "zod";
33

44
const tabParamSchema = z.object({
5-
tab: z.enum(["overview", "configuration"]).optional().default("overview").catch("overview")
5+
tab: z
6+
.enum(["overview", "configuration", "metadata"])
7+
.optional()
8+
.default("overview")
9+
.catch("overview")
610
});
711

812
export function useSelectedTab() {

0 commit comments

Comments
 (0)