Skip to content

Commit 2725570

Browse files
refactor: display Pipeline Params (#662)
1 parent a1fce2f commit 2725570

File tree

7 files changed

+155
-41
lines changed

7 files changed

+155
-41
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import ChevronDown from "@/assets/icons/chevron-down.svg?react";
2+
import { NestedCollapsible } from "@/components/NestedCollapsible";
3+
import { pipelineDeploymentQueries } from "@/data/pipeline-deployments";
4+
import { useQuery } from "@tanstack/react-query";
5+
import {
6+
CollapsibleContent,
7+
CollapsibleHeader,
8+
CollapsiblePanel,
9+
CollapsibleTrigger,
10+
Skeleton
11+
} from "@zenml-io/react-component-library";
12+
import { useState } from "react";
13+
14+
type Props = {
15+
deploymentId?: string;
16+
};
17+
18+
export function PipelineParamsCollapsible({ deploymentId }: Props) {
19+
const [open, setOpen] = useState(true);
20+
21+
const { isLoading, isError, data } = useQuery({
22+
...pipelineDeploymentQueries.detail(deploymentId!),
23+
enabled: !!deploymentId
24+
});
25+
26+
if (!deploymentId)
27+
return (
28+
<CollapsiblePanel open={open} onOpenChange={setOpen}>
29+
<CollapsibleHeader intent="primary" className="flex items-center gap-[10px]">
30+
<CollapsibleTrigger>
31+
<ChevronDown
32+
className={` ${
33+
open ? "" : "-rotate-90"
34+
} h-5 w-5 rounded-md fill-neutral-500 transition-transform duration-200 hover:bg-neutral-200`}
35+
/>
36+
</CollapsibleTrigger>
37+
Pipeline Parameters
38+
</CollapsibleHeader>
39+
<CollapsibleContent className="border-t border-theme-border-moderate bg-theme-surface-primary px-5 py-3">
40+
Not available
41+
</CollapsibleContent>
42+
</CollapsiblePanel>
43+
);
44+
45+
if (isLoading) return <Skeleton className="h-[150px] w-full" />;
46+
if (isError) return null;
47+
48+
return (
49+
<NestedCollapsible
50+
isInitialOpen
51+
title="Pipeline Parameters"
52+
data={data?.metadata?.pipeline_spec?.parameters}
53+
/>
54+
);
55+
}

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useParams } from "react-router-dom";
77
import { CodeCollapsible } from "./CodeCollapsible";
88
import { DockerImageCollapsible } from "./DockerImageCollapsible";
99
import { EnvironmentCollapsible } from "./EnvironmentCollapsible";
10+
import { PipelineParamsCollapsible } from "./ParameterCollapsible";
1011

