diff --git a/apps/spruce/src/gql/generated/types.ts b/apps/spruce/src/gql/generated/types.ts
index 05862f178..bb09e52d1 100644
--- a/apps/spruce/src/gql/generated/types.ts
+++ b/apps/spruce/src/gql/generated/types.ts
@@ -9539,6 +9539,7 @@ export type WaterfallQuery = {
id: string;
builds: Array<{
__typename?: "WaterfallBuild";
+ activated?: boolean | null;
displayName: string;
id: string;
version: string;
diff --git a/apps/spruce/src/gql/queries/waterfall.graphql b/apps/spruce/src/gql/queries/waterfall.graphql
index f721b158e..7334f51ec 100644
--- a/apps/spruce/src/gql/queries/waterfall.graphql
+++ b/apps/spruce/src/gql/queries/waterfall.graphql
@@ -4,6 +4,7 @@ query Waterfall($options: WaterfallOptions!) {
waterfall(options: $options) {
buildVariants {
builds {
+ activated
displayName
id
tasks {
diff --git a/apps/spruce/src/pages/waterfall/BuildRow.tsx b/apps/spruce/src/pages/waterfall/BuildRow.tsx
index cc6f85392..d2ae1107a 100644
--- a/apps/spruce/src/pages/waterfall/BuildRow.tsx
+++ b/apps/spruce/src/pages/waterfall/BuildRow.tsx
@@ -2,6 +2,7 @@ import { memo, useCallback } from "react";
import styled from "@emotion/styled";
import { palette } from "@leafygreen-ui/palette";
import { Link } from "react-router-dom";
+import { taskStatusToCopy } from "@evg-ui/lib/constants/task";
import { TaskStatus } from "@evg-ui/lib/types/task";
import { useWaterfallAnalytics } from "analytics";
import { StyledLink } from "components/styles";
@@ -12,6 +13,7 @@ import {
WaterfallBuildVariant,
WaterfallQuery,
} from "gql/generated/types";
+import { statusColorMap, statusIconMap } from "./icons";
import {
BuildVariantTitle,
columnBasis,
@@ -20,7 +22,7 @@ import {
Row,
} from "./styles";
-const { black, gray, green, white } = palette;
+const { black, gray, white } = palette;
export const BuildRow: React.FC<{
build: WaterfallBuildVariant;
@@ -94,14 +96,18 @@ const BuildGrid: React.FC<{
);
}}
>
- {build.tasks.map(({ displayName, id, status }) => (
-
- ))}
+ {build.tasks.map(({ displayName, id, status }) => {
+ // If the entire build is inactive, use inactive status for all tasks
+ const taskStatus = build.activated ? status : TaskStatus.Inactive;
+ return (
+
+ );
+ })}
);
@@ -128,12 +134,12 @@ const Square = styled(Link)<{ status: string }>`
cursor: pointer;
position: relative;
- /* TODO DEVPROD-11368: Render colors for all statuses. Could use background-image property to render icons. */
- ${({ status }) =>
- status === TaskStatus.Succeeded
- ? `background-color: ${green.dark1};`
- : `background-color: ${gray.light2};
- `}
+ ${({ status }) => {
+ const icon = statusIconMap?.[status];
+ const iconStyle = icon ? `background-image: ${icon};` : "";
+ return `${iconStyle}
+background-color: ${statusColorMap[status]};`;
+ }}
/* Tooltip */
:before {
diff --git a/apps/spruce/src/pages/waterfall/WaterfallGrid.tsx b/apps/spruce/src/pages/waterfall/WaterfallGrid.tsx
index 40e42f494..a5f82df52 100644
--- a/apps/spruce/src/pages/waterfall/WaterfallGrid.tsx
+++ b/apps/spruce/src/pages/waterfall/WaterfallGrid.tsx
@@ -1,6 +1,7 @@
import { useRef } from "react";
import { useSuspenseQuery } from "@apollo/client";
import styled from "@emotion/styled";
+import { DEFAULT_POLL_INTERVAL } from "constants/index";
import { WaterfallQuery, WaterfallQueryVariables } from "gql/generated/types";
import { WATERFALL } from "gql/queries";
import { useDimensions } from "hooks/useDimensions";
@@ -31,6 +32,8 @@ export const WaterfallGrid: React.FC = ({
limit: VERSION_LIMIT,
},
},
+ // @ts-expect-error pollInterval isn't officially supported by useSuspenseQuery, but it works so let's use it anyway.
+ pollInterval: DEFAULT_POLL_INTERVAL,
},
);
const refEl = useRef(null);
diff --git a/apps/spruce/src/pages/waterfall/icons/RedOutlineX.ts b/apps/spruce/src/pages/waterfall/icons/RedOutlineX.ts
new file mode 100644
index 000000000..52e1ba75f
--- /dev/null
+++ b/apps/spruce/src/pages/waterfall/icons/RedOutlineX.ts
@@ -0,0 +1 @@
+export default `url('data:image/svg+xml,')`;
diff --git a/apps/spruce/src/pages/waterfall/icons/WhiteClockWithArrow.ts b/apps/spruce/src/pages/waterfall/icons/WhiteClockWithArrow.ts
new file mode 100644
index 000000000..48aab98d3
--- /dev/null
+++ b/apps/spruce/src/pages/waterfall/icons/WhiteClockWithArrow.ts
@@ -0,0 +1 @@
+export default `url('data:image/svg+xml,')`;
diff --git a/apps/spruce/src/pages/waterfall/icons/WhiteGear.ts b/apps/spruce/src/pages/waterfall/icons/WhiteGear.ts
new file mode 100644
index 000000000..78270fe09
--- /dev/null
+++ b/apps/spruce/src/pages/waterfall/icons/WhiteGear.ts
@@ -0,0 +1 @@
+export default `url('data:image/svg+xml,')`;
diff --git a/apps/spruce/src/pages/waterfall/icons/WhiteWrench.ts b/apps/spruce/src/pages/waterfall/icons/WhiteWrench.ts
new file mode 100644
index 000000000..1f0e04cd5
--- /dev/null
+++ b/apps/spruce/src/pages/waterfall/icons/WhiteWrench.ts
@@ -0,0 +1 @@
+export default `url('data:image/svg+xml,')`;
diff --git a/apps/spruce/src/pages/waterfall/icons/WhiteX.ts b/apps/spruce/src/pages/waterfall/icons/WhiteX.ts
new file mode 100644
index 000000000..e71450eba
--- /dev/null
+++ b/apps/spruce/src/pages/waterfall/icons/WhiteX.ts
@@ -0,0 +1 @@
+export default `url('data:image/svg+xml,')`;
diff --git a/apps/spruce/src/pages/waterfall/icons/index.ts b/apps/spruce/src/pages/waterfall/icons/index.ts
new file mode 100644
index 000000000..ecec02ebd
--- /dev/null
+++ b/apps/spruce/src/pages/waterfall/icons/index.ts
@@ -0,0 +1,42 @@
+import { palette } from "@leafygreen-ui/palette";
+import { TaskStatus } from "@evg-ui/lib/types/task";
+import redOutlineX from "./RedOutlineX";
+import whiteClockWithArrow from "./WhiteClockWithArrow";
+import whiteGear from "./WhiteGear";
+import whiteWrench from "./WhiteWrench";
+import whiteX from "./WhiteX";
+
+const { blue, gray, green, purple, red, yellow } = palette;
+
+export const statusColorMap: Record = {
+ [TaskStatus.Succeeded]: green.dark1,
+ [TaskStatus.Started]: yellow.base,
+ [TaskStatus.Dispatched]: yellow.base,
+ [TaskStatus.SystemFailed]: purple.dark2,
+ [TaskStatus.SystemTimedOut]: purple.dark2,
+ [TaskStatus.SystemUnresponsive]: purple.dark2,
+ [TaskStatus.Failed]: red.base,
+ [TaskStatus.TaskTimedOut]: red.base,
+ [TaskStatus.TestTimedOut]: red.base,
+ [TaskStatus.KnownIssue]: red.light3,
+ [TaskStatus.SetupFailed]: blue.base,
+ [TaskStatus.Unscheduled]: gray.light1,
+ [TaskStatus.Aborted]: gray.light1,
+ [TaskStatus.Blocked]: gray.light1,
+ [TaskStatus.Inactive]: gray.light1,
+ [TaskStatus.Undispatched]: gray.dark1,
+ [TaskStatus.WillRun]: gray.dark1,
+ [TaskStatus.Pending]: gray.dark1,
+ [TaskStatus.Unstarted]: gray.dark1,
+};
+
+export const statusIconMap: Record = {
+ [TaskStatus.Failed]: whiteX,
+ [TaskStatus.TaskTimedOut]: whiteClockWithArrow,
+ [TaskStatus.TestTimedOut]: whiteClockWithArrow,
+ [TaskStatus.SetupFailed]: whiteWrench,
+ [TaskStatus.KnownIssue]: redOutlineX,
+ [TaskStatus.SystemFailed]: whiteGear,
+ [TaskStatus.SystemTimedOut]: whiteGear,
+ [TaskStatus.SystemUnresponsive]: whiteGear,
+};