From 36b2db918535fc3c50be449e2adb3b34f29e70dd Mon Sep 17 00:00:00 2001
From: minnakt <47064971+minnakt@users.noreply.github.com>
Date: Mon, 18 Dec 2023 14:11:17 -0500
Subject: [PATCH 1/8] DEVPROD-754: Add /distros redirect route (#2196)
---
.../integration/distroSettings/navigation.ts | 8 ++++++++
src/components/Content/index.tsx | 5 +++++
src/components/Header/AuxiliaryDropdown.tsx | 2 +-
.../Redirects/DistroSettingsRedirect.tsx | 19 +++++++++++++++++++
src/components/Redirects/index.ts | 2 ++
src/constants/routes.ts | 2 ++
src/hooks/useFirstDistro.ts | 17 ++++++++++-------
7 files changed, 47 insertions(+), 8 deletions(-)
create mode 100644 src/components/Redirects/DistroSettingsRedirect.tsx
diff --git a/cypress/integration/distroSettings/navigation.ts b/cypress/integration/distroSettings/navigation.ts
index 8b0e39fd26..9d92d620e6 100644
--- a/cypress/integration/distroSettings/navigation.ts
+++ b/cypress/integration/distroSettings/navigation.ts
@@ -62,3 +62,11 @@ describe("using the distro dropdown", () => {
});
});
});
+
+describe("/distros redirect route", () => {
+ it("should redirect to the first distro available", () => {
+ cy.visit("/distros");
+ cy.location("pathname").should("not.contain", "/distros");
+ cy.location("pathname").should("eq", "/distro/localhost/settings/general");
+ });
+});
diff --git a/src/components/Content/index.tsx b/src/components/Content/index.tsx
index fb016acab5..b6df1ed174 100644
--- a/src/components/Content/index.tsx
+++ b/src/components/Content/index.tsx
@@ -1,5 +1,6 @@
import { Route, Routes, Navigate } from "react-router-dom";
import {
+ DistroSettingsRedirect,
ProjectSettingsRedirect,
UserPatchesRedirect,
WaterfallCommitsRedirect,
@@ -45,6 +46,10 @@ export const Content: React.FC = () => (
}>
+ }
+ />
} />
} />
}>
diff --git a/src/components/Header/AuxiliaryDropdown.tsx b/src/components/Header/AuxiliaryDropdown.tsx
index dc71cf8b53..84c7c1e8f3 100644
--- a/src/components/Header/AuxiliaryDropdown.tsx
+++ b/src/components/Header/AuxiliaryDropdown.tsx
@@ -18,7 +18,7 @@ export const AuxiliaryDropdown: React.FC = ({
projectIdentifier,
}) => {
const { sendEvent } = useNavbarAnalytics();
- const distro = useFirstDistro();
+ const { distro } = useFirstDistro();
const menuItems = [
{
diff --git a/src/components/Redirects/DistroSettingsRedirect.tsx b/src/components/Redirects/DistroSettingsRedirect.tsx
new file mode 100644
index 0000000000..345f180668
--- /dev/null
+++ b/src/components/Redirects/DistroSettingsRedirect.tsx
@@ -0,0 +1,19 @@
+import { Navigate } from "react-router-dom";
+import {
+ getDistroSettingsRoute,
+ DistroSettingsTabRoutes,
+} from "constants/routes";
+import { useFirstDistro } from "hooks";
+
+export const DistroSettingsRedirect: React.FC = () => {
+ const { distro, loading } = useFirstDistro();
+
+ if (loading) {
+ return null;
+ }
+ return (
+
+ );
+};
diff --git a/src/components/Redirects/index.ts b/src/components/Redirects/index.ts
index bfea8f8f1c..d8b9def686 100644
--- a/src/components/Redirects/index.ts
+++ b/src/components/Redirects/index.ts
@@ -1,8 +1,10 @@
+import { DistroSettingsRedirect } from "./DistroSettingsRedirect";
import { ProjectSettingsRedirect } from "./ProjectSettingsRedirect";
import { UserPatchesRedirect } from "./UserPatchesRedirect";
import { WaterfallCommitsRedirect } from "./WaterfallCommitsRedirect";
export {
+ DistroSettingsRedirect,
ProjectSettingsRedirect,
UserPatchesRedirect,
WaterfallCommitsRedirect,
diff --git a/src/constants/routes.ts b/src/constants/routes.ts
index 777442bc65..34bf04c19c 100644
--- a/src/constants/routes.ts
+++ b/src/constants/routes.ts
@@ -56,6 +56,7 @@ const paths = {
commits: "/commits",
container: "/container",
distro: "/distro",
+ distros: "/distros",
host: "/host",
hosts: "/hosts",
jobLogs: "/job-logs",
@@ -74,6 +75,7 @@ const paths = {
waterfall: "/waterfall",
};
export const redirectRoutes = {
+ distroSettings: paths.distros,
projectSettings: paths.projects,
userPatches: `${paths.user}/:id`,
waterfall: `${paths.waterfall}/:projectIdentifier`,
diff --git a/src/hooks/useFirstDistro.ts b/src/hooks/useFirstDistro.ts
index 7c09714de3..fb0972b665 100644
--- a/src/hooks/useFirstDistro.ts
+++ b/src/hooks/useFirstDistro.ts
@@ -5,14 +5,17 @@ import { DISTROS } from "gql/queries";
/**
* `useFirstDistro` returns the alphabetically first distro from Evergreen's list of distros.
* This can be used to generate a general link to distro settings.
- * @returns the distro ID
+ * @returns an object containing the distro ID (string) and loading state (boolean)
*/
export const useFirstDistro = () => {
- const { data } = useQuery(DISTROS, {
- variables: {
- onlySpawnable: false,
- },
- });
+ const { data, loading } = useQuery(
+ DISTROS,
+ {
+ variables: {
+ onlySpawnable: false,
+ },
+ }
+ );
- return data?.distros?.[0]?.name ?? "ubuntu2204-large";
+ return { distro: data?.distros?.[0]?.name ?? "ubuntu2204-large", loading };
};
From 1c1397b15c7f83d43fa65a2086384d2f43bb32d7 Mon Sep 17 00:00:00 2001
From: Mohamed Khelif
Date: Tue, 19 Dec 2023 12:37:28 -0500
Subject: [PATCH 2/8] DEVPROD-794 Split out ETATimer and RuntimeTimer into
their own components (#2189)
---
src/hooks/index.ts | 1 +
src/hooks/useRunningTime/index.ts | 31 ++++++++++
.../useRunningTime/useRunningTime.test.ts | 49 +++++++++++++++
src/pages/task/metadata/ETATimer.tsx | 62 -------------------
.../task/metadata/ETATimer/ETATimer.test.tsx | 50 +++++++++++++++
src/pages/task/metadata/ETATimer/index.tsx | 30 +++++++++
src/pages/task/metadata/Metadata.test.tsx | 6 +-
.../RuntimeTimer/RuntimeTimer.test.tsx | 32 ++++++++++
.../task/metadata/RuntimeTimer/index.tsx | 22 +++++++
src/pages/task/metadata/index.tsx | 6 +-
src/utils/string/index.ts | 3 +
11 files changed, 226 insertions(+), 66 deletions(-)
create mode 100644 src/hooks/useRunningTime/index.ts
create mode 100644 src/hooks/useRunningTime/useRunningTime.test.ts
delete mode 100644 src/pages/task/metadata/ETATimer.tsx
create mode 100644 src/pages/task/metadata/ETATimer/ETATimer.test.tsx
create mode 100644 src/pages/task/metadata/ETATimer/index.tsx
create mode 100644 src/pages/task/metadata/RuntimeTimer/RuntimeTimer.test.tsx
create mode 100644 src/pages/task/metadata/RuntimeTimer/index.tsx
diff --git a/src/hooks/index.ts b/src/hooks/index.ts
index 540a59753b..9afda3ba11 100644
--- a/src/hooks/index.ts
+++ b/src/hooks/index.ts
@@ -25,3 +25,4 @@ export { useDateFormat } from "./useDateFormat";
export { useFirstDistro } from "./useFirstDistro";
export { useBreadcrumbRoot } from "./useBreadcrumbRoot";
export { useResize } from "./useResize";
+export { useRunningTime } from "./useRunningTime";
diff --git a/src/hooks/useRunningTime/index.ts b/src/hooks/useRunningTime/index.ts
new file mode 100644
index 0000000000..9eb23f5c61
--- /dev/null
+++ b/src/hooks/useRunningTime/index.ts
@@ -0,0 +1,31 @@
+import { useState, useEffect, useRef } from "react";
+import differenceInMilliseconds from "date-fns/differenceInMilliseconds";
+
+/**
+ * `useRunningTime` is a hook that returns the time elapsed since the start time. It refreshes every second.
+ * @param startTime - The start time of the timer
+ * @returns
+ * - `runningTime` - The running time in milliseconds
+ * - `endTimer` - A function that clears the timer
+ */
+export const useRunningTime = (startTime: Date) => {
+ const [runningTime, setRunningTime] = useState(
+ differenceInMilliseconds(Date.now(), startTime)
+ );
+
+ const timerRef = useRef(null);
+
+ useEffect(() => {
+ timerRef.current = setInterval(() => {
+ const newRunningTime = differenceInMilliseconds(Date.now(), startTime);
+ setRunningTime(newRunningTime > 0 ? newRunningTime : 0);
+ }, 1000);
+
+ return () => clearInterval(timerRef.current);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [startTime]);
+
+ const endTimer = () => clearInterval(timerRef.current);
+
+ return { runningTime, endTimer };
+};
diff --git a/src/hooks/useRunningTime/useRunningTime.test.ts b/src/hooks/useRunningTime/useRunningTime.test.ts
new file mode 100644
index 0000000000..83207bf98d
--- /dev/null
+++ b/src/hooks/useRunningTime/useRunningTime.test.ts
@@ -0,0 +1,49 @@
+import { renderHook, act } from "test_utils";
+import { useRunningTime } from "."; // Make sure to adjust the import path
+
+describe("useRunningTime", () => {
+ beforeAll(() => {
+ jest.useFakeTimers();
+ });
+ afterAll(() => {
+ jest.useRealTimers();
+ });
+
+ it("should initialize runningTime based on the provided startTime", () => {
+ const startTime = new Date();
+ const { result } = renderHook(() => useRunningTime(startTime));
+
+ expect(result.current.runningTime).toBe(0);
+ });
+ it("should update runningTime at intervals", () => {
+ const startTime = new Date();
+ const { result } = renderHook(() => useRunningTime(startTime));
+
+ act(() => {
+ jest.advanceTimersByTime(1000);
+ });
+
+ expect(result.current.runningTime).toBe(1000);
+ });
+
+ it("should stop the timer when endTimer is called", () => {
+ const startTime = new Date();
+ const { result } = renderHook(() => useRunningTime(startTime));
+
+ act(() => {
+ jest.advanceTimersByTime(1000);
+ });
+
+ expect(result.current.runningTime).toBe(1000);
+
+ act(() => {
+ result.current.endTimer();
+ });
+
+ act(() => {
+ jest.advanceTimersByTime(1000);
+ });
+
+ expect(result.current.runningTime).toBe(1000); // Should not have changed after stopping the timer
+ });
+});
diff --git a/src/pages/task/metadata/ETATimer.tsx b/src/pages/task/metadata/ETATimer.tsx
deleted file mode 100644
index fbe531ed97..0000000000
--- a/src/pages/task/metadata/ETATimer.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import { useState, useEffect } from "react";
-import { addMilliseconds, differenceInMilliseconds } from "date-fns";
-import { MetadataItem } from "components/MetadataCard";
-import { string } from "utils";
-
-const { msToDuration } = string;
-interface ETATimerProps {
- startTime: Date;
- expectedDuration: number;
-}
-export const ETATimer: React.FC = ({
- expectedDuration,
- startTime,
-}) => {
- const parsedStartTime = new Date(startTime);
- const estimatedCompletionTime = addMilliseconds(
- parsedStartTime,
- expectedDuration
- );
-
- const currentTime = Date.now();
- const [eta, setEta] = useState(
- differenceInMilliseconds(currentTime, estimatedCompletionTime)
- );
-
- const [runningTime, setRunningTime] = useState(
- differenceInMilliseconds(parsedStartTime, currentTime)
- );
-
- useEffect(() => {
- const timer = setInterval(() => {
- const newEta = differenceInMilliseconds(
- estimatedCompletionTime,
- currentTime
- );
- const newRunningTime = differenceInMilliseconds(
- currentTime,
- parsedStartTime
- );
- setEta(newEta > 0 ? newEta : 0);
- setRunningTime(newRunningTime > 0 ? newRunningTime : 0);
- }, 1000);
- if (eta === 0 || runningTime === 0) {
- clearInterval(timer);
- }
- return () => clearInterval(timer);
- });
-
- return (
- <>
-
- Running Time:{" "}
- {msToDuration(runningTime)}
-
- {eta >= 0 && (
-
- ETA: {msToDuration(eta)}
-
- )}
- >
- );
-};
diff --git a/src/pages/task/metadata/ETATimer/ETATimer.test.tsx b/src/pages/task/metadata/ETATimer/ETATimer.test.tsx
new file mode 100644
index 0000000000..57f174e155
--- /dev/null
+++ b/src/pages/task/metadata/ETATimer/ETATimer.test.tsx
@@ -0,0 +1,50 @@
+import { render, screen, waitFor, act } from "test_utils";
+import ETATimer from ".";
+
+describe("etaTimer", () => {
+ beforeEach(() => {
+ jest.useFakeTimers();
+ jest.spyOn(global, "setInterval");
+ jest.spyOn(global, "clearInterval");
+ });
+ afterEach(() => {
+ jest.useRealTimers();
+ jest.restoreAllMocks();
+ });
+ it("counts down", async () => {
+ const startTime = new Date();
+ const expectedDuration = 10000;
+ render(
+
+ );
+ expect(screen.getByText("ETA: 10s")).toBeInTheDocument();
+ act(() => {
+ jest.runOnlyPendingTimers();
+ });
+ await waitFor(() => {
+ expect(screen.getByText("ETA: 9s")).toBeInTheDocument();
+ });
+ act(() => {
+ jest.runOnlyPendingTimers();
+ });
+ await waitFor(() => {
+ expect(screen.getByText("ETA: 8s")).toBeInTheDocument();
+ });
+ });
+ it("stops counting down when it reaches 0", async () => {
+ const startTime = new Date();
+ const expectedDuration = 1000;
+ render(
+
+ );
+ expect(screen.getByText("ETA: 1s")).toBeInTheDocument();
+ act(() => {
+ jest.runOnlyPendingTimers();
+ });
+ await waitFor(() => {
+ expect(screen.getByText("ETA: 0s")).toBeInTheDocument();
+ });
+ expect(global.clearInterval).toHaveBeenCalledWith(expect.any(Number));
+ expect(jest.getTimerCount()).toBe(0);
+ });
+});
diff --git a/src/pages/task/metadata/ETATimer/index.tsx b/src/pages/task/metadata/ETATimer/index.tsx
new file mode 100644
index 0000000000..438a4e72d0
--- /dev/null
+++ b/src/pages/task/metadata/ETATimer/index.tsx
@@ -0,0 +1,30 @@
+import { useEffect } from "react";
+import { MetadataItem } from "components/MetadataCard";
+import { useRunningTime } from "hooks";
+import { string } from "utils";
+
+const { msToDuration } = string;
+
+interface ETATimerProps {
+ startTime: Date;
+ expectedDuration: number;
+}
+const ETATimer: React.FC = ({ expectedDuration, startTime }) => {
+ const parsedStartTime = new Date(startTime);
+ const { endTimer, runningTime } = useRunningTime(parsedStartTime);
+
+ useEffect(() => {
+ if (runningTime >= expectedDuration) {
+ endTimer();
+ }
+ }, [runningTime, expectedDuration, endTimer]);
+
+ const eta = expectedDuration - runningTime;
+ return (
+
+ ETA: {msToDuration(eta)}
+
+ );
+};
+
+export default ETATimer;
diff --git a/src/pages/task/metadata/Metadata.test.tsx b/src/pages/task/metadata/Metadata.test.tsx
index 2fb2685a9a..eea9e28287 100644
--- a/src/pages/task/metadata/Metadata.test.tsx
+++ b/src/pages/task/metadata/Metadata.test.tsx
@@ -26,7 +26,7 @@ describe("metadata", () => {
expect(
screen.queryByDataCy("task-metadata-estimated_start")
).toHaveTextContent("1s");
- expect(screen.queryByDataCy("metadata-eta-timer")).toBeNull();
+ expect(screen.queryByDataCy("task-metadata-eta")).toBeNull();
expect(screen.queryByDataCy("task-metadata-started")).toBeNull();
expect(screen.queryByDataCy("task-metadata-finished")).toBeNull();
});
@@ -45,7 +45,7 @@ describe("metadata", () => {
}
);
expect(screen.queryByDataCy("task-metadata-estimated_start")).toBeNull();
- expect(screen.getByDataCy("metadata-eta-timer")).toBeInTheDocument();
+ expect(screen.getByDataCy("task-metadata-eta")).toBeInTheDocument();
expect(screen.getByDataCy("task-metadata-started")).toBeInTheDocument();
expect(screen.queryByDataCy("task-metadata-finished")).toBeNull();
expect(screen.queryByDataCy("task-trace-link")).toBeNull();
@@ -69,7 +69,7 @@ describe("metadata", () => {
);
expect(screen.queryByDataCy("task-metadata-estimated_start")).toBeNull();
- expect(screen.queryByDataCy("metadata-eta-timer")).toBeNull();
+ expect(screen.queryByDataCy("task-metadata-eta")).toBeNull();
expect(screen.getByDataCy("task-metadata-started")).toBeInTheDocument();
expect(screen.getByDataCy("task-metadata-finished")).toBeInTheDocument();
expect(screen.getByDataCy("task-trace-link")).toBeInTheDocument();
diff --git a/src/pages/task/metadata/RuntimeTimer/RuntimeTimer.test.tsx b/src/pages/task/metadata/RuntimeTimer/RuntimeTimer.test.tsx
new file mode 100644
index 0000000000..fa330fee81
--- /dev/null
+++ b/src/pages/task/metadata/RuntimeTimer/RuntimeTimer.test.tsx
@@ -0,0 +1,32 @@
+import { render, screen, waitFor, act } from "test_utils";
+import RuntimeTimer from ".";
+
+describe("runtimeTimer", () => {
+ beforeEach(() => {
+ jest.useFakeTimers();
+ jest.spyOn(global, "setInterval");
+ jest.spyOn(global, "clearInterval");
+ });
+ afterEach(() => {
+ jest.useRealTimers();
+ jest.restoreAllMocks();
+ });
+ it("counts up as the run time progresses", async () => {
+ // 10 seconds ago
+ const startTime = new Date(Date.now() - 10000);
+ render();
+ expect(screen.getByText("Running Time: 10s")).toBeInTheDocument();
+ act(() => {
+ jest.runOnlyPendingTimers();
+ });
+ await waitFor(() => {
+ expect(screen.getByText("Running Time: 11s")).toBeInTheDocument();
+ });
+ act(() => {
+ jest.runOnlyPendingTimers();
+ });
+ await waitFor(() => {
+ expect(screen.getByText("Running Time: 12s")).toBeInTheDocument();
+ });
+ });
+});
diff --git a/src/pages/task/metadata/RuntimeTimer/index.tsx b/src/pages/task/metadata/RuntimeTimer/index.tsx
new file mode 100644
index 0000000000..a241da9ecc
--- /dev/null
+++ b/src/pages/task/metadata/RuntimeTimer/index.tsx
@@ -0,0 +1,22 @@
+import { MetadataItem } from "components/MetadataCard";
+import { useRunningTime } from "hooks";
+import { string } from "utils";
+
+const { msToDuration } = string;
+
+interface RuntimeTimerProps {
+ startTime: Date;
+}
+const RuntimeTimer: React.FC = ({ startTime }) => {
+ const parsedStartTime = new Date(startTime);
+
+ const { runningTime } = useRunningTime(parsedStartTime);
+
+ return (
+
+ Running Time: {msToDuration(runningTime)}
+
+ );
+};
+
+export default RuntimeTimer;
diff --git a/src/pages/task/metadata/index.tsx b/src/pages/task/metadata/index.tsx
index ddb1bdebcb..0843f9dcb0 100644
--- a/src/pages/task/metadata/index.tsx
+++ b/src/pages/task/metadata/index.tsx
@@ -36,7 +36,8 @@ import { TaskStatus } from "types/task";
import { string } from "utils";
import { AbortMessage } from "./AbortMessage";
import { DependsOn } from "./DependsOn";
-import { ETATimer } from "./ETATimer";
+import ETATimer from "./ETATimer";
+import RuntimeTimer from "./RuntimeTimer";
const { applyStrictRegex, msToDuration, shortenGithash } = string;
const { red } = palette;
@@ -165,6 +166,9 @@ export const Metadata: React.FC = ({ error, loading, task, taskId }) => {
{status === TaskStatus.Started && expectedDuration > 0 && (
)}
+ {status === TaskStatus.Started && startTime && (
+
+ )}
{startTime && (
Started:{" "}
diff --git a/src/utils/string/index.ts b/src/utils/string/index.ts
index 423024e5ee..cd9d4b2e59 100644
--- a/src/utils/string/index.ts
+++ b/src/utils/string/index.ts
@@ -9,6 +9,9 @@ export { githubPRLinkify } from "./githubPRLinkify";
* @returns - a string representing the duration in the format of "1d 2h 3m 4s"
*/
export const msToDuration = (ms: number): string => {
+ if (ms === 0) {
+ return "0s";
+ }
const days = Math.floor(ms / (24 * 60 * 60 * 1000));
const daysMilli = ms % (24 * 60 * 60 * 1000);
const hours = Math.floor(daysMilli / (60 * 60 * 1000));
From 494651f4204f9c72b90cb60078cf01b3c3b2f902 Mon Sep 17 00:00:00 2001
From: Arjun Patel
Date: Tue, 19 Dec 2023 13:14:17 -0500
Subject: [PATCH 3/8] v3.0.185
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 35ebe76697..563beb4778 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "spruce",
- "version": "3.0.184",
+ "version": "3.0.185",
"private": true,
"scripts": {
"bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh",
From d72fd8b008f20abede20036b048e1b9916b1ead0 Mon Sep 17 00:00:00 2001
From: SupaJoon
Date: Tue, 19 Dec 2023 14:17:15 -0500
Subject: [PATCH 4/8] DEVPROD-1905: Upgrade @leafygreen-ui/select to v11.1.1
(#2192)
---
cypress/integration/spawn/host.ts | 2 +-
cypress/integration/spawn/volume.ts | 2 +-
package.json | 2 +-
src/components/Hosts/UpdateStatusModal.tsx | 1 -
src/components/PageSizeSelector/index.tsx | 1 -
src/components/TupleSelect/index.tsx | 1 -
.../spawnVolume/SpawnVolumeModal.test.tsx | 5 +-
yarn.lock | 53 ++++++-------------
8 files changed, 24 insertions(+), 43 deletions(-)
diff --git a/cypress/integration/spawn/host.ts b/cypress/integration/spawn/host.ts
index 432b063564..94aaeaac21 100644
--- a/cypress/integration/spawn/host.ts
+++ b/cypress/integration/spawn/host.ts
@@ -174,7 +174,7 @@ describe("Navigating to Spawn Host page", () => {
cy.dataCy("distro-option-ubuntu1804-workstation")
.should("be.visible")
.click();
- cy.dataCy("volume-select").should("be.disabled");
+ cy.dataCy("volume-select").should("have.attr", "aria-disabled", "true");
});
it("Clicking 'Add new key' hides the key name dropdown and shows the key value text area", () => {
diff --git a/cypress/integration/spawn/volume.ts b/cypress/integration/spawn/volume.ts
index 6578a58f88..f117857230 100644
--- a/cypress/integration/spawn/volume.ts
+++ b/cypress/integration/spawn/volume.ts
@@ -270,7 +270,7 @@ describe("Spawn volume page", () => {
).click();
cy.dataCy("distro-input").click();
cy.dataCy("distro-option-ubuntu1804-workstation").click();
- cy.dataCy("region-select").should("be.disabled");
+ cy.dataCy("region-select").should("have.attr", "aria-disabled", "true");
cy.dataCy("migrate-modal").contains("Next").click({ force: true });
cy.dataCy("migrate-modal")
.contains("Migrate Volume")
diff --git a/package.json b/package.json
index 563beb4778..59cb26db7e 100644
--- a/package.json
+++ b/package.json
@@ -86,7 +86,7 @@
"@leafygreen-ui/radio-group": "10.1.1",
"@leafygreen-ui/search-input": "2.0.8",
"@leafygreen-ui/segmented-control": "8.2.6",
- "@leafygreen-ui/select": "10.2.0",
+ "@leafygreen-ui/select": "11.1.1",
"@leafygreen-ui/side-nav": "14.0.3",
"@leafygreen-ui/skeleton-loader": "1.1.0",
"@leafygreen-ui/table": "12.1.4",
diff --git a/src/components/Hosts/UpdateStatusModal.tsx b/src/components/Hosts/UpdateStatusModal.tsx
index cdbe810d82..8cd2332d97 100644
--- a/src/components/Hosts/UpdateStatusModal.tsx
+++ b/src/components/Hosts/UpdateStatusModal.tsx
@@ -113,7 +113,6 @@ export const UpdateStatusModal: React.FC = ({
);
};
-// @ts-expect-error
const StyledSelect = styled(Select)`
margin-bottom: ${size.xs};
`;
diff --git a/src/components/PageSizeSelector/index.tsx b/src/components/PageSizeSelector/index.tsx
index c4b762fdbe..ce91e5175e 100644
--- a/src/components/PageSizeSelector/index.tsx
+++ b/src/components/PageSizeSelector/index.tsx
@@ -33,7 +33,6 @@ const PageSizeSelector: React.FC = ({ onChange, value, ...rest }) => (
);
-// @ts-expect-error
const StyledSelect = styled(Select)`
width: 120px;
`;
diff --git a/src/components/TupleSelect/index.tsx b/src/components/TupleSelect/index.tsx
index 3a9140b092..5713090199 100644
--- a/src/components/TupleSelect/index.tsx
+++ b/src/components/TupleSelect/index.tsx
@@ -89,7 +89,6 @@ const LabelContainer = styled.div`
flex-direction: row;
`;
-// @ts-expect-error
const GroupedSelect = styled(Select)`
width: 30%;
/* overwrite lg borders https://jira.mongodb.org/browse/PD-1995 */
diff --git a/src/pages/spawn/spawnVolume/SpawnVolumeModal.test.tsx b/src/pages/spawn/spawnVolume/SpawnVolumeModal.test.tsx
index dd4b686c30..565c3a1edc 100644
--- a/src/pages/spawn/spawnVolume/SpawnVolumeModal.test.tsx
+++ b/src/pages/spawn/spawnVolume/SpawnVolumeModal.test.tsx
@@ -59,7 +59,10 @@ describe("spawnVolumeModal", () => {
);
expect(screen.queryByDataCy("type-select")).toHaveTextContent("gp2");
expect(screen.queryByLabelText("Never expire")).not.toBeChecked();
- expect(screen.queryByDataCy("host-select")).toBeDisabled();
+ expect(screen.queryByDataCy("host-select")).toHaveAttribute(
+ "aria-disabled",
+ "true"
+ );
expect(screen.queryByText("No hosts available.")).toBeVisible();
});
diff --git a/yarn.lock b/yarn.lock
index b8a67bf571..e8dec19340 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3229,7 +3229,7 @@
"@leafygreen-ui/tokens" "^2.1.4"
polished "^4.2.2"
-"@leafygreen-ui/button@^19.0.1", "@leafygreen-ui/button@^19.0.4":
+"@leafygreen-ui/button@^19.0.1":
version "19.0.4"
resolved "https://registry.yarnpkg.com/@leafygreen-ui/button/-/button-19.0.4.tgz#f94ea61608e56020358ac3f8cd66669f125dff64"
integrity sha512-T72lmAHS63cvhyAKaO53tNysL3xDsjnmIoaP0I55eOFOYlEy522U7vf0RMi/BsOePyAJak+x9yZ4uj8AWMCsbg==
@@ -3863,24 +3863,25 @@
lodash "^4.17.21"
polished "^4.2.2"
-"@leafygreen-ui/select@10.2.0":
- version "10.2.0"
- resolved "https://registry.yarnpkg.com/@leafygreen-ui/select/-/select-10.2.0.tgz#d5c9dd7ca6ec4f043cda45c07c7c5fad89505543"
- integrity sha512-w0/XSmN0O85jIahBxgpqGncR0b7R9As4+TNenHe0ULmEwsV1cKpNGt5qXlRyzh6dO7vYKcuSGGhvZW9fCuU/xQ==
+"@leafygreen-ui/select@11.1.1", "@leafygreen-ui/select@^11.1.0":
+ version "11.1.1"
+ resolved "https://registry.yarnpkg.com/@leafygreen-ui/select/-/select-11.1.1.tgz#b4d03071837feca1d5c206b36a1018b7d936f43f"
+ integrity sha512-aH0RNrIF3EU+5ChHJxVVjzlmFGkYRTq9DTRqm9eWgWcZIT3+ggIJCOwBNMr/8rD72NhyXm+RD8Gp2wwk8XJJrg==
dependencies:
- "@leafygreen-ui/button" "^19.0.4"
- "@leafygreen-ui/emotion" "^4.0.3"
- "@leafygreen-ui/hooks" "^7.3.3"
- "@leafygreen-ui/icon" "^11.12.4"
- "@leafygreen-ui/lib" "^10.0.0"
- "@leafygreen-ui/palette" "^3.4.7"
- "@leafygreen-ui/popover" "^11.0.4"
- "@leafygreen-ui/tokens" "^2.0.0"
- "@leafygreen-ui/typography" "^16.0.0"
- "@types/react-is" "^17.0.0"
+ "@leafygreen-ui/button" "^21.0.10"
+ "@leafygreen-ui/emotion" "^4.0.7"
+ "@leafygreen-ui/hooks" "^8.0.1"
+ "@leafygreen-ui/icon" "^11.25.0"
+ "@leafygreen-ui/input-option" "^1.0.13"
+ "@leafygreen-ui/lib" "^13.0.0"
+ "@leafygreen-ui/palette" "^4.0.7"
+ "@leafygreen-ui/popover" "^11.1.1"
+ "@leafygreen-ui/tokens" "^2.2.0"
+ "@leafygreen-ui/typography" "^18.0.1"
+ "@types/react-is" "^18.0.0"
lodash "^4.17.21"
polished "^4.1.3"
- react-is "^17.0.1"
+ react-is "^18.0.1"
"@leafygreen-ui/select@^10.1.0", "@leafygreen-ui/select@^10.3.12":
version "10.3.12"
@@ -3901,26 +3902,6 @@
polished "^4.1.3"
react-is "^17.0.1"
-"@leafygreen-ui/select@^11.1.0":
- version "11.1.1"
- resolved "https://registry.yarnpkg.com/@leafygreen-ui/select/-/select-11.1.1.tgz#b4d03071837feca1d5c206b36a1018b7d936f43f"
- integrity sha512-aH0RNrIF3EU+5ChHJxVVjzlmFGkYRTq9DTRqm9eWgWcZIT3+ggIJCOwBNMr/8rD72NhyXm+RD8Gp2wwk8XJJrg==
- dependencies:
- "@leafygreen-ui/button" "^21.0.10"
- "@leafygreen-ui/emotion" "^4.0.7"
- "@leafygreen-ui/hooks" "^8.0.1"
- "@leafygreen-ui/icon" "^11.25.0"
- "@leafygreen-ui/input-option" "^1.0.13"
- "@leafygreen-ui/lib" "^13.0.0"
- "@leafygreen-ui/palette" "^4.0.7"
- "@leafygreen-ui/popover" "^11.1.1"
- "@leafygreen-ui/tokens" "^2.2.0"
- "@leafygreen-ui/typography" "^18.0.1"
- "@types/react-is" "^18.0.0"
- lodash "^4.17.21"
- polished "^4.1.3"
- react-is "^18.0.1"
-
"@leafygreen-ui/side-nav@14.0.3":
version "14.0.3"
resolved "https://registry.yarnpkg.com/@leafygreen-ui/side-nav/-/side-nav-14.0.3.tgz#cf356dc7733e80bef88c4e33a5623c1ea028f748"
From cc5b5510ab81c2de5122cf036f50035c06a93196 Mon Sep 17 00:00:00 2001
From: Mohamed Khelif
Date: Tue, 19 Dec 2023 17:27:24 -0500
Subject: [PATCH 5/8] DEVPROD-2637 Add Guide Cue for Parsley viewable log files
(#2193)
---
cypress/integration/task/files_tables.ts | 2 +-
package.json | 2 +-
src/constants/cookies.ts | 2 +
.../GroupedFileTable.stories.tsx | 2 +
.../FileTable/GroupedFileTable/index.tsx | 70 +++++++++++++++++--
yarn.lock | 20 +++---
6 files changed, 81 insertions(+), 17 deletions(-)
diff --git a/cypress/integration/task/files_tables.ts b/cypress/integration/task/files_tables.ts
index fea7593da7..f4eacf1e2e 100644
--- a/cypress/integration/task/files_tables.ts
+++ b/cypress/integration/task/files_tables.ts
@@ -1,7 +1,7 @@
describe("files table", () => {
const FILES_ROUTE = "/task/evergreen_ubuntu1604_89/files";
const FILES_ROUTE_WITHOUT_FILES =
- "/task/evergreen_ubuntu1604_test_model_commitqueue_patch_5e823e1f28baeaa22ae00823d83e03082cd148ab_5e4ff3abe3c3317e352062e4_20_02_21_15_13_48/files ";
+ "/task/evergreen_ubuntu1604_test_model_commitqueue_patch_5e823e1f28baeaa22ae00823d83e03082cd148ab_5e4ff3abe3c3317e352062e4_20_02_21_15_13_48/files";
it("File names under name column should link to a new tab", () => {
cy.visit(FILES_ROUTE);
diff --git a/package.json b/package.json
index 59cb26db7e..cda3a8b6e9 100644
--- a/package.json
+++ b/package.json
@@ -69,7 +69,7 @@
"@leafygreen-ui/confirmation-modal": "5.0.6",
"@leafygreen-ui/emotion": "4.0.7",
"@leafygreen-ui/expandable-card": "3.0.5",
- "@leafygreen-ui/guide-cue": "5.0.4",
+ "@leafygreen-ui/guide-cue": "5.0.5",
"@leafygreen-ui/icon": "11.12.1",
"@leafygreen-ui/icon-button": "15.0.5",
"@leafygreen-ui/inline-definition": "6.0.14",
diff --git a/src/constants/cookies.ts b/src/constants/cookies.ts
index 1a7379954b..7bfabd058c 100644
--- a/src/constants/cookies.ts
+++ b/src/constants/cookies.ts
@@ -16,5 +16,7 @@ export const INCLUDE_COMMIT_QUEUE_USER_PATCHES =
"include-commit-queue-user-patches";
export const INCLUDE_HIDDEN_PATCHES = "include-hidden-patches";
export const SEEN_HONEYCOMB_GUIDE_CUE = "seen-honeycomb-guide-cue";
+export const SEEN_PARSLEY_FILES_GUIDE_CUE = "seen-parsley-files-guide-cue";
+export const SEEN_MIGRATE_GUIDE_CUE = "seen-migrate-guide-cue";
export const SLACK_NOTIFICATION_BANNER = "has-closed-slack-banner";
export const SUBSCRIPTION_METHOD = "subscription-method";
diff --git a/src/pages/task/taskTabs/FileTable/GroupedFileTable/GroupedFileTable.stories.tsx b/src/pages/task/taskTabs/FileTable/GroupedFileTable/GroupedFileTable.stories.tsx
index b8a6627cca..9a58e08c7b 100644
--- a/src/pages/task/taskTabs/FileTable/GroupedFileTable/GroupedFileTable.stories.tsx
+++ b/src/pages/task/taskTabs/FileTable/GroupedFileTable/GroupedFileTable.stories.tsx
@@ -5,10 +5,12 @@ const files = [
{
name: "some_file",
link: "some_link",
+ urlParsley: null,
},
{
name: "another_file",
link: "another_link",
+ urlParsley: "parsley_link",
},
];
diff --git a/src/pages/task/taskTabs/FileTable/GroupedFileTable/index.tsx b/src/pages/task/taskTabs/FileTable/GroupedFileTable/index.tsx
index 35a26c46ea..0da68b9e01 100644
--- a/src/pages/task/taskTabs/FileTable/GroupedFileTable/index.tsx
+++ b/src/pages/task/taskTabs/FileTable/GroupedFileTable/index.tsx
@@ -1,12 +1,15 @@
-import { useMemo, useRef } from "react";
+import { useEffect, useMemo, useRef, useState } from "react";
import styled from "@emotion/styled";
import Button from "@leafygreen-ui/button";
+import { GuideCue } from "@leafygreen-ui/guide-cue";
import { useLeafyGreenTable, LGColumnDef } from "@leafygreen-ui/table";
import Tooltip from "@leafygreen-ui/tooltip";
import { Subtitle } from "@leafygreen-ui/typography";
+import Cookies from "js-cookie";
import { useTaskAnalytics } from "analytics";
import { StyledLink } from "components/styles";
import { BaseTable } from "components/Table/BaseTable";
+import { SEEN_PARSLEY_FILES_GUIDE_CUE } from "constants/cookies";
import { size } from "constants/tokens";
import { Unpacked } from "types/utils";
import { GroupedFiles } from "../types";
@@ -14,7 +17,11 @@ import { GroupedFiles } from "../types";
type GroupedFilesFile = Unpacked;
const columns = (
- taskAnalytics: ReturnType
+ taskAnalytics: ReturnType,
+ options: {
+ gudeCueTriggerRef: React.RefObject;
+ firstParsleyFileIndex: number;
+ }
): LGColumnDef[] => [
{
accessorKey: "name",
@@ -47,6 +54,11 @@ const columns = (
target="_blank"
disabled={value.row.original.urlParsley === null}
size="small"
+ ref={
+ options && options.firstParsleyFileIndex === value.row.index
+ ? options.gudeCueTriggerRef
+ : null
+ }
onClick={() => {
taskAnalytics.sendEvent({
name: "Click Task File Parsley Link",
@@ -79,11 +91,39 @@ const GroupedFileTable: React.FC = ({
}) => {
const tableContainerRef = useRef(null);
const taskAnalytics = useTaskAnalytics();
-
+ const [openGuideCue, setOpenGuideCue] = useState(
+ Cookies.get(SEEN_PARSLEY_FILES_GUIDE_CUE) !== "true"
+ );
+ const firstParsleyFileIndex = useMemo(
+ () => files.findIndex((file) => file.urlParsley !== null),
+ [files]
+ );
+ const parsleyLinkRef = useRef(null);
const memoizedColumns = useMemo(
- () => columns(taskAnalytics),
- [taskAnalytics]
+ () =>
+ columns(
+ taskAnalytics,
+ firstParsleyFileIndex !== -1
+ ? {
+ gudeCueTriggerRef: parsleyLinkRef,
+ firstParsleyFileIndex,
+ }
+ : {
+ gudeCueTriggerRef: null,
+ firstParsleyFileIndex: -1,
+ }
+ ),
+ [taskAnalytics, firstParsleyFileIndex]
);
+ useEffect(() => {
+ // Scroll to the first file that can be opened in parsley on initial render.
+ // Since the button may not always be in view, we need to scroll to it.
+ if (firstParsleyFileIndex !== -1 && openGuideCue) {
+ parsleyLinkRef.current?.scrollIntoView();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
const table = useLeafyGreenTable({
containerRef: tableContainerRef,
data: files,
@@ -93,6 +133,26 @@ const GroupedFileTable: React.FC = ({
return (
{taskName && {taskName}}
+ {parsleyLinkRef.current !== null && (
+ {
+ Cookies.set(SEEN_PARSLEY_FILES_GUIDE_CUE, "true", {
+ expires: 365,
+ });
+ setOpenGuideCue(false);
+ }}
+ >
+ Open your file in Parsley to view it with Parsley's rich text
+ formatting capabilities.
+
+ )}
);
diff --git a/yarn.lock b/yarn.lock
index e8dec19340..ecb0a8cc3b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3242,7 +3242,7 @@
"@leafygreen-ui/tokens" "^2.0.0"
polished "^4.2.2"
-"@leafygreen-ui/button@^21.0.10", "@leafygreen-ui/button@^21.0.3", "@leafygreen-ui/button@^21.0.5", "@leafygreen-ui/button@^21.0.9":
+"@leafygreen-ui/button@^21.0.10", "@leafygreen-ui/button@^21.0.3", "@leafygreen-ui/button@^21.0.5":
version "21.0.11"
resolved "https://registry.yarnpkg.com/@leafygreen-ui/button/-/button-21.0.11.tgz#a1cfa56226d9ccdf43945441340013ff02c55fbe"
integrity sha512-NJhllsXO7jAJoAou9kPIk/B8ODYUrGxr4l4TceoAwAM3cW0kZ5kys9KA+0TOmG2AxNKLcElLu+wCg3TbssFk+Q==
@@ -3426,22 +3426,22 @@
"@leafygreen-ui/typography" "^16.0.0"
react-transition-group "^4.4.1"
-"@leafygreen-ui/guide-cue@5.0.4":
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/@leafygreen-ui/guide-cue/-/guide-cue-5.0.4.tgz#272b47f62f0957b153284a359aa423d62a8bcfe6"
- integrity sha512-L+k1EZNfvpixoMSkzds6Qr4rNkFL6f+yiKRq+2XF/lPDRHnohf06VULp0qmHs1UcUNICmMj8SP6qOYy3LyagKw==
+"@leafygreen-ui/guide-cue@5.0.5":
+ version "5.0.5"
+ resolved "https://registry.yarnpkg.com/@leafygreen-ui/guide-cue/-/guide-cue-5.0.5.tgz#bff9651b81d8c47d380280a9a5a01cf00bb9cf2e"
+ integrity sha512-E8SqC/UTypkTuxP0HHSh+AG9FpPHwgDvBb+qBYZ8xHNLODVDI81nuRSoEDZx4AUajziRQNOrIbGYnq2hjW02xw==
dependencies:
"@leafygreen-ui/a11y" "^1.4.11"
- "@leafygreen-ui/button" "^21.0.9"
+ "@leafygreen-ui/button" "^21.0.10"
"@leafygreen-ui/emotion" "^4.0.7"
- "@leafygreen-ui/hooks" "^8.0.0"
- "@leafygreen-ui/icon" "^11.23.0"
+ "@leafygreen-ui/hooks" "^8.0.1"
+ "@leafygreen-ui/icon" "^11.25.0"
"@leafygreen-ui/icon-button" "^15.0.19"
"@leafygreen-ui/lib" "^13.0.0"
"@leafygreen-ui/palette" "^4.0.7"
"@leafygreen-ui/popover" "^11.1.1"
- "@leafygreen-ui/tooltip" "^10.1.0"
- "@leafygreen-ui/typography" "^18.0.0"
+ "@leafygreen-ui/tooltip" "^11.0.0"
+ "@leafygreen-ui/typography" "^18.0.1"
focus-trap "6.9.4"
focus-trap-react "9.0.2"
polished "^4.2.2"
From 6d24d2f11e0c99b01d42797fdada8d0264ede65c Mon Sep 17 00:00:00 2001
From: Zackary Santana <64446617+ZackarySantana@users.noreply.github.com>
Date: Thu, 21 Dec 2023 13:46:39 -0500
Subject: [PATCH 6/8] DEVPROD-977 Add stepback bisect to project settings page
(#2177)
---
.../projectSettings/stepback_bisect.ts | 61 +++++++++++++++++++
.../fragments/projectSettings/general.graphql | 2 +
src/gql/generated/types.ts | 11 ++++
.../projectSettings/CopyProjectModal.test.tsx | 1 +
.../tabs/EventLogTab/EventLogTab.test.tsx | 2 +
.../tabs/GeneralTab/getFormSchema.tsx | 14 +++++
.../tabs/GeneralTab/transformers.test.ts | 4 ++
.../tabs/GeneralTab/transformers.ts | 2 +
.../projectSettings/tabs/GeneralTab/types.ts | 1 +
src/pages/projectSettings/tabs/testData.ts | 2 +
10 files changed, 100 insertions(+)
create mode 100644 cypress/integration/projectSettings/stepback_bisect.ts
diff --git a/cypress/integration/projectSettings/stepback_bisect.ts b/cypress/integration/projectSettings/stepback_bisect.ts
new file mode 100644
index 0000000000..d75b0dc18e
--- /dev/null
+++ b/cypress/integration/projectSettings/stepback_bisect.ts
@@ -0,0 +1,61 @@
+import { clickSave } from "../../utils";
+import { getGeneralRoute, project, projectUseRepoEnabled } from "./constants";
+
+describe("Stepback bisect setting", () => {
+ describe("Repo project present", () => {
+ const destination = getGeneralRoute(projectUseRepoEnabled);
+
+ beforeEach(() => {
+ cy.visit(destination);
+ });
+
+ it("Starts as default to repo", () => {
+ cy.dataCy("stepback-bisect-group")
+ .contains("Default to repo")
+ .find("input")
+ .should("have.attr", "aria-checked", "true");
+ });
+
+ it("Clicking on enabled and then save shows a success toast", () => {
+ cy.dataCy("stepback-bisect-group").contains("Enable").click();
+ clickSave();
+ cy.validateToast("success", "Successfully updated project");
+
+ cy.reload();
+
+ cy.dataCy("stepback-bisect-group")
+ .contains("Enable")
+ .find("input")
+ .should("have.attr", "aria-checked", "true");
+ });
+ });
+
+ describe("Repo project not present", () => {
+ const destination = getGeneralRoute(project);
+
+ beforeEach(() => {
+ cy.visit(destination);
+ });
+
+ it("Starts as disabled", () => {
+ cy.dataCy("stepback-bisect-group")
+ .contains("Disable")
+ .find("input")
+ .should("have.attr", "aria-checked", "true");
+ });
+
+ it("Clicking on enabled and then save shows a success toast", () => {
+ cy.dataCy("stepback-bisect-group").contains("Enable").click();
+
+ clickSave();
+ cy.validateToast("success", "Successfully updated project");
+
+ cy.reload();
+
+ cy.dataCy("stepback-bisect-group")
+ .contains("Enable")
+ .find("input")
+ .should("have.attr", "aria-checked", "true");
+ });
+ });
+});
diff --git a/src/gql/fragments/projectSettings/general.graphql b/src/gql/fragments/projectSettings/general.graphql
index 632f9a6df0..17051d8573 100644
--- a/src/gql/fragments/projectSettings/general.graphql
+++ b/src/gql/fragments/projectSettings/general.graphql
@@ -12,6 +12,7 @@ fragment ProjectGeneralSettings on Project {
repo
repotrackerDisabled
spawnHostScriptPath
+ stepbackBisect
stepbackDisabled
taskSync {
configEnabled
@@ -32,6 +33,7 @@ fragment RepoGeneralSettings on RepoRef {
repo
repotrackerDisabled
spawnHostScriptPath
+ stepbackBisect
stepbackDisabled
taskSync {
configEnabled
diff --git a/src/gql/generated/types.ts b/src/gql/generated/types.ts
index 83873f335a..3af7bd17b3 100644
--- a/src/gql/generated/types.ts
+++ b/src/gql/generated/types.ts
@@ -3459,6 +3459,7 @@ export type ProjectGeneralSettingsFragment = {
repo: string;
repotrackerDisabled?: boolean | null;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled?: boolean | null;
versionControlEnabled?: boolean | null;
taskSync: {
@@ -3481,6 +3482,7 @@ export type RepoGeneralSettingsFragment = {
repo: string;
repotrackerDisabled: boolean;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled: boolean;
versionControlEnabled: boolean;
taskSync: {
@@ -3628,6 +3630,7 @@ export type ProjectSettingsFieldsFragment = {
repo: string;
repotrackerDisabled?: boolean | null;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled?: boolean | null;
versionControlEnabled?: boolean | null;
notifyOnBuildFailure?: boolean | null;
@@ -3834,6 +3837,7 @@ export type RepoSettingsFieldsFragment = {
repo: string;
repotrackerDisabled: boolean;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled: boolean;
versionControlEnabled: boolean;
notifyOnBuildFailure: boolean;
@@ -4235,6 +4239,7 @@ export type ProjectEventSettingsFragment = {
repo: string;
repotrackerDisabled?: boolean | null;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled?: boolean | null;
notifyOnBuildFailure?: boolean | null;
githubTriggerAliases?: Array | null;
@@ -6698,6 +6703,7 @@ export type ProjectEventLogsQuery = {
repo: string;
repotrackerDisabled?: boolean | null;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled?: boolean | null;
notifyOnBuildFailure?: boolean | null;
githubTriggerAliases?: Array | null;
@@ -6910,6 +6916,7 @@ export type ProjectEventLogsQuery = {
repo: string;
repotrackerDisabled?: boolean | null;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled?: boolean | null;
notifyOnBuildFailure?: boolean | null;
githubTriggerAliases?: Array | null;
@@ -7197,6 +7204,7 @@ export type ProjectSettingsQuery = {
repo: string;
repotrackerDisabled?: boolean | null;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled?: boolean | null;
versionControlEnabled?: boolean | null;
notifyOnBuildFailure?: boolean | null;
@@ -7455,6 +7463,7 @@ export type RepoEventLogsQuery = {
repo: string;
repotrackerDisabled?: boolean | null;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled?: boolean | null;
notifyOnBuildFailure?: boolean | null;
githubTriggerAliases?: Array | null;
@@ -7667,6 +7676,7 @@ export type RepoEventLogsQuery = {
repo: string;
repotrackerDisabled?: boolean | null;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled?: boolean | null;
notifyOnBuildFailure?: boolean | null;
githubTriggerAliases?: Array | null;
@@ -7883,6 +7893,7 @@ export type RepoSettingsQuery = {
repo: string;
repotrackerDisabled: boolean;
spawnHostScriptPath: string;
+ stepbackBisect?: boolean | null;
stepbackDisabled: boolean;
versionControlEnabled: boolean;
notifyOnBuildFailure: boolean;
diff --git a/src/pages/projectSettings/CopyProjectModal.test.tsx b/src/pages/projectSettings/CopyProjectModal.test.tsx
index cd959f13ed..65aadbc0fd 100644
--- a/src/pages/projectSettings/CopyProjectModal.test.tsx
+++ b/src/pages/projectSettings/CopyProjectModal.test.tsx
@@ -290,6 +290,7 @@ const projectSettingsMock: ApolloMock<
deactivatePrevious: true,
repotrackerDisabled: false,
stepbackDisabled: null,
+ stepbackBisect: null,
patchingDisabled: false,
taskSync: {
configEnabled: false,
diff --git a/src/pages/projectSettings/tabs/EventLogTab/EventLogTab.test.tsx b/src/pages/projectSettings/tabs/EventLogTab/EventLogTab.test.tsx
index b461a90b11..c5ff25f416 100644
--- a/src/pages/projectSettings/tabs/EventLogTab/EventLogTab.test.tsx
+++ b/src/pages/projectSettings/tabs/EventLogTab/EventLogTab.test.tsx
@@ -100,6 +100,7 @@ const projectEventsQuery: ProjectEventLogsQuery = {
deactivatePrevious: true,
repotrackerDisabled: false,
stepbackDisabled: null,
+ stepbackBisect: null,
patchingDisabled: false,
taskSync: {
configEnabled: false,
@@ -186,6 +187,7 @@ const projectEventsQuery: ProjectEventLogsQuery = {
deactivatePrevious: true,
repotrackerDisabled: false,
stepbackDisabled: null,
+ stepbackBisect: null,
patchingDisabled: false,
taskSync: {
configEnabled: false,
diff --git a/src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx b/src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx
index 3e5d7d5c92..40cb116420 100644
--- a/src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx
+++ b/src/pages/projectSettings/tabs/GeneralTab/getFormSchema.tsx
@@ -165,6 +165,14 @@ export const getFormSchema = (
true
),
},
+ stepbackBisection: {
+ type: ["boolean", "null"],
+ title: "Stepback Bisection",
+ oneOf: radioBoxOptions(
+ ["Enabled", "Disabled"],
+ repoData?.projectFlags?.scheduling?.stepbackBisection
+ ),
+ },
deactivateStepback: {
type: "null" as "null",
},
@@ -342,6 +350,12 @@ export const getFormSchema = (
"ui:description":
"Disabling this setting will override all enabled stepback settings for the project. Disabling stepback won't cancel any active stepback tasks, but it will prevent any future ones.",
},
+ stepbackBisection: {
+ "ui:widget": widgets.RadioBoxWidget,
+ "ui:description":
+ "Bisection will cause your stepback to activate the midway task between the last failing task and last passing task.",
+ "ui:data-cy": "stepback-bisect-group",
+ },
deactivateStepback: {
"ui:field": "deactivateStepbackTask",
"ui:showLabel": false,
diff --git a/src/pages/projectSettings/tabs/GeneralTab/transformers.test.ts b/src/pages/projectSettings/tabs/GeneralTab/transformers.test.ts
index 9372a65bfa..8c2f41bd0f 100644
--- a/src/pages/projectSettings/tabs/GeneralTab/transformers.test.ts
+++ b/src/pages/projectSettings/tabs/GeneralTab/transformers.test.ts
@@ -47,6 +47,7 @@ const repoForm: GeneralFormState = {
scheduling: {
deactivatePrevious: true,
stepbackDisabled: true,
+ stepbackBisection: true,
deactivateStepback: null,
},
repotracker: {
@@ -81,6 +82,7 @@ const repoResult: Pick = {
repotrackerDisabled: false,
patchingDisabled: false,
stepbackDisabled: true,
+ stepbackBisect: true,
taskSync: {
configEnabled: true,
patchEnabled: true,
@@ -111,6 +113,7 @@ const projectForm: GeneralFormState = {
scheduling: {
deactivatePrevious: null,
stepbackDisabled: null,
+ stepbackBisection: null,
deactivateStepback: null,
},
repotracker: {
@@ -148,6 +151,7 @@ const projectResult: Pick = {
repotrackerDisabled: null,
patchingDisabled: null,
stepbackDisabled: null,
+ stepbackBisect: null,
taskSync: {
configEnabled: null,
patchEnabled: null,
diff --git a/src/pages/projectSettings/tabs/GeneralTab/transformers.ts b/src/pages/projectSettings/tabs/GeneralTab/transformers.ts
index 9f0307256a..f859e0fc98 100644
--- a/src/pages/projectSettings/tabs/GeneralTab/transformers.ts
+++ b/src/pages/projectSettings/tabs/GeneralTab/transformers.ts
@@ -41,6 +41,7 @@ export const gqlToForm = ((data, options = {}) => {
scheduling: {
deactivatePrevious: projectRef.deactivatePrevious,
stepbackDisabled: projectRef.stepbackDisabled,
+ stepbackBisection: projectRef.stepbackBisect,
deactivateStepback: null,
},
repotracker: {
@@ -91,6 +92,7 @@ export const formToGql = ((
deactivatePrevious: projectFlags.scheduling.deactivatePrevious,
repotrackerDisabled: projectFlags.repotracker.repotrackerDisabled,
stepbackDisabled: projectFlags.scheduling.stepbackDisabled,
+ stepbackBisect: projectFlags.scheduling.stepbackBisection,
patchingDisabled: projectFlags.patch.patchingDisabled,
taskSync: {
configEnabled: projectFlags.taskSync.configEnabled,
diff --git a/src/pages/projectSettings/tabs/GeneralTab/types.ts b/src/pages/projectSettings/tabs/GeneralTab/types.ts
index 296c36da6b..04a4d92143 100644
--- a/src/pages/projectSettings/tabs/GeneralTab/types.ts
+++ b/src/pages/projectSettings/tabs/GeneralTab/types.ts
@@ -22,6 +22,7 @@ export interface GeneralFormState {
scheduling: {
deactivatePrevious: boolean | null;
stepbackDisabled: boolean | null;
+ stepbackBisection: boolean | null;
deactivateStepback: null;
};
repotracker: {
diff --git a/src/pages/projectSettings/tabs/testData.ts b/src/pages/projectSettings/tabs/testData.ts
index 217141a0d6..9621b17e2b 100644
--- a/src/pages/projectSettings/tabs/testData.ts
+++ b/src/pages/projectSettings/tabs/testData.ts
@@ -46,6 +46,7 @@ const projectBase: ProjectSettingsQuery["projectSettings"] = {
repotrackerDisabled: null,
patchingDisabled: null,
stepbackDisabled: null,
+ stepbackBisect: null,
taskSync: {
configEnabled: null,
patchEnabled: null,
@@ -174,6 +175,7 @@ const repoBase: RepoSettingsQuery["repoSettings"] = {
notifyOnBuildFailure: false,
patchingDisabled: false,
stepbackDisabled: true,
+ stepbackBisect: true,
taskSync: {
configEnabled: true,
patchEnabled: true,
From 2b33d3044006d54ddfb97616ecc6fbd0164cb956 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 26 Dec 2023 11:57:51 -0500
Subject: [PATCH 7/8] CHORE(NPM) - bump @types/prompts from 2.4.6 to 2.4.9
(#2200)
---
package.json | 2 +-
yarn.lock | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package.json b/package.json
index cda3a8b6e9..8bcca3e1bf 100644
--- a/package.json
+++ b/package.json
@@ -158,7 +158,7 @@
"@types/new-relic-browser": "0.1212.2",
"@types/node": "^16.11.47",
"@types/pluralize": "0.0.29",
- "@types/prompts": "2.4.6",
+ "@types/prompts": "2.4.9",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0",
"@typescript-eslint/eslint-plugin": "5.57.1",
diff --git a/yarn.lock b/yarn.lock
index ecb0a8cc3b..13adcd12c1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6123,10 +6123,10 @@
resolved "https://registry.yarnpkg.com/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz#72a26101dc567b0d68fd956cf42314556e42d601"
integrity sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==
-"@types/prompts@2.4.6":
- version "2.4.6"
- resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.6.tgz#5c14794e7c8850b1d633a17a052b724bd2b019a3"
- integrity sha512-hIwnDhvsTV6XwAPo1zNy2MTelR0JmCxklIRsVxwROHLGaf6LfB+sGDkB9n+aqV4gXDz8z5MnlAz4CEC9wQDRsw==
+"@types/prompts@2.4.9":
+ version "2.4.9"
+ resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.9.tgz#8775a31e40ad227af511aa0d7f19a044ccbd371e"
+ integrity sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==
dependencies:
"@types/node" "*"
kleur "^3.0.3"
From 054203da08284f39ffefdcc6ef64b7124f1fbd5f Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 26 Dec 2023 11:59:34 -0500
Subject: [PATCH 8/8] CHORE(NPM) - bump @leafygreen-ui/icon from 11.12.1 to
11.26.0 (#2202)
---
package.json | 2 +-
yarn.lock | 15 ++++-----------
2 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/package.json b/package.json
index 8bcca3e1bf..01b440c1b5 100644
--- a/package.json
+++ b/package.json
@@ -70,7 +70,7 @@
"@leafygreen-ui/emotion": "4.0.7",
"@leafygreen-ui/expandable-card": "3.0.5",
"@leafygreen-ui/guide-cue": "5.0.5",
- "@leafygreen-ui/icon": "11.12.1",
+ "@leafygreen-ui/icon": "11.26.0",
"@leafygreen-ui/icon-button": "15.0.5",
"@leafygreen-ui/inline-definition": "6.0.14",
"@leafygreen-ui/interaction-ring": "7.0.2",
diff --git a/yarn.lock b/yarn.lock
index 13adcd12c1..61a59c198c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3512,17 +3512,10 @@
"@leafygreen-ui/palette" "^4.0.7"
"@leafygreen-ui/tokens" "^2.1.4"
-"@leafygreen-ui/icon@11.12.1":
- version "11.12.1"
- resolved "https://registry.yarnpkg.com/@leafygreen-ui/icon/-/icon-11.12.1.tgz#8ec2a8cd209c07e5e9a3b5a8f42b74afa4364573"
- integrity sha512-TOnECGHs3honiuy7JdbGXLYi7mgOzX7mJtO8Ius63pG4D0gTZZrJPE4JhXPmdOgYtZ22/pGxSCHcOHvIBYYjvw==
- dependencies:
- "@leafygreen-ui/emotion" "^4.0.3"
-
-"@leafygreen-ui/icon@^11.12.1", "@leafygreen-ui/icon@^11.12.3", "@leafygreen-ui/icon@^11.12.4", "@leafygreen-ui/icon@^11.12.5", "@leafygreen-ui/icon@^11.15.0", "@leafygreen-ui/icon@^11.17.0", "@leafygreen-ui/icon@^11.22.1", "@leafygreen-ui/icon@^11.22.2", "@leafygreen-ui/icon@^11.23.0", "@leafygreen-ui/icon@^11.25.0":
- version "11.25.0"
- resolved "https://registry.yarnpkg.com/@leafygreen-ui/icon/-/icon-11.25.0.tgz#a6cc0d54e7988cb39d3a2b1e947715b6af8f1ca2"
- integrity sha512-54nEMSj/g8cfKsh2iQ9qVr7oYSSbdpZbzrgQ/tExDuaG90UR0FJeWHzPiNbUI7hrRuLYuokn7WafsxqX6Sfr2A==
+"@leafygreen-ui/icon@11.26.0", "@leafygreen-ui/icon@^11.12.1", "@leafygreen-ui/icon@^11.12.3", "@leafygreen-ui/icon@^11.12.4", "@leafygreen-ui/icon@^11.12.5", "@leafygreen-ui/icon@^11.15.0", "@leafygreen-ui/icon@^11.17.0", "@leafygreen-ui/icon@^11.22.1", "@leafygreen-ui/icon@^11.22.2", "@leafygreen-ui/icon@^11.23.0", "@leafygreen-ui/icon@^11.25.0":
+ version "11.26.0"
+ resolved "https://registry.yarnpkg.com/@leafygreen-ui/icon/-/icon-11.26.0.tgz#2093df50445bd15758925aae9c0f40813eb817a8"
+ integrity sha512-2+sexm+uLqPC3XxQ8xDky3UhcxwGIuiWnkcG2JImNNMJSnrk87BEG0z7DdCXIpJ46+RtGDYa4B3ADxKSl9M9oQ==
dependencies:
"@leafygreen-ui/emotion" "^4.0.7"
lodash "^4.17.21"