diff --git a/src/features/artifacts/components/ArtifactsItem.tsx b/src/features/artifacts/components/ArtifactsItem.tsx index c29b0ce6..34166d88 100644 --- a/src/features/artifacts/components/ArtifactsItem.tsx +++ b/src/features/artifacts/components/ArtifactsItem.tsx @@ -6,7 +6,7 @@ import { useTheme } from "@mui/material/styles"; import { Artifact } from "../../../common/models"; import { PrefContext } from "../../../preferences"; -import { isPathAbsolute } from "../../../utils/helpers"; +import { artifactBaseUrl } from "../../../utils/helpers"; interface IArtifactsProps { /** @@ -17,9 +17,7 @@ interface IArtifactsProps { export const ArtifactItem = ({ artifact }: IArtifactsProps) => { const pref = React.useContext(PrefContext); - const url = isPathAbsolute(pref.apiUrl) - ? pref.apiUrl - : `${window.location.origin}${pref.apiUrl}`; + const url = artifactBaseUrl(pref.apiUrl, window.location.origin); const route = new URL(artifact.route, url).toString(); const theme = useTheme(); diff --git a/src/features/metadata/components/EnvBuilds.tsx b/src/features/metadata/components/EnvBuilds.tsx index da85edcc..ce06497e 100644 --- a/src/features/metadata/components/EnvBuilds.tsx +++ b/src/features/metadata/components/EnvBuilds.tsx @@ -4,8 +4,14 @@ import { StyledMetadataItem } from "../../../styles/StyledMetadataItem"; import { Build as IBuild } from "../../../common/models"; import { Build } from "../../../features/metadata/components"; import { buildMapper } from "../../../utils/helpers/buildMapper"; +import Link from "@mui/material/Link"; +import OpenInNewIcon from "@mui/icons-material/OpenInNew"; +import { artifactBaseUrl } from "../../../utils/helpers"; +import { PrefContext } from "../../../preferences"; +import artifactList from "../../../utils/helpers/artifact"; +import { Artifact } from "../../../common/models"; -interface IData { +export interface IData { currentBuildId: number; selectedBuildId: number; builds: IBuild[]; @@ -21,6 +27,34 @@ export const EnvBuilds = ({ const envBuilds = builds.length ? buildMapper(builds, currentBuildId) : []; const currentBuild = envBuilds.find(build => build.id === selectedBuildId); + // If the selected build is a failed build, we will render the link to the build log. + let logLink; + const showLogLink = currentBuild?.status === "Failed"; + const logArtifact: Artifact | never = artifactList(currentBuild?.id, [ + "LOGS" + ])[0]; + if (showLogLink && logArtifact) { + const pref = React.useContext(PrefContext); + const url = new URL( + logArtifact.route, + artifactBaseUrl(pref.apiUrl, window.location.origin) + ); + logLink = ( + + + Log + + ); + } + return ( <> {mode === "edit" ? "Change active environment version:" : "Builds:"} - {currentBuild && ( + {currentBuild ? ( <> Status: {""} - {currentBuild.status_info ? ( - <> - {currentBuild.status} ({currentBuild.status_info}) - - ) : ( - <>{currentBuild.status} - )} - {(currentBuild.status === "Building" || + {currentBuild.status} + {currentBuild.status_info && ` (${currentBuild.status_info})`} + {((currentBuild.status === "Building" || currentBuild.status === "Queued") && ( - )} + )) || + // If the selected build is a failed build, render the link to the build log. + (showLogLink && <>. {logLink})} - )} - {!currentBuild && ( + ) : ( ; + +export const Primary = { + args: { + currentBuildId: 1, + selectedBuildId: 1, + mode: "read-only", + builds: mockBuilds + }, + decorators: [ + (Story: Story) => ( + + + + ) + ] +}; diff --git a/src/utils/helpers/parseArtifactList.ts b/src/utils/helpers/parseArtifactList.ts index d8d0fdb6..cd8aa130 100644 --- a/src/utils/helpers/parseArtifactList.ts +++ b/src/utils/helpers/parseArtifactList.ts @@ -9,6 +9,14 @@ export const parseArtifacts = (artifact_list: string[] | undefined) => { }); }; -export const isPathAbsolute = (path: string) => { +const isPathAbsolute = (path: string) => { return new RegExp("^(?:[a-z]+:)?//", "i").test(path); }; + +export const artifactBaseUrl = (apiUrl: string, baseUrl: string) => { + if (isPathAbsolute(apiUrl)) { + return apiUrl; + } else { + return `${baseUrl}${apiUrl}`; + } +}; diff --git a/test/metadata/EnvBuilds.test.tsx b/test/metadata/EnvBuilds.test.tsx index 5762536b..6dbcba66 100644 --- a/test/metadata/EnvBuilds.test.tsx +++ b/test/metadata/EnvBuilds.test.tsx @@ -9,7 +9,12 @@ describe("", () => { it("should render component", () => { const component = render( - + ); expect(component.container).toHaveTextContent("Builds"); @@ -18,10 +23,50 @@ describe("", () => { it("should show a progress bar if builds are not available", () => { const component = render( - + ); const progressBar = component.getByRole("progressbar"); expect(progressBar).toBeInTheDocument(); }); + + it("should render link to log if selected build failed", () => { + const failedBuild = { ...BUILD, status: "FAILED" }; + const { getByTestId, getByRole } = render( + + + + ); + expect(getByRole("link", { name: "Log" })).toBeInTheDocument(); + expect(getByTestId("build-status")).toHaveTextContent( + /^Status: Failed\. Log$/ + ); + }); + + it("should not render log link for normal build", () => { + const { getByTestId, queryByRole } = render( + + + + ); + expect(queryByRole("link", { name: "Log" })).not.toBeInTheDocument(); + expect(getByTestId("build-status")).toHaveTextContent( + /^Status: Completed$/ + ); + }); }); diff --git a/test/testutils.tsx b/test/testutils.tsx index 90630d96..3a59d347 100644 --- a/test/testutils.tsx +++ b/test/testutils.tsx @@ -86,7 +86,8 @@ export const BUILD = { scheduled_on: "2022-11-08T14:28:05.655564", started_on: "2022-11-08T14:28:05.655564", ended_on: "2022-11-08T14:28:05.655564", - build_artifacts: [] + build_artifacts: [], + status_info: null }; export const mockTheme = (children: any) => {