From fc0b56154749f4638a6e0781e8b857b1c9d6a281 Mon Sep 17 00:00:00 2001 From: Mohamed Khelif Date: Wed, 24 Jan 2024 16:46:58 -0500 Subject: [PATCH 1/4] DEVPROD-801 Remove axios (#2238) --- package.json | 1 - src/utils/request.test.js | 27 ---------------------- src/utils/request.test.ts | 48 +++++++++++++++++++++++++++++++++++++++ src/utils/request.ts | 42 ++++++++++------------------------ yarn.lock | 11 +-------- 5 files changed, 61 insertions(+), 68 deletions(-) delete mode 100644 src/utils/request.test.js create mode 100644 src/utils/request.test.ts diff --git a/package.json b/package.json index 40dd7ee1fb..0ffde827dc 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,6 @@ "@sentry/types": "7.56.0", "ansi_up": "6.0.2", "antd": "4.20.0", - "axios": "1.6.1", "date-fns": "2.28.0", "date-fns-tz": "2.0.0", "deep-object-diff": "1.1.9", diff --git a/src/utils/request.test.js b/src/utils/request.test.js deleted file mode 100644 index 74bad5dce6..0000000000 --- a/src/utils/request.test.js +++ /dev/null @@ -1,27 +0,0 @@ -import axios from "axios"; -import { post } from "./request"; - -const API_URL = "/some/endpoint"; - -const jsonMessage = "got JSON response"; - -const mockApi = { - statusText: "OK", - data: jsonMessage, -}; - -jest.mock("axios"); - -test("posts", async () => { - axios.post.mockImplementationOnce(() => Promise.resolve(mockApi)); - const response = await post(API_URL, {}); - expect(response.data).toBe(jsonMessage); -}); - -test("should handle a bad response", async () => { - const errorCallback = jest.fn(); - axios.post.mockImplementationOnce(() => Promise.resolve(jsonMessage)); - - expect(await post(API_URL, {}, { onFailure: errorCallback })).toBe(undefined); - expect(errorCallback).toHaveBeenCalledTimes(1); -}); diff --git a/src/utils/request.test.ts b/src/utils/request.test.ts new file mode 100644 index 0000000000..6dbfbf19f7 --- /dev/null +++ b/src/utils/request.test.ts @@ -0,0 +1,48 @@ +import { post } from "./request"; + +describe("post", () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it("should make a POST request and return the response for a successful request", async () => { + const url = "/api/resource"; + const body = { key: "value" }; + const fetchMock = jest.fn().mockResolvedValue({ + ok: true, + }); + + jest.spyOn(global, "fetch").mockImplementation(fetchMock); + + const response = await post(url, body); + + expect(response).toStrictEqual({ ok: true }); + expect(fetchMock).toHaveBeenCalledWith("/api/resource", { + method: "POST", + body: JSON.stringify(body), + credentials: "include", + }); + }); + + it("should handle and report an error for a failed request", async () => { + const url = "/api/resource"; + const body = { key: "value" }; + const fetchMock = jest.fn().mockResolvedValue({ + ok: false, + status: 500, + statusText: "Internal Server Error", + }); + const errorReportingMock = jest.fn(); + jest.spyOn(console, "error").mockImplementation(errorReportingMock); + jest.spyOn(global, "fetch").mockImplementation(fetchMock); + + await post(url, body); + + expect(fetchMock).toHaveBeenCalledWith("/api/resource", { + method: "POST", + body: JSON.stringify(body), + credentials: "include", + }); + expect(errorReportingMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/utils/request.ts b/src/utils/request.ts index ab8c55a8a9..a4846eb22e 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,44 +1,26 @@ -import axios from "axios"; import { getUiUrl } from "./environmentVariables"; import { reportError } from "./errorReporting"; -type optionsType = { - onFailure?: (e) => void; -}; -export const post = async ( - url: string, - body: unknown, - options: optionsType = {}, -) => { +export const post = async (url: string, body: unknown) => { try { - const response = await axios.post( - `${getUiUrl()}${url}`, - { body }, - { withCredentials: true }, - ); - if (isBadResponse(response)) { - throw new Error(getErrorMessage(response, "POST")); + const response = await fetch(`${getUiUrl()}${url}`, { + method: "POST", + body: JSON.stringify(body), + credentials: "include", + }); + if (!response.ok) { + throw new Error(await getErrorMessage(response, "POST")); } return response; - } catch (e) { - if (options.onFailure) { - options.onFailure(e); - } + } catch (e: any) { handleError(e); } }; -const isBadResponse = (response) => - !response || (response && response.statusText !== "OK"); - -type responseType = { - status: number; - statusText: string; +const getErrorMessage = async (response: Response, method: string) => { + const { status, statusText } = response; + return `${method} Error: ${status} - ${statusText}`; }; -const getErrorMessage = (response: responseType, method: string) => - response - ? `${method} Error: ${response.status} - ${response.statusText}` - : `${method} Error: Did not receive a response from the server`; const handleError = (error: string) => { reportError(new Error(error)).warning(); diff --git a/yarn.lock b/yarn.lock index 6324e4a24c..2afa84ae57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7000,15 +7000,6 @@ axe-core@=4.7.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== -axios@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.1.tgz#76550d644bf0a2d469a01f9244db6753208397d7" - integrity sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - axobject-query@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" @@ -9674,7 +9665,7 @@ focus-trap@6.9.4, focus-trap@^6.9.4: dependencies: tabbable "^5.3.3" -follow-redirects@^1.0.0, follow-redirects@^1.15.0: +follow-redirects@^1.0.0: version "1.15.4" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== From 11d84a3c3fe3bad30861041c3f63ab2122997d30 Mon Sep 17 00:00:00 2001 From: minnakt <47064971+minnakt@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:31:38 -0500 Subject: [PATCH 2/4] DEVPROD-797: Update host events table (#2237) --- cypress/integration/host/host_events.ts | 8 +-- src/pages/host/HostTable.tsx | 83 ++++++++++++++----------- 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/cypress/integration/host/host_events.ts b/cypress/integration/host/host_events.ts index 8a851c7063..df5d40f853 100644 --- a/cypress/integration/host/host_events.ts +++ b/cypress/integration/host/host_events.ts @@ -2,7 +2,7 @@ import { clickOnPageSizeBtnAndAssertURLandTableSize } from "../../utils"; describe("Host events", () => { const pathWithEvents = "/host/i-0f81a2d39744003dd"; - const dataCyTableRows = "[data-cy=host-events-table] .ant-table-row"; + const dataCyTableRows = "[data-cy=host-events-table]"; beforeEach(() => { cy.window().then((win) => { @@ -217,9 +217,9 @@ describe("Host events", () => { cy.contains("Hawaii").click(); cy.contains("button", "Save Changes").click(); cy.visit(pathWithEvents); - cy.dataCy("HOST_JASPER_RESTARTING-time").contains( - "Sep 30, 2017, 9:11:16 AM", - ); + cy.dataCy("leafygreen-table-row") + .first() + .contains("Sep 30, 2017, 9:11:16 AM"); // Reset timezone so re-running this test works. cy.visit("/preferences"); cy.contains("Hawaii").click(); diff --git a/src/pages/host/HostTable.tsx b/src/pages/host/HostTable.tsx index 4beb3a4e89..8a6119321f 100644 --- a/src/pages/host/HostTable.tsx +++ b/src/pages/host/HostTable.tsx @@ -1,25 +1,22 @@ -import { useMemo } from "react"; +import { useMemo, useRef } from "react"; import { ApolloError } from "@apollo/client"; import styled from "@emotion/styled"; -import { - V10Table as Table, - V10TableHeader as TableHeader, - V10HeaderRow as HeaderRow, - V10Row as Row, - V10Cell as Cell, - V11Adapter, -} from "@leafygreen-ui/table"; +import { useLeafyGreenTable, LGColumnDef } from "@leafygreen-ui/table"; import { Subtitle, SubtitleProps } from "@leafygreen-ui/typography"; import { useHostsTableAnalytics } from "analytics"; import PageSizeSelector, { usePageSizeSelector, } from "components/PageSizeSelector"; import Pagination from "components/Pagination"; +import { BaseTable } from "components/Table/BaseTable"; import { size } from "constants/tokens"; import { HostEventsQuery } from "gql/generated/types"; import { useDateFormat } from "hooks"; import { HostCard } from "pages/host/HostCard"; import { HostEventString } from "pages/host/HostEventString"; +import { Unpacked } from "types/utils"; + +type HostEvent = Unpacked; export const HostTable: React.FC<{ loading: boolean; @@ -43,10 +40,42 @@ export const HostTable: React.FC<{ hostsTableAnalytics.sendEvent({ name: "Change Page Size" }); }; + const columns: LGColumnDef[] = useMemo( + () => [ + { + header: "Date", + accessorKey: "timestamp", + cell: ({ getValue }) => getDateCopy(getValue() as Date), + }, + { + header: "Event", + accessorKey: "eventType", + cell: ({ getValue, row }) => ( + + ), + }, + ], + [getDateCopy], + ); + + const tableContainerRef = useRef(null); + const table = useLeafyGreenTable({ + columns, + containerRef: tableContainerRef, + data: logEntries ?? [], + defaultColumn: { + enableColumnFilter: false, + }, + manualPagination: true, + }); + return ( - Recent Events + Recent Events - - - - - - } - > - {({ datum }) => ( - - - {getDateCopy(datum.timestamp)} - - - - - - )} -
-
+
); }; From 39459e027c7488e5f46b294b18739a294d2d5278 Mon Sep 17 00:00:00 2001 From: Mohamed Khelif Date: Thu, 25 Jan 2024 11:50:32 -0500 Subject: [PATCH 3/4] DEVPROD-3935 Use correct query for project health view setting (#2242) --- src/gql/generated/types.ts | 11 ++++------- src/gql/queries/project-health-view.graphql | 8 +++----- src/pages/commits/ViewToggle.tsx | 2 +- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/gql/generated/types.ts b/src/gql/generated/types.ts index 8cdae65f8e..1235243be3 100644 --- a/src/gql/generated/types.ts +++ b/src/gql/generated/types.ts @@ -7111,13 +7111,10 @@ export type ProjectHealthViewQueryVariables = Exact<{ export type ProjectHealthViewQuery = { __typename?: "Query"; - projectSettings: { - __typename?: "ProjectSettings"; - projectRef?: { - __typename?: "Project"; - id: string; - projectHealthView: ProjectHealthView; - } | null; + project: { + __typename?: "Project"; + id: string; + projectHealthView: ProjectHealthView; }; }; diff --git a/src/gql/queries/project-health-view.graphql b/src/gql/queries/project-health-view.graphql index 544a0dc1b0..0a83b77a4f 100644 --- a/src/gql/queries/project-health-view.graphql +++ b/src/gql/queries/project-health-view.graphql @@ -1,8 +1,6 @@ query ProjectHealthView($identifier: String!) { - projectSettings(identifier: $identifier) { - projectRef { - id - projectHealthView - } + project(projectIdentifier: $identifier) { + id + projectHealthView } } diff --git a/src/pages/commits/ViewToggle.tsx b/src/pages/commits/ViewToggle.tsx index 3d27af4b5d..9471ccb9f9 100644 --- a/src/pages/commits/ViewToggle.tsx +++ b/src/pages/commits/ViewToggle.tsx @@ -42,7 +42,7 @@ export const ViewToggle: React.FC = ({ identifier }) => { useEffect(() => { if (!view) { - setView(data?.projectSettings?.projectRef?.projectHealthView); + setView(data?.project?.projectHealthView); } }, [data, setView, view]); From 23b1ce0141fd7f1927292be5813fd079c91e0edd Mon Sep 17 00:00:00 2001 From: Mohamed Khelif Date: Thu, 25 Jan 2024 13:36:56 -0500 Subject: [PATCH 4/4] v3.0.195 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0ffde827dc..f9dcc6c611 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "spruce", - "version": "3.0.194", + "version": "3.0.195", "private": true, "scripts": { "bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh",