diff --git a/cypress/integration/projectHealth/commits.ts b/cypress/integration/projectHealth/commits.ts index 0f65820e67..1b5081a750 100644 --- a/cypress/integration/projectHealth/commits.ts +++ b/cypress/integration/projectHealth/commits.ts @@ -2,40 +2,43 @@ describe("commits page", () => { beforeEach(() => { cy.visit("/commits/spruce"); }); - it("should present a default view with only failing task icons visible", () => { - cy.dataCy("waterfall-task-status-icon").should("exist"); - cy.dataCy("waterfall-task-status-icon") - .should("be.visible") - .should("have.length", 2); - cy.dataCy("waterfall-task-status-icon").should( - "have.attr", - "aria-label", - "failed icon" - ); - cy.dataCy("grouped-task-status-badge").should("not.exist"); - }); - it("shows all icons and no badges when the view is toggled", () => { - cy.dataCy("waterfall-task-status-icon").should("exist"); + describe("view", () => { + it("should present a default view with only failing task icons visible", () => { + cy.dataCy("waterfall-task-status-icon").should("exist"); + cy.dataCy("waterfall-task-status-icon") + .should("be.visible") + .should("have.length", 2); + cy.dataCy("waterfall-task-status-icon").should( + "have.attr", + "aria-label", + "failed icon" + ); + cy.dataCy("grouped-task-status-badge").should("not.exist"); + }); - cy.dataCy("view-all").click(); - cy.dataCy("waterfall-task-status-icon") - .should("be.visible") - .should("have.length", 50); - cy.dataCy("grouped-task-status-badge").should("have.length", 0); - cy.location("search").should("contain", "view=ALL"); + it("shows all icons and no badges when the view is toggled", () => { + cy.dataCy("waterfall-task-status-icon").should("exist"); - cy.dataCy("view-failed").click(); - cy.dataCy("waterfall-task-status-icon") - .should("be.visible") - .should("have.length", 2); - }); + cy.dataCy("view-all").click(); + cy.dataCy("waterfall-task-status-icon") + .should("be.visible") + .should("have.length", 50); + cy.dataCy("grouped-task-status-badge").should("have.length", 0); + cy.location("search").should("contain", "view=ALL"); + + cy.dataCy("view-failed").click(); + cy.dataCy("waterfall-task-status-icon") + .should("be.visible") + .should("have.length", 2); + }); - it("shows all icons when loaded with the view all query param", () => { - cy.visit(`/commits/spruce?view=ALL`); - cy.dataCy("waterfall-task-status-icon") - .should("be.visible") - .should("have.length", 50); + it("shows all icons when loaded with the view all query param", () => { + cy.visit(`/commits/spruce?view=ALL`); + cy.dataCy("waterfall-task-status-icon") + .should("be.visible") + .should("have.length", 50); + }); }); it("should be able to collapse/expand commit graph which retains state when paginating", () => { @@ -97,21 +100,7 @@ describe("commits page", () => { cy.dataCy("prev-page-button").click(); cy.dataCy("prev-page-button").should("have.attr", "aria-disabled", "true"); }); - it("should only show matching requester filters", () => { - cy.dataCy("requester-select").click(); - cy.dataCy("requester-select-options").should("be.visible"); - cy.dataCy("requester-select-options").within(() => { - cy.getInputByLabel("Git Tag").should("exist"); - cy.getInputByLabel("Git Tag").should("not.be.checked"); - cy.getInputByLabel("Git Tag").check({ force: true }); - }); - cy.dataCy("requester-select").click(); - cy.dataCy("requester-select-options").should("not.exist"); - cy.dataCy("commit-label").should("exist"); - cy.dataCy("commit-label").each(($el) => { - cy.wrap($el).should("contain.text", "Git Tag"); - }); - }); + it("resizing the page adjusts the number of commits rendered", () => { cy.visit("/commits/spruce"); cy.dataCy("commit-chart-container").should("have.length", 9); @@ -120,94 +109,7 @@ describe("commits page", () => { cy.viewport(1280, 1024); cy.dataCy("commit-chart-container").should("have.length", 6); }); - describe("task filtering", () => { - beforeEach(() => { - cy.visit("/commits/spruce"); - }); - it("applying an `all` status filter should show all matching tasks with non failing tasks grouped", () => { - cy.dataCy("project-task-status-select").should("exist"); - cy.dataCy("project-task-status-select").click(); - cy.dataCy("project-task-status-select-options").should("be.visible"); - cy.dataCy("project-task-status-select-options").within(() => { - cy.getInputByLabel("All").should("exist"); - cy.getInputByLabel("All").should("not.be.checked"); - cy.getInputByLabel("All").check({ force: true }); - }); - cy.dataCy("project-task-status-select").click(); - cy.dataCy("project-task-status-select-options").should("not.exist"); - cy.dataCy("grouped-task-status-badge").should("have.length", 9); - cy.dataCy("waterfall-task-status-icon").should("have.length", 2); - }); - it("applying a status filter should only show matching tasks", () => { - cy.dataCy("project-task-status-select").should("exist"); - cy.dataCy("project-task-status-select").click(); - cy.dataCy("project-task-status-select-options").should("be.visible"); - cy.dataCy("project-task-status-select-options").within(() => { - cy.getInputByLabel("Succeeded").should("exist"); - cy.getInputByLabel("Succeeded").should("not.be.checked"); - cy.getInputByLabel("Succeeded").check({ force: true }); - }); - cy.dataCy("project-task-status-select").click(); - cy.dataCy("project-task-status-select-options").should("not.exist"); - cy.dataCy("grouped-task-status-badge").should("have.length", 9); - cy.dataCy("grouped-task-status-badge").should( - "contain.text", - "Succeeded" - ); - cy.dataCy("waterfall-task-status-icon").should("not.exist"); - }); - it("applying a build variant filter should show all task statuses by default", () => { - cy.getInputByLabel("Add New Filter").type("Ubuntu").type("{enter}"); - cy.dataCy("filter-badge").should("have.length", 1); - cy.dataCy("filter-badge").should("have.text", "buildVariants: Ubuntu"); - cy.location("search").should("contain", "?buildVariants=Ubuntu"); - cy.dataCy("grouped-task-status-badge").should("have.length", 9); - cy.dataCy("waterfall-task-status-icon").should("have.length", 2); - cy.dataCy("waterfall-task-status-icon").should( - "have.attr", - "aria-label", - "failed icon" - ); - }); - it("applying a task filter should show all task icons instead of groupings", () => { - cy.contains("button", "Build Variant").should("exist"); - cy.contains("button", "Build Variant").click({ force: true }); - cy.get("li").contains("Task").should("be.visible"); - cy.get("li").contains("Task").click(); - cy.getInputByLabel("Add New Filter").type(".").type("{enter}"); - cy.dataCy("grouped-task-status-badge").should("not.exist"); - cy.dataCy("waterfall-task-status-icon").should("have.length", 51); - cy.dataCy("waterfall-task-status-icon") - .get("[aria-label='failed icon']") - .should("exist"); - cy.dataCy("waterfall-task-status-icon") - .get("[aria-label='failed icon']") - .should("have.length", 2); - cy.dataCy("waterfall-task-status-icon") - .get("[aria-label='success icon']") - .should("exist"); - cy.dataCy("waterfall-task-status-icon") - .get("[aria-label='success icon']") - .should("have.length", 49); - }); - it("should hide commits that don't match applied filters", () => { - cy.dataCy("project-task-status-select").should("exist"); - cy.dataCy("project-task-status-select").click(); - cy.dataCy("project-task-status-select-options").should("be.visible"); - cy.dataCy("project-task-status-select-options").within(() => { - cy.getInputByLabel("Failed").should("exist"); - cy.getInputByLabel("Failed").should("not.be.checked"); - cy.getInputByLabel("Failed").check({ force: true }); - }); - cy.dataCy("project-task-status-select").click(); - cy.dataCy("project-task-status-select-options").should("not.exist"); - cy.dataCy("grouped-task-status-badge").should("not.exist"); - cy.dataCy("inactive-commits-button").should("have.length", 5); - cy.dataCy("inactive-commits-button").each(($el) => { - cy.wrap($el).should("contain.text", "Unmatching"); - }); - }); - }); + describe("inactive / unmatching commit tooltips", () => { beforeEach(() => { cy.visit("/commits/spruce"); @@ -295,4 +197,42 @@ describe("commits page", () => { }); }); }); + + describe("search by git commit", () => { + const revision = "aac24c894994e44a2dadc6db40b46eb82e41f2cc"; + + beforeEach(() => { + cy.visit("/commits/spruce"); + cy.dataCy("waterfall-menu").click(); + cy.dataCy("git-commit-search").click(); + cy.dataCy("git-commit-search-modal").should("be.visible"); + cy.getInputByLabel("Git Commit Hash").type(revision); + cy.contains("button", "Submit").click(); + cy.location("search").should("contain", `revision=${revision}`); + }); + + it("should jump to the given commit", () => { + cy.get("[data-selected='true']").should("be.visible"); + cy.get("[data-selected='true']").should( + "contain.text", + revision.substring(0, 7) + ); + }); + + it("should be possible to paginate from the given commit", () => { + cy.get("[data-selected='true']").should("be.visible"); + + cy.dataCy("next-page-button").click(); + cy.get("[data-selected='true']").should("not.exist"); + cy.dataCy("prev-page-button").click(); + + cy.get("[data-selected='true']").should("be.visible"); + + cy.dataCy("prev-page-button").click(); + cy.get("[data-selected='true']").should("not.exist"); + cy.dataCy("next-page-button").click(); + + cy.get("[data-selected='true']").should("be.visible"); + }); + }); }); diff --git a/cypress/integration/projectHealth/filtering.ts b/cypress/integration/projectHealth/filtering.ts new file mode 100644 index 0000000000..d43128f1ae --- /dev/null +++ b/cypress/integration/projectHealth/filtering.ts @@ -0,0 +1,107 @@ +describe("filtering", () => { + beforeEach(() => { + cy.visit("/commits/spruce"); + }); + + it("should only show matching requester filters", () => { + cy.dataCy("requester-select").click(); + cy.dataCy("requester-select-options").should("be.visible"); + cy.dataCy("requester-select-options").within(() => { + cy.getInputByLabel("Git Tag").should("exist"); + cy.getInputByLabel("Git Tag").should("not.be.checked"); + cy.getInputByLabel("Git Tag").check({ force: true }); + }); + cy.dataCy("requester-select").click(); + cy.dataCy("requester-select-options").should("not.exist"); + cy.dataCy("commit-label").should("exist"); + cy.dataCy("commit-label").each(($el) => { + cy.wrap($el).should("contain.text", "Git Tag"); + }); + }); + + describe("task filtering", () => { + it("applying an `all` status filter should show all matching tasks with non failing tasks grouped", () => { + cy.dataCy("project-task-status-select").should("exist"); + cy.dataCy("project-task-status-select").click(); + cy.dataCy("project-task-status-select-options").should("be.visible"); + cy.dataCy("project-task-status-select-options").within(() => { + cy.getInputByLabel("All").should("exist"); + cy.getInputByLabel("All").should("not.be.checked"); + cy.getInputByLabel("All").check({ force: true }); + }); + cy.dataCy("project-task-status-select").click(); + cy.dataCy("project-task-status-select-options").should("not.exist"); + cy.dataCy("grouped-task-status-badge").should("have.length", 9); + cy.dataCy("waterfall-task-status-icon").should("have.length", 2); + }); + it("applying a status filter should only show matching tasks", () => { + cy.dataCy("project-task-status-select").should("exist"); + cy.dataCy("project-task-status-select").click(); + cy.dataCy("project-task-status-select-options").should("be.visible"); + cy.dataCy("project-task-status-select-options").within(() => { + cy.getInputByLabel("Succeeded").should("exist"); + cy.getInputByLabel("Succeeded").should("not.be.checked"); + cy.getInputByLabel("Succeeded").check({ force: true }); + }); + cy.dataCy("project-task-status-select").click(); + cy.dataCy("project-task-status-select-options").should("not.exist"); + cy.dataCy("grouped-task-status-badge").should("have.length", 9); + cy.dataCy("grouped-task-status-badge").should( + "contain.text", + "Succeeded" + ); + cy.dataCy("waterfall-task-status-icon").should("not.exist"); + }); + it("applying a build variant filter should show all task statuses by default", () => { + cy.getInputByLabel("Add New Filter").type("Ubuntu{enter}"); + cy.dataCy("filter-badge").should("have.length", 1); + cy.dataCy("filter-badge").should("have.text", "buildVariants: Ubuntu"); + cy.location("search").should("contain", "?buildVariants=Ubuntu"); + cy.dataCy("grouped-task-status-badge").should("have.length", 9); + cy.dataCy("waterfall-task-status-icon").should("have.length", 2); + cy.dataCy("waterfall-task-status-icon").should( + "have.attr", + "aria-label", + "failed icon" + ); + }); + it("applying a task filter should show all task icons instead of groupings", () => { + cy.contains("button", "Build Variant").should("exist"); + cy.contains("button", "Build Variant").click({ force: true }); + cy.get("li").contains("Task").should("be.visible"); + cy.get("li").contains("Task").click(); + cy.getInputByLabel("Add New Filter").type(".{enter}"); + cy.dataCy("grouped-task-status-badge").should("not.exist"); + cy.dataCy("waterfall-task-status-icon").should("have.length", 51); + cy.dataCy("waterfall-task-status-icon") + .get("[aria-label='failed icon']") + .should("exist"); + cy.dataCy("waterfall-task-status-icon") + .get("[aria-label='failed icon']") + .should("have.length", 2); + cy.dataCy("waterfall-task-status-icon") + .get("[aria-label='success icon']") + .should("exist"); + cy.dataCy("waterfall-task-status-icon") + .get("[aria-label='success icon']") + .should("have.length", 49); + }); + it("should hide commits that don't match applied filters", () => { + cy.dataCy("project-task-status-select").should("exist"); + cy.dataCy("project-task-status-select").click(); + cy.dataCy("project-task-status-select-options").should("be.visible"); + cy.dataCy("project-task-status-select-options").within(() => { + cy.getInputByLabel("Failed").should("exist"); + cy.getInputByLabel("Failed").should("not.be.checked"); + cy.getInputByLabel("Failed").check({ force: true }); + }); + cy.dataCy("project-task-status-select").click(); + cy.dataCy("project-task-status-select-options").should("not.exist"); + cy.dataCy("grouped-task-status-badge").should("not.exist"); + cy.dataCy("inactive-commits-button").should("have.length", 5); + cy.dataCy("inactive-commits-button").each(($el) => { + cy.wrap($el).should("contain.text", "Unmatching"); + }); + }); + }); +}); diff --git a/src/analytics/projectHealth/useProjectHealthAnalytics.ts b/src/analytics/projectHealth/useProjectHealthAnalytics.ts index e24d96a98c..6ec3a4f01d 100644 --- a/src/analytics/projectHealth/useProjectHealthAnalytics.ts +++ b/src/analytics/projectHealth/useProjectHealthAnalytics.ts @@ -38,6 +38,8 @@ type Action = name: "Toggle commit chart label tooltip"; } | { name: "Open Notification Modal" } + | { name: "Open Git Commit Search Modal" } + | { name: "Search for commit"; commit: string } | { name: "Add Notification"; subscription: SaveSubscriptionForUserMutationVariables["subscription"]; diff --git a/src/components/ButtonDropdown.tsx b/src/components/ButtonDropdown.tsx index 957598d776..4de498adbe 100644 --- a/src/components/ButtonDropdown.tsx +++ b/src/components/ButtonDropdown.tsx @@ -9,6 +9,8 @@ interface Props { dropdownItems: JSX.Element[]; size?: "default" | "small" | "large"; "data-cy"?: string; + open?: boolean; + setOpen?: (open: boolean) => void; } export const ButtonDropdown: React.FC = ({ @@ -16,6 +18,8 @@ export const ButtonDropdown: React.FC = ({ disabled = false, dropdownItems, loading = false, + open = undefined, + setOpen = undefined, size = "small", }) => ( = ({ data-cy="card-dropdown" popoverZIndex={zIndex.popover} adjustOnMutation + open={open} + setOpen={setOpen} > {dropdownItems} diff --git a/src/gql/generated/types.ts b/src/gql/generated/types.ts index ee8713b798..2304720817 100644 --- a/src/gql/generated/types.ts +++ b/src/gql/generated/types.ts @@ -933,6 +933,7 @@ export type MainlineCommitsOptions = { limit?: InputMaybe; projectIdentifier: Scalars["String"]["input"]; requesters?: InputMaybe>; + revision?: InputMaybe; shouldCollapse?: InputMaybe; skipOrderNumber?: InputMaybe; }; diff --git a/src/pages/commits/CommitChart/index.tsx b/src/pages/commits/CommitChart/index.tsx index edf16c39dd..fff9b5a56c 100644 --- a/src/pages/commits/CommitChart/index.tsx +++ b/src/pages/commits/CommitChart/index.tsx @@ -26,12 +26,12 @@ const DEFAULT_OPEN_STATE = true; interface Props { versions?: Commits; hasTaskFilter?: boolean; - hasError?: boolean; + noData?: boolean; } export const CommitChart: React.FC = ({ - hasError = false, hasTaskFilter, + noData = false, versions, }) => { const [chartOpen, setChartOpen] = useQueryParam( @@ -70,7 +70,7 @@ export const CommitChart: React.FC = ({ const onToggleAccordion = ({ isVisible }) => Cookies.set(COMMIT_CHART_TYPE_VIEW_OPTIONS_ACCORDION, isVisible.toString()); - return hasError ? ( + return noData ? ( diff --git a/src/pages/commits/CommitsWrapper.tsx b/src/pages/commits/CommitsWrapper.tsx index bc00586e33..19e41710c5 100644 --- a/src/pages/commits/CommitsWrapper.tsx +++ b/src/pages/commits/CommitsWrapper.tsx @@ -1,5 +1,4 @@ import { useMemo } from "react"; -import { ApolloError } from "@apollo/client"; import styled from "@emotion/styled"; import { palette } from "@leafygreen-ui/palette"; import { Skeleton } from "antd"; @@ -9,6 +8,7 @@ import { CommitChart } from "./CommitChart"; import { getCommitKey, getCommitWidth, + isCommitSelected, RenderCommitsLabel, RenderCommitsBuildVariants, } from "./RenderCommit"; @@ -19,17 +19,17 @@ const { white } = palette; interface CommitsWrapperProps { versions: Commits; - error?: ApolloError; isLoading: boolean; hasTaskFilter: boolean; hasFilters: boolean; + revision?: string; } export const CommitsWrapper: React.FC = ({ - error, hasFilters, hasTaskFilter, isLoading, + revision, versions, }) => { const buildVariantDict = useMemo(() => { @@ -38,12 +38,12 @@ export const CommitsWrapper: React.FC = ({ } }, [versions]); - if (error) { - return ; - } if (isLoading) { return ; } + if (!versions) { + return ; + } if (versions) { return ( @@ -54,6 +54,8 @@ export const CommitsWrapper: React.FC = ({ @@ -65,6 +67,7 @@ export const CommitsWrapper: React.FC = ({ = ({ name: "Paginate", direction: "previous", }); - // 0 is the first page so we can just omit the query param updateQueryParams({ [MainlineCommitQueryParams.SkipOrderNumber]: - prevPageOrderNumber > 0 ? prevPageOrderNumber.toString() : undefined, + prevPageOrderNumber.toString(), }); }; return ( diff --git a/src/pages/commits/ProjectHealth.stories.tsx b/src/pages/commits/ProjectHealth.stories.tsx index 98b8d2d5fa..48b3106723 100644 --- a/src/pages/commits/ProjectHealth.stories.tsx +++ b/src/pages/commits/ProjectHealth.stories.tsx @@ -59,7 +59,6 @@ const RenderCommitsWrapper = ({
{ throw new Error("Commit type not found"); }; -export { RenderCommitsChart, RenderCommitsLabel, getCommitKey, getCommitWidth }; +const isCommitSelected = (commit: Commit, revision: string) => { + const { rolledUpVersions, version } = commit; + + if (revision.trim() === "") { + return false; + } + if (version && version.revision.includes(revision)) { + return true; + } + if ( + rolledUpVersions && + rolledUpVersions.some((v) => v.revision.includes(revision)) + ) { + return true; + } + return false; +}; + +export { + RenderCommitsChart, + RenderCommitsLabel, + getCommitKey, + getCommitWidth, + isCommitSelected, +}; diff --git a/src/pages/commits/WaterfallMenu/AddNotification.tsx b/src/pages/commits/WaterfallMenu/AddNotification.tsx index 381fe4c87d..1f44e1eb77 100644 --- a/src/pages/commits/WaterfallMenu/AddNotification.tsx +++ b/src/pages/commits/WaterfallMenu/AddNotification.tsx @@ -6,7 +6,13 @@ import { NotificationModal } from "components/Notifications"; import { waterfallTriggers } from "constants/triggers"; import { subscriptionMethods } from "types/subscription"; -export const AddNotification: React.FC = () => { +interface AddNotificationProps { + setMenuOpen: (open: boolean) => void; +} + +export const AddNotification: React.FC = ({ + setMenuOpen, +}) => { const { projectIdentifier } = useParams<{ projectIdentifier: string }>(); const [isModalVisible, setIsModalVisible] = useState(false); const { sendEvent } = useProjectHealthAnalytics({ page: "Commit chart" }); @@ -23,7 +29,10 @@ export const AddNotification: React.FC = () => { setIsModalVisible(false)} + onCancel={() => { + setIsModalVisible(false); + setMenuOpen(false); + }} resourceId={projectIdentifier} sendAnalyticsEvent={(subscription) => sendEvent({ name: "Add Notification", subscription }) diff --git a/src/pages/commits/WaterfallMenu/GitCommitSearch.tsx b/src/pages/commits/WaterfallMenu/GitCommitSearch.tsx new file mode 100644 index 0000000000..75b662a2a0 --- /dev/null +++ b/src/pages/commits/WaterfallMenu/GitCommitSearch.tsx @@ -0,0 +1,62 @@ +import { useState } from "react"; +import TextInput from "@leafygreen-ui/text-input"; +import { useProjectHealthAnalytics } from "analytics/projectHealth/useProjectHealthAnalytics"; +import { DropdownItem } from "components/ButtonDropdown"; +import { ConfirmationModal } from "components/ConfirmationModal"; +import { useUpdateURLQueryParams } from "hooks/useUpdateURLQueryParams"; +import { MainlineCommitQueryParams } from "types/commits"; + +interface GitCommitSearchProps { + setMenuOpen: (open: boolean) => void; +} + +export const GitCommitSearch: React.FC = ({ + setMenuOpen, +}) => { + const { sendEvent } = useProjectHealthAnalytics({ page: "Commit chart" }); + const updateQueryParams = useUpdateURLQueryParams(); + + const [isModalVisible, setIsModalVisible] = useState(false); + const [commitHash, setCommitHash] = useState(""); + + const onSubmit = () => { + sendEvent({ name: "Search for commit", commit: commitHash }); + updateQueryParams({ + [MainlineCommitQueryParams.Revision]: commitHash, + [MainlineCommitQueryParams.SkipOrderNumber]: undefined, + }); + setIsModalVisible(false); + setMenuOpen(false); + }; + + return ( + <> + { + setIsModalVisible(true); + sendEvent({ name: "Open Git Commit Search Modal" }); + }} + > + Search by Git Commit + + setIsModalVisible(false)} + onConfirm={onSubmit} + open={isModalVisible} + // Force user to input at least 7 characters of the hash. + submitDisabled={commitHash.trim().length < 7} + title="Search by Git Commit Hash" + > + setCommitHash(e.target.value)} + onKeyPress={(e) => e.key === "Enter" && onSubmit()} + value={commitHash} + /> + + + ); +}; diff --git a/src/pages/commits/WaterfallMenu/index.tsx b/src/pages/commits/WaterfallMenu/index.tsx index 9cd1d93441..8b31987f31 100644 --- a/src/pages/commits/WaterfallMenu/index.tsx +++ b/src/pages/commits/WaterfallMenu/index.tsx @@ -1,14 +1,23 @@ +import { useState } from "react"; import { ButtonDropdown } from "components/ButtonDropdown"; import { AddNotification } from "./AddNotification"; +import { GitCommitSearch } from "./GitCommitSearch"; export const WaterfallMenu: React.FC = () => { - const dropdownItems = []; + const [menuOpen, setMenuOpen] = useState(false); + + const dropdownItems = [ + , + , + ]; return ( ); }; diff --git a/src/pages/commits/index.tsx b/src/pages/commits/index.tsx index 058891d163..13a0926a44 100644 --- a/src/pages/commits/index.tsx +++ b/src/pages/commits/index.tsx @@ -107,7 +107,13 @@ const Commits = () => { const skipOrderNumberParam = getString( parsed[MainlineCommitQueryParams.SkipOrderNumber] ); - const skipOrderNumber = parseInt(skipOrderNumberParam, 10) || undefined; + const revision = getString(parsed[MainlineCommitQueryParams.Revision]); + + const parsedSkipNum = parseInt(skipOrderNumberParam, 10); + const skipOrderNumber = Number.isNaN(parsedSkipNum) + ? undefined + : parsedSkipNum; + const filterState = { statuses: statusFilters, variants: variantFilters, @@ -115,27 +121,31 @@ const Commits = () => { requesters: requesterFilters, view: viewFilter || ProjectHealthView.Failed, }; + const variables = getMainlineCommitsQueryVariables({ mainlineCommitOptions: { projectIdentifier, skipOrderNumber, limit, + revision, }, filterState, }); const { hasFilters, hasTasks } = getFilterStatus(filterState); - const { data, error, loading, refetch, startPolling, stopPolling } = useQuery< + const { data, loading, refetch, startPolling, stopPolling } = useQuery< MainlineCommitsQuery, MainlineCommitsQueryVariables >(MAINLINE_COMMITS, { skip: !projectIdentifier || isResizing, + errorPolicy: "all", fetchPolicy: "cache-and-network", variables, pollInterval: DEFAULT_POLL_INTERVAL, - onError: (e) => - dispatchToast.error(`There was an error loading the page: ${e.message}`), + onError: (e) => { + dispatchToast.error(`There was an error loading the page: ${e.message}`); + }, }); usePolling({ startPolling, stopPolling, refetch }); @@ -220,7 +230,7 @@ const Commits = () => {
` +export const CommitWrapper = styled.div<{ + width: number; + selected?: boolean; +}>` + background-color: ${({ selected }) => + selected ? blue.light3 : "transparent"}; width: ${({ width }) => width}px; min-width: ${({ width }) => width * 0.75}px; + align-self: stretch; margin: 0px ${size.xs}; &:first-of-type { diff --git a/src/pages/commits/utils.test.ts b/src/pages/commits/utils.test.ts index 3ab7b13afb..3f68fc8d4f 100644 --- a/src/pages/commits/utils.test.ts +++ b/src/pages/commits/utils.test.ts @@ -80,6 +80,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -104,6 +105,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -126,6 +128,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Succeeded], @@ -148,6 +151,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -170,6 +174,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -196,6 +201,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -217,6 +223,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Failed], @@ -238,6 +245,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -263,6 +271,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -285,6 +294,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Failed], @@ -305,6 +315,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -325,6 +336,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -349,6 +361,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -373,6 +386,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -397,6 +411,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Succeeded], @@ -421,6 +436,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Succeeded], @@ -445,6 +461,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Failed, TaskStatus.Succeeded], @@ -468,6 +485,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -489,6 +507,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Succeeded], @@ -512,6 +531,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -538,6 +558,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -561,6 +582,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -584,6 +606,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Succeeded], @@ -607,6 +630,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Succeeded], @@ -630,6 +654,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Succeeded, TaskStatus.Failed], @@ -652,6 +677,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Failed], @@ -674,6 +700,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -696,6 +723,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [], @@ -716,6 +744,7 @@ describe("getMainlineCommitsQueryVariables", () => { projectIdentifier: "projectIdentifier", limit: 5, skipOrderNumber: 0, + revision: "", }, filterState: { statuses: [TaskStatus.Failed], diff --git a/src/pages/commits/utils.ts b/src/pages/commits/utils.ts index a55375856d..ca761c12ab 100644 --- a/src/pages/commits/utils.ts +++ b/src/pages/commits/utils.ts @@ -31,6 +31,7 @@ interface MainlineCommitOptions { projectIdentifier: string; limit: number; skipOrderNumber: number; + revision: string; } interface CommitsPageReducerState { filterState: FilterState; diff --git a/src/types/commits.ts b/src/types/commits.ts index 34d901dc7c..fd76f49427 100644 --- a/src/types/commits.ts +++ b/src/types/commits.ts @@ -17,6 +17,7 @@ export enum ChartToggleQueryParams { export enum MainlineCommitQueryParams { Requester = "requester", SkipOrderNumber = "skipOrderNumber", + Revision = "revision", } export enum ChartTypes {