Skip to content

Commit

Permalink
<EnvBuildStatus /> component (#377)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabalafou authored Mar 26, 2024
1 parent ee80e93 commit 7e0fa2a
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 192 deletions.
19 changes: 11 additions & 8 deletions src/features/metadata/components/BuildDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,25 @@ import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import IconButton from "@mui/material/IconButton";
import { useAppDispatch } from "../../../hooks";
import { currentBuildIdChanged } from "..";
import { Build } from "../../../common/models";
import { buildDatetimeStatus } from "../../../utils/helpers/buildMapper";

interface IBuildProps {
/**
* @param builds list of builds
* @param currentBuildId id of the current build
* @param onChangeStatus update the build status
* @param selectedBuildId id of the build selected from the dropdown
*/
builds: {
id: number;
name: string;
status: string;
}[];
builds: Build[];
currentBuildId: number;
selectedBuildId: number;
}

export const Build = ({ builds, selectedBuildId }: IBuildProps) => {
export const BuildDropdown = ({
builds,
currentBuildId,
selectedBuildId
}: IBuildProps) => {
const dispatch = useAppDispatch();
const { palette } = useTheme();
const [open, setOpen] = useState(false);
Expand Down Expand Up @@ -92,7 +95,7 @@ export const Build = ({ builds, selectedBuildId }: IBuildProps) => {
{builds
? builds.map(build => (
<MenuItem key={build.id} value={build.id}>
{build.name}
{buildDatetimeStatus(build, currentBuildId)}
</MenuItem>
))
: null}
Expand Down
74 changes: 74 additions & 0 deletions src/features/metadata/components/EnvBuildStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from "react";
import { CircularProgress, Typography } from "@mui/material";
import Link from "@mui/material/Link";
import OpenInNewIcon from "@mui/icons-material/OpenInNew";
import { Artifact, Build } from "../../../common/models";
import { PrefContext } from "../../../preferences";
import { StyledMetadataItem } from "../../../styles/StyledMetadataItem";
import artifactList from "../../../utils/helpers/artifact";
import { artifactBaseUrl } from "../../../utils/helpers/parseArtifactList";
import { buildStatus } from "../../../utils/helpers/buildMapper";

const LogLink = ({ logArtifact }: { logArtifact: Artifact }) => {
const pref = React.useContext(PrefContext);
const url = new URL(
logArtifact.route,
artifactBaseUrl(pref.apiUrl, window.location.origin)
);
return (
<Link
href={url.toString()}
target="_blank"
sx={{
display: "inline-flex",
verticalAlign: "bottom", // align link (icon plus link text) with non-link text on the same line
alignItems: "center" // align icon and text within link
}}
>
<OpenInNewIcon sx={{ mr: 0.5 }} fontSize="inherit" />
Log
</Link>
);
};

interface IEnvBuildStatusProps {
build: Build;
}

export const EnvBuildStatus = ({ build }: IEnvBuildStatusProps) => {
const logArtifact: Artifact | void = artifactList(build.id, ["LOGS"])[0];

return (
<StyledMetadataItem
sx={{
marginTop: "0",
fontSize: "13px",
fontWeight: 500,
paddingBottom: "0"
}}
data-testid="build-status"
>
Status: {""}
<Typography component="span" sx={{ fontSize: "13px" }}>
{buildStatus(build)}
{build.status_info && ` (${build.status_info})`}
{build.status === "BUILDING" || build.status === "QUEUED" ? (
<CircularProgress
size={10}
sx={{
marginLeft: "8px"
}}
/>
) : (
// If the selected build is a failed build, render the link to the build log.
build.status === "FAILED" &&
logArtifact && (
<>
. <LogLink logArtifact={logArtifact} />
</>
)
)}
</Typography>
</StyledMetadataItem>
);
};
79 changes: 11 additions & 68 deletions src/features/metadata/components/EnvBuilds.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import React from "react";
import { CircularProgress, Typography } from "@mui/material";
import { CircularProgress } from "@mui/material";
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";
import { BuildDropdown } from "../../../features/metadata/components";
import { EnvBuildStatus } from "./EnvBuildStatus";

export interface IData {
currentBuildId: number;
Expand All @@ -24,37 +18,7 @@ export const EnvBuilds = ({
builds,
mode
}: IData) => {
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 = (
<Link
href={url.toString()}
target="_blank"
sx={{
display: "inline-flex",
verticalAlign: "bottom", // align link (icon plus link text) with non-link text on the same line
alignItems: "center" // align icon and text within link
}}
>
<OpenInNewIcon sx={{ mr: 0.5 }} fontSize="inherit" />
Log
</Link>
);
}

const selectedBuild = builds.find(build => build.id === selectedBuildId);
return (
<>
<StyledMetadataItem
Expand All @@ -65,35 +29,14 @@ export const EnvBuilds = ({
>
{mode === "edit" ? "Change active environment version:" : "Builds:"}
</StyledMetadataItem>
{currentBuild ? (
{selectedBuild ? (
<>
<Build builds={envBuilds} selectedBuildId={selectedBuildId} />
<StyledMetadataItem
sx={{
marginTop: "0",
fontSize: "13px",
fontWeight: 500,
paddingBottom: "0"
}}
data-testid="build-status"
>
Status: {""}
<Typography component="span" sx={{ fontSize: "13px" }}>
{currentBuild.status}
{currentBuild.status_info && ` (${currentBuild.status_info})`}
{((currentBuild.status === "Building" ||
currentBuild.status === "Queued") && (
<CircularProgress
size={10}
sx={{
marginLeft: "8px"
}}
/>
)) ||
// If the selected build is a failed build, render the link to the build log.
(showLogLink && <>. {logLink}</>)}
</Typography>
</StyledMetadataItem>
<BuildDropdown
builds={builds}
currentBuildId={currentBuildId}
selectedBuildId={selectedBuildId}
/>
<EnvBuildStatus build={selectedBuild} />
</>
) : (
<CircularProgress
Expand Down
1 change: 1 addition & 0 deletions src/features/metadata/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from "./EnvMetadata";
export * from "./BuildDropdown";
export * from "./Description";
export * from "./EnvBuilds";
export * from "./EnvBuildStatus";
96 changes: 33 additions & 63 deletions src/utils/helpers/buildMapper.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { format, utcToZonedTime } from "date-fns-tz";
import { Build } from "../../common/models";

const STATUS_OPTIONS: any = {
const STATUS_OPTIONS: { [key: Build["status"]]: string } = {
COMPLETED: "Available",
QUEUED: "Queued",
FAILED: "Failed",
Expand All @@ -10,26 +10,6 @@ const STATUS_OPTIONS: any = {

const TIMEZONE = Intl.DateTimeFormat().resolvedOptions().timeZone;

const isBuilding = (status: string) => {
const BUILD_STATUS = ["BUILDING"];
return BUILD_STATUS.includes(status);
};

const isQueued = (status: string) => {
const BUILD_STATUS = ["QUEUED"];
return BUILD_STATUS.includes(status);
};

const isCompleted = (status: string, duration: number) => {
if (status === "COMPLETED") {
if (duration > 0) {
return `Completed in ${duration} min`;
}
return "Completed";
}
return STATUS_OPTIONS[status];
};

const dateToTimezone = (date: string) => {
if (!date) {
return "";
Expand All @@ -40,51 +20,41 @@ const dateToTimezone = (date: string) => {
});
};

export const buildMapper = (data: Build[], currentBuildId: number) => {
return data.map(
({ id, status, status_info, ended_on, scheduled_on }: Build) => {
let duration = 0;
export const buildDatetimeStatus = (
{ id, status, ended_on, scheduled_on }: Build,
currentBuildId: number
): string => {
if (id === currentBuildId) {
return `${dateToTimezone(ended_on ?? scheduled_on)} - Active`;
} else if (status === "BUILDING") {
return `${dateToTimezone(scheduled_on)} - Building`;
} else if (status === "QUEUED") {
return `${dateToTimezone(scheduled_on)} - Queued`;
} else {
return `${dateToTimezone(ended_on ?? scheduled_on)} - ${
STATUS_OPTIONS[status]
}`;
}
};

export const buildStatus = ({
status,
ended_on,
scheduled_on
}: Build): string => {
switch (status) {
case "COMPLETED":
if (ended_on && scheduled_on) {
const startTime = new Date(scheduled_on);
const endTime = new Date(ended_on);
duration = (endTime.valueOf() - startTime.valueOf()) / 60000;
let duration = (endTime.valueOf() - startTime.valueOf()) / 60000;
duration = Math.round(duration);
if (duration > 0) {
return `Completed in ${duration} min`;
}
}
if (id === currentBuildId) {
return {
id,
name: `${dateToTimezone(ended_on ?? scheduled_on)} - Active`,
status: isCompleted(status, duration),
status_info
};
}

if (isBuilding(status)) {
return {
id,
name: `${dateToTimezone(scheduled_on)} - Building`,
status: "Building",
status_info
};
}

if (isQueued(status)) {
return {
id,
name: `${dateToTimezone(scheduled_on)} - Queued`,
status: "Building",
status_info
};
}

return {
id,
name: `${dateToTimezone(ended_on ?? scheduled_on)} - ${
STATUS_OPTIONS[status]
}`,
status: isCompleted(status, duration),
status_info
};
}
);
return "Completed";
default:
return STATUS_OPTIONS[status];
}
};
Loading

0 comments on commit 7e0fa2a

Please sign in to comment.