From 7ff007ec044a833461cc9380cf3f18a6cb1361e2 Mon Sep 17 00:00:00 2001 From: gabalafou Date: Tue, 5 Mar 2024 16:11:21 -0500 Subject: [PATCH 1/2] Fix test warnings (#370) --- .../environments/components/EnvironmentDropdown.tsx | 10 ++++++++-- src/styles/StyledIconButton.tsx | 2 +- .../CreateEnvironmentPackagesTableRow.test.tsx | 10 +++++++--- test/environmentDetails/SpecificationEdit.test.tsx | 1 + .../RequestedPackagesTableRow.test.tsx | 6 +++++- 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/features/environments/components/EnvironmentDropdown.tsx b/src/features/environments/components/EnvironmentDropdown.tsx index 5fa5d8a8..bd2f5983 100644 --- a/src/features/environments/components/EnvironmentDropdown.tsx +++ b/src/features/environments/components/EnvironmentDropdown.tsx @@ -100,8 +100,14 @@ export const EnvironmentDropdown = ({ } > onCreateNewEnvironmentTab(e, namespace)} - disabled={!canCreate} + onClick={e => + canCreate && onCreateNewEnvironmentTab(e, namespace) + } + // Do not use the `disabled` attribute. Disable manually with + // JavaScript and the `aria-disabled` attribute, otherwise the + // tooltip won't work. More info: + // https://github.com/conda-incubator/conda-store-ui/pull/370/files#r1486492450 + aria-disabled={!canCreate} > diff --git a/src/styles/StyledIconButton.tsx b/src/styles/StyledIconButton.tsx index 11016a07..e4a39753 100644 --- a/src/styles/StyledIconButton.tsx +++ b/src/styles/StyledIconButton.tsx @@ -18,7 +18,7 @@ export const StyledIconButton = styled(Button)(({ theme }) => ({ outlineWidth: "medium", transition: "none" }, - "&:disabled": { + '&[aria-disabled="true"]': { backgroundColor: theme.palette.secondary[100], border: "none", color: theme.palette.secondary[300] diff --git a/test/environmentCreate/CreateEnvironmentPackagesTableRow.test.tsx b/test/environmentCreate/CreateEnvironmentPackagesTableRow.test.tsx index ca14148d..62cf6a64 100644 --- a/test/environmentCreate/CreateEnvironmentPackagesTableRow.test.tsx +++ b/test/environmentCreate/CreateEnvironmentPackagesTableRow.test.tsx @@ -34,9 +34,13 @@ describe("", () => { return render( mockTheme( - + + + + +
) ); diff --git a/test/environmentDetails/SpecificationEdit.test.tsx b/test/environmentDetails/SpecificationEdit.test.tsx index 0182ea8d..8862b81b 100644 --- a/test/environmentDetails/SpecificationEdit.test.tsx +++ b/test/environmentDetails/SpecificationEdit.test.tsx @@ -70,6 +70,7 @@ describe("", () => { ) diff --git a/test/requestedPackages/RequestedPackagesTableRow.test.tsx b/test/requestedPackages/RequestedPackagesTableRow.test.tsx index f0d8bb82..73c54583 100644 --- a/test/requestedPackages/RequestedPackagesTableRow.test.tsx +++ b/test/requestedPackages/RequestedPackagesTableRow.test.tsx @@ -34,7 +34,11 @@ describe("", () => { return render( mockTheme( - + + + + +
) ); From 7806a85f37375ec9b4908a6de894464fc856b3dc Mon Sep 17 00:00:00 2001 From: gabalafou Date: Tue, 5 Mar 2024 16:11:55 -0500 Subject: [PATCH 2/2] Add log link next to status message (#367) --- .../artifacts/components/ArtifactsItem.tsx | 6 +- .../metadata/components/EnvBuilds.tsx | 57 ++++++++++++++----- src/features/metadata/mocks/index.ts | 1 + src/features/metadata/mocks/mockBuilds.ts | 30 ++++++++++ .../metadata/stories/EnvBuilds.stories.tsx | 27 +++++++++ src/utils/helpers/parseArtifactList.ts | 10 +++- test/metadata/EnvBuilds.test.tsx | 49 +++++++++++++++- test/testutils.tsx | 3 +- 8 files changed, 162 insertions(+), 21 deletions(-) create mode 100644 src/features/metadata/mocks/index.ts create mode 100644 src/features/metadata/mocks/mockBuilds.ts create mode 100644 src/features/metadata/stories/EnvBuilds.stories.tsx 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) => {