1112
export function ConfigurationTab() {
1213
const { runId } = useParams() as { runId: string };
@@ -31,11 +32,7 @@ export function ConfigurationTab() {
3132

3233
return (
3334
<div className="grid grid-cols-1 gap-5">
34-
<NestedCollapsible
35-
isInitialOpen
36-
title="Parameters"
37-
data={data.metadata?.config.parameters ?? undefined}
38-
/>
35+
<PipelineParamsCollapsible deploymentId={data.body?.deployment_id ?? undefined} />
3936
{(buildData?.metadata?.images as BuildItemMap)?.orchestrator && (
4037
<DockerImageCollapsible data={buildData?.metadata?.images?.orchestrator as BuildItem} />
4138
)}

src/components/NestedCollapsible.tsx

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export function NestedCollapsible({
3535
const regex = /^<class\s+'.*'>$/;
3636

3737
for (const [key, value] of Object.entries(data || {})) {
38-
if (typeof value === "object" && !Array.isArray(value)) {
38+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3939
objects[key] = value;
4040
} else if (Array.isArray(value)) {
4141
arrays[key] = value;
@@ -44,8 +44,6 @@ export function NestedCollapsible({
4444
}
4545
}
4646

47-
if (Object.keys(data || {}).length === 0) return null;
48-
4947
const values = Object.entries(nonObjects);
5048
values.sort((a, b) => a[0].localeCompare(b[0]));
5149

@@ -57,40 +55,46 @@ export function NestedCollapsible({
5755
intent={intent}
5856
title={title}
5957
>
60-
<div className="flex flex-col gap-3">
61-
<dl className="grid grid-cols-1 gap-x-[10px] gap-y-2 md:grid-cols-3 md:gap-y-4">
62-
{values.map(([key, value]) => (
63-
<KeyValue
64-
key={key}
65-
label={
66-
<TooltipProvider>
67-
<Tooltip>
68-
<TooltipTrigger className="cursor-default truncate">{key}</TooltipTrigger>
69-
<TooltipContent className="max-w-[480px]">{key}</TooltipContent>
70-
</Tooltip>
71-
</TooltipProvider>
72-
}
73-
value={
74-
<>
75-
{typeof value === "boolean" ? (
76-
<div className="py-1">{JSON.stringify(value)}</div>
77-
) : regex.test(value) ? (
78-
<Codesnippet className="py-1" highlightCode code={value} />
79-
) : (
80-
<div className="overflow-x-auto py-1">{value}</div>
81-
)}
82-
</>
83-
}
84-
/>
58+
{Object.keys(data || {}).length === 0 ? (
59+
<p>Not available</p>
60+
) : (
61+
<div className="flex flex-col gap-3">
62+
<dl className="grid grid-cols-1 gap-x-[10px] gap-y-2 md:grid-cols-3 md:gap-y-4">
63+
{values.map(([key, value]) => (
64+
<KeyValue
65+
key={key}
66+
label={
67+
<TooltipProvider>
68+
<Tooltip>
69+
<TooltipTrigger className="cursor-default truncate">{key}</TooltipTrigger>
70+
<TooltipContent className="max-w-[480px]">{key}</TooltipContent>
71+
</Tooltip>
72+
</TooltipProvider>
73+
}
74+
value={
75+
<>
76+
{typeof value === "boolean" ? (
77+
<div className="py-1">{JSON.stringify(value)}</div>
78+
) : regex.test(value) ? (
79+
<Codesnippet className="py-1" highlightCode code={value} />
80+
) : value === null ? (
81+
<div className="overflow-x-auto">null</div>
82+
) : (
83+
<div className="overflow-x-auto py-1">{value}</div>
84+
)}
85+
</>
86+
}
87+
/>
88+
))}
89+
</dl>
90+
{Object.entries(arrays).map(([key, value]) => (
91+
<RenderArray key={key} title={key} value={value} />
92+
))}
93+
{Object.entries(objects).map(([key, value]) => (
94+
<NestedCollapsible intent="secondary" title={key} data={value} key={key} />
8595
))}
86-
</dl>
87-
{Object.entries(arrays).map(([key, value]) => (
88-
<RenderArray key={key} title={key} value={value} />
89-
))}
90-
{Object.entries(objects).map(([key, value]) => (
91-
<NestedCollapsible intent="secondary" title={key} data={value} key={key} />
92-
))}
93-
</div>
96+
</div>
97+
)}
9498
</CollapsibleCard>
9599
);
96100
}

src/data/api.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ export const apiPaths = {
3030
all: "/pipeline_builds",
3131
detail: (runId: string) => `/pipeline_builds/${runId}`
3232
},
33+
pipeline_deployments: {
34+
detail: (deploymentId: string) => `/pipeline_deployments/${deploymentId}`
35+
},
3336
code_repositories: {
3437
all: "/code_repositories",
3538
detail: (codeRepositoryId: string) => `/code_repositories/${codeRepositoryId}`
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { queryOptions } from "@tanstack/react-query";
2+
import { fetchPipelineDeployment } from "./pipeline-deployments-detail";
3+
4+
export const pipelineDeploymentQueries = {
5+
all: ["pipeline_deployments"],
6+
detail: (deploymentId: string) =>
7+
queryOptions({
8+
queryKey: [...pipelineDeploymentQueries.all, deploymentId],
9+
queryFn: async () => fetchPipelineDeployment({ deploymentId })
10+
})
11+
};
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { FetchError } from "@/lib/fetch-error";
2+
import { apiPaths, createApiPath } from "../api";
3+
import { PipelineDeployment } from "@/types/pipeline-deployments";
4+
5+
export type PipelineDeploymentArgs = {
6+
deploymentId: string;
7+
};
8+
9+
export async function fetchPipelineDeployment(
10+
{ deploymentId }: PipelineDeploymentArgs,
11+
token?: string
12+
): Promise<PipelineDeployment> {
13+
const url = createApiPath(apiPaths.pipeline_deployments.detail(deploymentId));
14+
15+
const res = await fetch(url, {
16+
method: "GET",
17+
credentials: "include",
18+
headers: {
19+
"Content-Type": "application/json",
20+
...(token && { Authorization: `Bearer ${token}` })
21+
}
22+
});
23+
24+
if (!res.ok) {
25+
const errorData: string = await res
26+
.json()
27+
.then((data) => {
28+
if (Array.isArray(data.detail)) {
29+
return data.detail[1];
30+
}
31+
return data.detail;
32+
})
33+
.catch(() => `Error while fetching pipeline deployment ${deploymentId}`);
34+
throw new FetchError({
35+
status: res.status,
36+
statusText: res.statusText,
37+
message: errorData
38+
});
39+
}
40+
return res.json();
41+
}

src/types/pipeline-deployments.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { components } from "./core";
2+
3+
export type PipelineDeployment = components["schemas"]["PipelineDeploymentResponse"];

0 commit comments

Comments
 (0)