Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into EVG-19973
Browse files Browse the repository at this point in the history
  • Loading branch information
minnakt committed Oct 9, 2023
2 parents 37e5b60 + f4e27db commit 1f6ea78
Show file tree
Hide file tree
Showing 24 changed files with 254 additions and 115 deletions.
83 changes: 83 additions & 0 deletions cypress/integration/distroSettings/permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
describe("with various permission levels", () => {
it("hides the new distro button when a user cannot create distros", () => {
const userData = {
data: {
user: {
userId: "admin",
permissions: {
canCreateDistro: false,
distroPermissions: {
admin: true,
edit: true,
},
},
},
},
};
cy.overwriteGQL("UserDistroSettingsPermissions", userData);
cy.visit("/distro/rhel71-power8-large/settings/general");
cy.dataCy("new-distro-button").should("not.exist");
cy.dataCy("delete-distro-button").should(
"not.have.attr",
"aria-disabled",
"true"
);
cy.get("textarea").should("not.be.disabled");
});

it("disables the delete button when user lacks admin permissions", () => {
const userData = {
data: {
user: {
userId: "admin",
permissions: {
canCreateDistro: false,
distroPermissions: {
admin: false,
edit: true,
},
},
},
},
};
cy.overwriteGQL("UserDistroSettingsPermissions", userData);
cy.visit("/distro/rhel71-power8-large/settings/general");
cy.dataCy("new-distro-button").should("not.exist");
cy.dataCy("delete-distro-button").should(
"have.attr",
"aria-disabled",
"true"
);
cy.get("textarea").should("not.be.disabled");
});

it("disables fields when user lacks edit permissions", () => {
const userData = {
data: {
user: {
userId: "admin",
permissions: {
canCreateDistro: false,
distroPermissions: {
admin: false,
edit: false,
},
},
},
},
};
cy.overwriteGQL("UserDistroSettingsPermissions", userData);
cy.visit("/distro/rhel71-power8-large/settings/general");
cy.dataCy("new-distro-button").should("not.exist");
cy.dataCy("delete-distro-button").should(
"have.attr",
"aria-disabled",
"true"
);
cy.dataCy("distro-settings-page").within(() => {
cy.get("input").should("be.disabled");
cy.get("textarea").should("be.disabled");
cy.get("button").should("have.attr", "aria-disabled", "true");
});
});
});
16 changes: 9 additions & 7 deletions cypress/integration/nav_bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,22 @@ describe("Nav Bar", () => {
cy.visit(SPRUCE_URLS.cli);
cy.dataCy("legacy-ui-link").should("not.exist");
});
it("Nav Dropdown should provide links to legacy pages", () => {
cy.visit(SPRUCE_URLS.version);
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", LEGACY_URLS.distros);
});
it("Nav Dropdown should link to patches page of most recent project if cookie exists", () => {
cy.setCookie(projectCookie, "spruce");
cy.visit(SPRUCE_URLS.userPatches);
cy.dataCy("auxiliary-dropdown-link").click();
cy.dataCy("auxiliary-dropdown-project-patches").click();
cy.location("pathname").should("eq", "/project/spruce/patches");
});
it("Nav Dropdown should link to the first distro returned by the distros resolver", () => {
cy.visit(SPRUCE_URLS.version);
cy.dataCy("auxiliary-dropdown-link").click();
cy.dataCy("auxiliary-dropdown-distro-settings").should(
"have.attr",
"href",
"/distro/localhost/settings/general"
);
});
it("Nav Dropdown should link to patches page of default project in SpruceConfig if cookie does not exist", () => {
cy.clearCookie(projectCookie);
cy.visit(SPRUCE_URLS.userPatches);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "spruce",
"version": "3.0.151",
"version": "3.0.153",
"private": true,
"scripts": {
"bootstrap-logkeeper": "./scripts/bootstrap-logkeeper.sh",
Expand Down
2 changes: 1 addition & 1 deletion src/components/Content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const Content: React.FC = () => (
<Route path={routes.configurePatch} element={<ConfigurePatch />}>
<Route path={tab} element={null} />
</Route>
<Route path={`${routes.distro}/*`} element={<Distro />}>
<Route path={`${routes.distroSettings}/*`} element={<Distro />}>
<Route path={tab} element={null} />
</Route>
<Route path={routes.host} element={<Host />} />
Expand Down
14 changes: 6 additions & 8 deletions src/components/Header/AuxiliaryDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
import { useNavbarAnalytics } from "analytics";
import { legacyRoutes } from "constants/externalResources";
import {
routes,
getDistroSettingsRoute,
getProjectPatchesRoute,
getProjectSettingsRoute,
getTaskQueueRoute,
getCommitQueueRoute,
} from "constants/routes";
import { environmentVariables } from "utils";
import { useFirstDistro } from "hooks";
import { NavDropdown } from "./NavDropdown";

const { getUiUrl } = environmentVariables;

interface AuxiliaryDropdownProps {
projectIdentifier: string;
}

export const AuxiliaryDropdown: React.FC<AuxiliaryDropdownProps> = ({
projectIdentifier,
}) => {
const uiURL = getUiUrl();
const { sendEvent } = useNavbarAnalytics();
const distro = useFirstDistro();

const menuItems = [
{
Expand All @@ -39,9 +37,9 @@ export const AuxiliaryDropdown: React.FC<AuxiliaryDropdownProps> = ({
onClick: () => sendEvent({ name: "Click Task Queue Link" }),
},
{
"data-cy": "legacy_route",
href: `${uiURL}${legacyRoutes.distros}`,
text: "Distros",
"data-cy": "auxiliary-dropdown-distro-settings",
to: getDistroSettingsRoute(distro),
text: "Distro Settings",
onClick: () => sendEvent({ name: "Click Distros Link" }),
},

Expand Down
3 changes: 0 additions & 3 deletions src/constants/externalResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,6 @@ export const getParsleyTestLogURL = (buildId: string, testId: string) =>
export const getParsleyBuildLogURL = (buildId: string) =>
`${getParsleyUrl()}/resmoke/${buildId}/all`;

export const getDistroPageUrl = (distroId: string) =>
`${getUiUrl()}/distros##${distroId}`;

export const getHoneycombTraceUrl = (traceId: string, startTs: Date) =>
`${getHoneycombBaseURL()}/datasets/evergreen-agent/trace?trace_id=${traceId}&trace_start_ts=${getUnixTime(
new Date(startTs)
Expand Down
4 changes: 2 additions & 2 deletions src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const routes = {
commits: paths.commits,
configurePatch: `${paths.patch}/:id/configure`,
container: `${paths.container}/:id`,
distro: `${paths.distro}/:distroId/${PageNames.Settings}`,
distroSettings: `${paths.distro}/:distroId/${PageNames.Settings}`,
host: `${paths.host}/:id`,
hosts: paths.hosts,
jobLogs: `${paths.jobLogs}/:buildId`,
Expand Down Expand Up @@ -240,7 +240,7 @@ export const getDistroSettingsRoute = (
) =>
tab
? `${paths.distro}/${distroId}/${PageNames.Settings}/${tab}`
: `${paths.distro}/${distroId}/${PageNames.Settings}`;
: `${paths.distro}/${distroId}/${PageNames.Settings}/${DistroSettingsTabRoutes.General}`;

export const getCommitQueueRoute = (projectIdentifier: string) =>
`${paths.commitQueue}/${encodeURIComponent(projectIdentifier)}`;
Expand Down
12 changes: 8 additions & 4 deletions src/context/auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,14 @@ const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
credentials: "include",
method: "GET",
redirect: "manual",
}).then(() => {
dispatch({ type: "deauthenticated" });
window.location.href = `${getLoginDomain()}/login`;
});
})
.then(() => {
dispatch({ type: "deauthenticated" });
window.location.href = `${getLoginDomain()}/login`;
})
.catch((error) => {
leaveBreadcrumb("Logout failed", { error }, "user");
});
},
dispatchAuthenticated: () => {
if (!state.isAuthenticated) {
Expand Down
8 changes: 7 additions & 1 deletion src/gql/generated/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ export type File = {
__typename?: "File";
link: Scalars["String"]["output"];
name: Scalars["String"]["output"];
urlParsley?: Maybe<Scalars["String"]["output"]>;
visibility: Scalars["String"]["output"];
};

Expand Down Expand Up @@ -2935,6 +2936,7 @@ export type Version = {
finishTime?: Maybe<Scalars["Time"]["output"]>;
gitTags?: Maybe<Array<GitTag>>;
id: Scalars["String"]["output"];
ignored: Scalars["Boolean"]["output"];
isPatch: Scalars["Boolean"]["output"];
manifest?: Maybe<Manifest>;
message: Scalars["String"]["output"];
Expand Down Expand Up @@ -8471,7 +8473,11 @@ export type UserDistroSettingsPermissionsQuery = {
permissions: {
__typename?: "Permissions";
canCreateDistro: boolean;
distroPermissions: { __typename?: "DistroPermissions"; admin: boolean };
distroPermissions: {
__typename?: "DistroPermissions";
admin: boolean;
edit: boolean;
};
};
};
};
Expand Down
1 change: 1 addition & 0 deletions src/gql/queries/user-distro-settings-permissions.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ query UserDistroSettingsPermissions($distroId: String!) {
canCreateDistro
distroPermissions(options: { distroId: $distroId }) {
admin
edit
}
}
userId
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ export { useSpruceConfig } from "./useSpruceConfig";
export { useUserSettings } from "./useUserSettings";
export { useUserTimeZone } from "./useUserTimeZone";
export { useDateFormat } from "./useDateFormat";
export { useFirstDistro } from "./useFirstDistro";
export { useBreadcrumbRoot } from "./useBreadcrumbRoot";
export { useResize } from "./useResize";
18 changes: 18 additions & 0 deletions src/hooks/useFirstDistro.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useQuery } from "@apollo/client";
import { DistrosQuery, DistrosQueryVariables } from "gql/generated/types";
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
*/
export const useFirstDistro = () => {
const { data } = useQuery<DistrosQuery, DistrosQueryVariables>(DISTROS, {
variables: {
onlySpawnable: false,
},
});

return data?.distros?.[0]?.name ?? "ubuntu2204-large";
};
4 changes: 3 additions & 1 deletion src/hooks/useLegacyUIURL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const useLegacyUIURL = (): string | null => {
[routes.spawnHost]: `${uiURL}/spawn#?resourcetype=hosts`,
[routes.spawnVolume]: `${uiURL}/spawn#?resourcetype=volumes`,
[`${routes.commits}/:id`]: `${uiURL}/waterfall/${id}`,
[`${routes.distroSettings}/*`]: `${uiURL}/distros##${id}`,
[routes.hosts]: `${uiURL}/hosts`,
[routes.host]: `${uiURL}/host/${id}`,
};
Expand All @@ -34,7 +35,8 @@ export const useLegacyUIURL = (): string | null => {
if (matchedPath !== null) {
setId(
get(matchedPath, "params.id", "") ||
get(matchedPath, "params.identifier", "")
get(matchedPath, "params.identifier", "") ||
get(matchedPath, "params.distroId", "")
);
setLegacyUIUrl(legacyUIMap[legacyUIKeys[i]]);
break;
Expand Down
2 changes: 2 additions & 0 deletions src/pages/distroSettings/DeleteDistro/DeleteDistro.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ const isAdminMock: ApolloMock<
distroPermissions: {
__typename: "DistroPermissions",
admin: true,
edit: true,
},
},
},
Expand Down Expand Up @@ -159,6 +160,7 @@ const notAdminMock: ApolloMock<
distroPermissions: {
__typename: "DistroPermissions",
admin: false,
edit: false,
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe("distro select", () => {
expect(screen.getByDataCy("distro-select-options")).toBeInTheDocument();
await user.click(screen.getByText("abc"));
expect(screen.queryByDataCy("distro-select-options")).toBeNull();
expect(router.state.location.pathname).toBe("/distro/abc/settings");
expect(router.state.location.pathname).toBe("/distro/abc/settings/general");
});

it("typing in the text input will narrow down search results", async () => {
Expand Down
3 changes: 2 additions & 1 deletion src/pages/distroSettings/NavigationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export const NavigationModal: React.FC = () => {

const shouldConfirmNavigation = ({ nextLocation }): boolean => {
const isDistroSettingsRoute =
nextLocation && !!matchPath(`${routes.distro}/*`, nextLocation.pathname);
nextLocation &&
!!matchPath(`${routes.distroSettings}/*`, nextLocation.pathname);
if (!isDistroSettingsRoute) {
return hasUnsaved;
}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/distroSettings/NewDistro/CopyModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe("copy distro modal", () => {
await waitFor(() => expect(dispatchToast.warning).toHaveBeenCalledTimes(0));
await waitFor(() => expect(dispatchToast.error).toHaveBeenCalledTimes(0));
expect(router.state.location.pathname).toBe(
`/distro/${newDistroId}/settings`
`/distro/${newDistroId}/settings/general`
);
});

Expand Down
2 changes: 1 addition & 1 deletion src/pages/distroSettings/NewDistro/CreateModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe("create distro modal", () => {
await waitFor(() => expect(dispatchToast.warning).toHaveBeenCalledTimes(0));
await waitFor(() => expect(dispatchToast.error).toHaveBeenCalledTimes(0));
expect(router.state.location.pathname).toBe(
`/distro/${newDistroId}/settings`
`/distro/${newDistroId}/settings/general`
);
});

Expand Down
2 changes: 2 additions & 0 deletions src/pages/distroSettings/NewDistro/NewDistroButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ describe("new distro button", () => {
distroPermissions: {
__typename: "DistroPermissions",
admin: false,
edit: false,
},
},
},
Expand Down Expand Up @@ -131,6 +132,7 @@ const hasPermissionsMock: ApolloMock<
distroPermissions: {
__typename: "DistroPermissions",
admin: true,
edit: true,
},
},
},
Expand Down
9 changes: 0 additions & 9 deletions src/pages/distroSettings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { useToastContext } from "context/toast";
import { DistroQuery, DistroQueryVariables } from "gql/generated/types";
import { DISTRO } from "gql/queries";
import { usePageTitle } from "hooks";
import { isProduction } from "utils/environmentVariables";
import { DistroSettingsProvider } from "./Context";
import { DistroSelect } from "./DistroSelect";
import { getTabTitle } from "./getTabTitle";
Expand All @@ -44,14 +43,6 @@ const DistroSettings: React.FC = () => {
}
);

if (isProduction()) {
return (
<PageWrapper>
<h1>Coming Soon 🌱⚙️</h1>
</PageWrapper>
);
}

if (!Object.values(DistroSettingsTabRoutes).includes(currentTab)) {
return (
<Navigate
Expand Down
Loading

0 comments on commit 1f6ea78

Please sign in to comment.