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) => {