Skip to content

Commit 2f4e918

Browse files
feat: imporve code repo in pipeline step (#598) (#603)
Co-authored-by: Cahllagerfeld <[email protected]>
1 parent 8438dc1 commit 2f4e918

File tree

4 files changed

+97
-4
lines changed

4 files changed

+97
-4
lines changed

src/components/steps/step-sheet/DetailsTab.tsx

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { ErrorFallback } from "../../Error";
1212
import Github from "@/assets/icons/github.svg?react";
1313
import { CopyButton } from "@/components/CopyButton";
1414
import { transformToEllipsis } from "@/lib/strings";
15+
import { useCodeRepository } from "@/data/code-repositories/code-repositories-detail-query";
1516

1617
type Props = {
1718
stepId: string;
@@ -26,6 +27,15 @@ export function StepDetailsTab({ stepId, runId }: Props) {
2627
const { data, isError, isPending, error } = useStepDetail({ stepId });
2728
const { data: pipelineRunData } = usePipelineRun({ runId });
2829

30+
const repository = pipelineRunData?.body?.code_reference?.body?.code_repository;
31+
32+
const { data: codeRepositoryData } = useCodeRepository(
33+
{ repositoryId: repository?.id as string },
34+
{ throwOnError: true, enabled: !!repository?.id }
35+
);
36+
37+
const repositoryMetadata = codeRepositoryData?.metadata?.config;
38+
2939
if (isError) return <ErrorFallback err={error} />;
3040
if (isPending) return <Skeleton className="h-[300px] w-full" />;
3141

@@ -36,6 +46,32 @@ export function StepDetailsTab({ stepId, runId }: Props) {
3646
const enable_artifact_metadata = data.metadata?.config?.enable_artifact_metadata;
3747
const enable_artifact_visualization = data.metadata?.config?.enable_artifact_visualization;
3848

49+
const getRepositoryLink = () => {
50+
let name: string = repository?.name as string;
51+
let url: string | null = "";
52+
53+
if (repository?.body?.source?.attribute === "GitHubCodeRepository") {
54+
name = `${repositoryMetadata?.owner}/${repositoryMetadata?.repository}`;
55+
url = `https://www.github.com/${name}`;
56+
} else if (repository?.body?.source?.attribute === "GitLabCodeRepository") {
57+
name = `${repositoryMetadata?.group}/${repositoryMetadata?.project}`;
58+
url = `https://www.gitlab.com/${name}`;
59+
}
60+
61+
return (
62+
<a
63+
target="_blank"
64+
rel="noopener noreferrer"
65+
className={`flex items-center ${url ? "" : "pointer-events-none"}`}
66+
onClick={(e) => e.stopPropagation()}
67+
href={url}
68+
>
69+
<Github className="mr-1 h-5 w-5 fill-theme-text-brand" />
70+
{name}
71+
</a>
72+
);
73+
};
74+
3975
return (
4076
<CollapsibleCard initialOpen title="Details">
4177
<dl className="grid grid-cols-1 gap-x-[10px] gap-y-2 md:grid-cols-3 md:gap-y-4">
@@ -112,7 +148,7 @@ export function StepDetailsTab({ stepId, runId }: Props) {
112148
</Tag>
113149
}
114150
/>
115-
{pipelineRunData.body?.code_reference && (
151+
{pipelineRunData.body?.code_reference && repositoryMetadata && (
116152
<KeyValue
117153
label="Repository/Commit"
118154
value={
@@ -123,8 +159,7 @@ export function StepDetailsTab({ stepId, runId }: Props) {
123159
rounded={false}
124160
emphasis="subtle"
125161
>
126-
<Github className="mr-1 h-5 w-5 fill-theme-text-brand" />
127-
zenml.io/zenml
162+
{getRepositoryLink()}
128163
<div className="ml-1 rounded-sm bg-neutral-200 px-1 py-0.25">
129164
{transformToEllipsis(
130165
pipelineRunData?.body?.code_reference?.body?.commit as string,

src/data/api.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ export const apiPaths = {
2828
all: "/pipeline_builds",
2929
detail: (runId: string) => `/pipeline_builds/${runId}`
3030
},
31+
code_repositories: {
32+
all: "/code_repositories",
33+
detail: (codeRepositoryId: string) => `/code_repositories/${codeRepositoryId}`
34+
},
3135
stacks: {
3236
detail: (stackId: string) => `/stacks/${stackId}`
3337
},
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { UseQueryOptions, useQuery } from "@tanstack/react-query";
2+
import { FetchError } from "@/lib/fetch-error";
3+
import { notFound } from "@/lib/not-found-error";
4+
import { apiPaths, createApiPath } from "../api";
5+
import { CodeRepository } from "@/types/code-repository";
6+
7+
export type CodeRepositoryDetail = {
8+
repositoryId: string;
9+
};
10+
11+
export function getCodeRepositoryDetailQueryKey({ repositoryId }: CodeRepositoryDetail) {
12+
return ["code_repositories", repositoryId];
13+
}
14+
15+
export async function fetchAllCodeRepositories({ repositoryId }: CodeRepositoryDetail) {
16+
const url = createApiPath(apiPaths.code_repositories.detail(repositoryId));
17+
const res = await fetch(url, {
18+
method: "GET",
19+
credentials: "include",
20+
headers: {
21+
"Content-Type": "application/json"
22+
}
23+
});
24+
25+
if (res.status === 404) {
26+
notFound();
27+
}
28+
29+
if (!res.ok) {
30+
throw new FetchError({
31+
message: `Error while fetching code repository ${repositoryId}`,
32+
status: res.status,
33+
statusText: res.statusText
34+
});
35+
}
36+
return res.json();
37+
}
38+
39+
export function useCodeRepository(
40+
repositoryId: CodeRepositoryDetail,
41+
options?: Omit<UseQueryOptions<CodeRepository, FetchError>, "queryKey" | "queryFn">
42+
) {
43+
return useQuery<CodeRepository, FetchError>({
44+
queryKey: getCodeRepositoryDetailQueryKey(repositoryId),
45+
queryFn: () => fetchAllCodeRepositories(repositoryId),
46+
...options
47+
});
48+
}

src/types/code-repository.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1-
import { components } from "./core";
1+
import { components, operations } from "./core";
22

33
export type CodeRepository = components["schemas"]["CodeRepositoryResponse"];
4+
5+
export type PageCodeRepositoryResponse = components["schemas"]["Page_CodeRepositoryResponse_"];
6+
7+
export type CodeRepositoryListQueryParams = NonNullable<
8+
operations["list_code_repositories_api_v1_code_repositories_get"]["parameters"]["query"]
9+
>;

0 commit comments

Comments
 (0)