From 43bb8b67a078753eed9cabaca964d3761c1f7cb9 Mon Sep 17 00:00:00 2001 From: Arjun Patel Date: Tue, 12 Sep 2023 11:31:45 -0400 Subject: [PATCH] admin btn --- cypress/integration/nav_bar.ts | 55 +++++++++++++++---- cypress/integration/version/action_buttons.ts | 2 +- cypress/support/commands.ts | 12 ++++ cypress/support/e2e.ts | 6 ++ src/components/Header/Navbar.tsx | 9 ++- src/constants/externalResources.ts | 2 + src/gql/generated/types.ts | 5 ++ src/gql/mocks/getUser.ts | 3 + src/gql/queries/get-user.graphql | 3 + 9 files changed, 82 insertions(+), 15 deletions(-) diff --git a/cypress/integration/nav_bar.ts b/cypress/integration/nav_bar.ts index c5ebb3a876..b8c09a3956 100644 --- a/cypress/integration/nav_bar.ts +++ b/cypress/integration/nav_bar.ts @@ -5,10 +5,12 @@ const SPRUCE_URLS = { userPatches: `/user/${USER_ID}/patches`, cli: `/preferences/cli`, }; +const legacyBase = "http://localhost:9090"; const LEGACY_URLS = { - version: `/version/${PATCH_ID}`, - userPatches: `/patches/user/${USER_ID}`, - distros: `/distros`, + version: `${legacyBase}/version/${PATCH_ID}`, + userPatches: `${legacyBase}/patches/user/${USER_ID}`, + distros: `${legacyBase}/distros`, + admin: `${legacyBase}/admin`, }; describe("Nav Bar", () => { const projectCookie = "mci-project-cookie"; @@ -16,9 +18,11 @@ describe("Nav Bar", () => { it("Should have a nav bar linking to the proper page on the legacy UI", () => { cy.visit(SPRUCE_URLS.version); cy.dataCy("legacy-ui-link").should("exist"); - cy.dataCy("legacy-ui-link") - .should("have.attr", "href") - .and("include", LEGACY_URLS.version); + cy.dataCy("legacy-ui-link").should( + "have.attr", + "href", + LEGACY_URLS.version + ); }); it("Navigating to a different page should change the nav link to the legacy UI", () => { cy.visit(SPRUCE_URLS.version); @@ -28,9 +32,11 @@ describe("Nav Bar", () => { .and("include", LEGACY_URLS.version); cy.visit(SPRUCE_URLS.userPatches); cy.dataCy("legacy-ui-link").should("exist"); - cy.dataCy("legacy-ui-link") - .should("have.attr", "href") - .and("include", LEGACY_URLS.userPatches); + cy.dataCy("legacy-ui-link").should( + "have.attr", + "href", + LEGACY_URLS.userPatches + ); }); it("Visiting a page with no legacy equivalent should not display a nav link", () => { cy.visit(SPRUCE_URLS.cli); @@ -41,9 +47,7 @@ describe("Nav Bar", () => { cy.dataCy("legacy_route").should("not.exist"); cy.dataCy("auxiliary-dropdown-link").click(); cy.dataCy("legacy_route").should("exist"); - cy.dataCy("legacy_route") - .should("have.attr", "href") - .and("include", LEGACY_URLS.distros); + cy.dataCy("legacy_route").should("have.attr", "href", LEGACY_URLS.distros); }); it("Nav Dropdown should link to patches page of most recent project if cookie exists", () => { cy.setCookie(projectCookie, "spruce"); @@ -100,4 +104,31 @@ describe("Nav Bar", () => { ); cy.getCookie(projectCookie).should("have.property", "value", "spruce"); }); + + describe("Admin settings", () => { + it("Should not show Admin button to non-admins", () => { + const userData = { + data: { + user: { + userId: "admin", + displayName: "Evergreen Admin", + emailAddress: "admin@evergreen.com", + permissions: { + canUpdateAdminSettings: false, + }, + }, + }, + }; + cy.overwriteGQL("User", userData); + cy.visit(SPRUCE_URLS.version); + cy.dataCy("admin-link").should("not.exist"); + }); + + it("Should show Admin button to admins", () => { + cy.visit(SPRUCE_URLS.version); + cy.dataCy("admin-link") + .should("be.visible") + .should("have.attr", "href", LEGACY_URLS.admin); + }); + }); }); diff --git a/cypress/integration/version/action_buttons.ts b/cypress/integration/version/action_buttons.ts index 1750a88d40..2d3c19ed19 100644 --- a/cypress/integration/version/action_buttons.ts +++ b/cypress/integration/version/action_buttons.ts @@ -51,7 +51,7 @@ describe("Action Buttons", () => { it("Clicking 'Set Priority' button shows popconfirm with input and toast on success", () => { const priority = "99"; cy.dataCy("prioritize-patch").click(); - cy.dataCy("patch-priority-input").type(priority).type("{enter}"); + cy.dataCy("patch-priority-input").type(`${priority}{enter}`); cy.validateToast("success", priority); }); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 83fb2affbd..e1b60557dc 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -1,3 +1,5 @@ +import { GQL_URL, hasOperationName } from "../utils/graphql-test-utils"; + const user = { username: "admin", password: "password", @@ -113,3 +115,13 @@ Cypress.Commands.add( }); } ); + +Cypress.Commands.add("overwriteGQL", (operationName: string, body: any) => { + cy.intercept("POST", GQL_URL, (req) => { + if (hasOperationName(req, operationName)) { + req.reply((res) => { + res.body = body; + }); + } + }); +}); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index 7d3f6af7e6..7e4938f400 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -114,6 +114,12 @@ declare global { message?: string, shouldClose?: boolean ): void; + /** + * Custom command to overwrite a GQL response + * @param operationName - The operation name of the query + * @param body - The replacement response body + */ + overwriteGQL(operationName: string, body: any); } } } diff --git a/src/components/Header/Navbar.tsx b/src/components/Header/Navbar.tsx index 1ce994c084..a4fac747a6 100644 --- a/src/components/Header/Navbar.tsx +++ b/src/components/Header/Navbar.tsx @@ -8,7 +8,7 @@ import { Link, useParams } from "react-router-dom"; import { useNavbarAnalytics } from "analytics"; import Icon from "components/Icon"; import { CURRENT_PROJECT } from "constants/cookies"; -import { wikiUrl } from "constants/externalResources"; +import { adminSettingsURL, wikiUrl } from "constants/externalResources"; import { getCommitsRoute, getUserPatchesRoute, routes } from "constants/routes"; import { size } from "constants/tokens"; import { useAuthStateContext } from "context/auth"; @@ -27,7 +27,7 @@ export const Navbar: React.FC = () => { const { data: userData } = useQuery(GET_USER); const { user } = userData || {}; - const { userId } = user || {}; + const { permissions, userId } = user || {}; const { projectIdentifier: projectFromUrl } = useParams<{ projectIdentifier: string; @@ -82,6 +82,11 @@ export const Navbar: React.FC = () => { > My Hosts + {permissions?.canUpdateAdminSettings && ( + + Admin + + )} diff --git a/src/constants/externalResources.ts b/src/constants/externalResources.ts index 52fa94100f..9bf766f811 100644 --- a/src/constants/externalResources.ts +++ b/src/constants/externalResources.ts @@ -133,3 +133,5 @@ export const getHoneycombSystemMetricsUrl = ( query )}&omitMissingValues`; }; + +export const adminSettingsURL = `${getUiUrl()}/admin`; diff --git a/src/gql/generated/types.ts b/src/gql/generated/types.ts index 59f47f7dd8..64f0de0677 100644 --- a/src/gql/generated/types.ts +++ b/src/gql/generated/types.ts @@ -1518,6 +1518,7 @@ export type Permissions = { __typename?: "Permissions"; canCreateDistro: Scalars["Boolean"]["output"]; canCreateProject: Scalars["Boolean"]["output"]; + canUpdateAdminSettings: Scalars["Boolean"]["output"]; distroPermissions: DistroPermissions; userId: Scalars["String"]["output"]; }; @@ -8300,6 +8301,10 @@ export type UserQuery = { displayName: string; emailAddress: string; userId: string; + permissions: { + __typename?: "Permissions"; + canUpdateAdminSettings: boolean; + }; }; }; diff --git a/src/gql/mocks/getUser.ts b/src/gql/mocks/getUser.ts index bd20261709..2f130fb24b 100644 --- a/src/gql/mocks/getUser.ts +++ b/src/gql/mocks/getUser.ts @@ -14,6 +14,9 @@ export const getUserMock: ApolloMock = { userId: "admin", displayName: "Evergreen Admin", emailAddress: "admin@evergreen.com", + permissions: { + canUpdateAdminSettings: true, + }, }, }, }, diff --git a/src/gql/queries/get-user.graphql b/src/gql/queries/get-user.graphql index e0ee7e3034..106d7e0290 100644 --- a/src/gql/queries/get-user.graphql +++ b/src/gql/queries/get-user.graphql @@ -2,6 +2,9 @@ query User { user { displayName emailAddress + permissions { + canUpdateAdminSettings + } userId } }