Skip to content

Commit 17ad284

Browse files
authored
fix: fix deployment settings navigation issues (#16780)
1 parent 24f3445 commit 17ad284

18 files changed

+350
-221
lines changed

site/e2e/tests/roles.spec.ts

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import { type Page, expect, test } from "@playwright/test";
2+
import {
3+
createOrganization,
4+
createOrganizationMember,
5+
setupApiCalls,
6+
} from "../api";
7+
import { license, users } from "../constants";
8+
import { login, requiresLicense } from "../helpers";
9+
import { beforeCoderTest } from "../hooks";
10+
11+
test.beforeEach(async ({ page }) => {
12+
beforeCoderTest(page);
13+
});
14+
15+
type AdminSetting = (typeof adminSettings)[number];
16+
17+
const adminSettings = [
18+
"Deployment",
19+
"Organizations",
20+
"Healthcheck",
21+
"Audit Logs",
22+
] as const;
23+
24+
async function hasAccessToAdminSettings(page: Page, settings: AdminSetting[]) {
25+
// Organizations and Audit Logs both require a license to be visible
26+
const visibleSettings = license
27+
? settings
28+
: settings.filter((it) => it !== "Organizations" && it !== "Audit Logs");
29+
const adminSettingsButton = page.getByRole("button", {
30+
name: "Admin settings",
31+
});
32+
if (visibleSettings.length < 1) {
33+
await expect(adminSettingsButton).not.toBeVisible();
34+
return;
35+
}
36+
37+
await adminSettingsButton.click();
38+
39+
for (const name of visibleSettings) {
40+
await expect(page.getByText(name, { exact: true })).toBeVisible();
41+
}
42+
43+
const hiddenSettings = adminSettings.filter(
44+
(it) => !visibleSettings.includes(it),
45+
);
46+
for (const name of hiddenSettings) {
47+
await expect(page.getByText(name, { exact: true })).not.toBeVisible();
48+
}
49+
}
50+
51+
test.describe("roles admin settings access", () => {
52+
test("member cannot see admin settings", async ({ page }) => {
53+
await login(page, users.member);
54+
await page.goto("/", { waitUntil: "domcontentloaded" });
55+
56+
// None, "Admin settings" button should not be visible
57+
await hasAccessToAdminSettings(page, []);
58+
});
59+
60+
test("template admin can see admin settings", async ({ page }) => {
61+
await login(page, users.templateAdmin);
62+
await page.goto("/", { waitUntil: "domcontentloaded" });
63+
64+
await hasAccessToAdminSettings(page, ["Deployment", "Organizations"]);
65+
});
66+
67+
test("user admin can see admin settings", async ({ page }) => {
68+
await login(page, users.userAdmin);
69+
await page.goto("/", { waitUntil: "domcontentloaded" });
70+
71+
await hasAccessToAdminSettings(page, ["Deployment", "Organizations"]);
72+
});
73+
74+
test("auditor can see admin settings", async ({ page }) => {
75+
await login(page, users.auditor);
76+
await page.goto("/", { waitUntil: "domcontentloaded" });
77+
78+
await hasAccessToAdminSettings(page, [
79+
"Deployment",
80+
"Organizations",
81+
"Audit Logs",
82+
]);
83+
});
84+
85+
test("admin can see admin settings", async ({ page }) => {
86+
await login(page, users.admin);
87+
await page.goto("/", { waitUntil: "domcontentloaded" });
88+
89+
await hasAccessToAdminSettings(page, [
90+
"Deployment",
91+
"Organizations",
92+
"Healthcheck",
93+
"Audit Logs",
94+
]);
95+
});
96+
});
97+
98+
test.describe("org-scoped roles admin settings access", () => {
99+
requiresLicense();
100+
101+
test.beforeEach(async ({ page }) => {
102+
await login(page);
103+
await setupApiCalls(page);
104+
});
105+
106+
test("org template admin can see admin settings", async ({ page }) => {
107+
const org = await createOrganization();
108+
const orgTemplateAdmin = await createOrganizationMember({
109+
[org.id]: ["organization-template-admin"],
110+
});
111+
112+
await login(page, orgTemplateAdmin);
113+
await page.goto("/", { waitUntil: "domcontentloaded" });
114+
115+
await hasAccessToAdminSettings(page, ["Organizations"]);
116+
});
117+
118+
test("org user admin can see admin settings", async ({ page }) => {
119+
const org = await createOrganization();
120+
const orgUserAdmin = await createOrganizationMember({
121+
[org.id]: ["organization-user-admin"],
122+
});
123+
124+
await login(page, orgUserAdmin);
125+
await page.goto("/", { waitUntil: "domcontentloaded" });
126+
127+
await hasAccessToAdminSettings(page, ["Deployment", "Organizations"]);
128+
});
129+
130+
test("org auditor can see admin settings", async ({ page }) => {
131+
const org = await createOrganization();
132+
const orgAuditor = await createOrganizationMember({
133+
[org.id]: ["organization-auditor"],
134+
});
135+
136+
await login(page, orgAuditor);
137+
await page.goto("/", { waitUntil: "domcontentloaded" });
138+
139+
await hasAccessToAdminSettings(page, ["Organizations", "Audit Logs"]);
140+
});
141+
142+
test("org admin can see admin settings", async ({ page }) => {
143+
const org = await createOrganization();
144+
const orgAdmin = await createOrganizationMember({
145+
[org.id]: ["organization-admin"],
146+
});
147+
148+
await login(page, orgAdmin);
149+
await page.goto("/", { waitUntil: "domcontentloaded" });
150+
151+
await hasAccessToAdminSettings(page, [
152+
"Deployment",
153+
"Organizations",
154+
"Audit Logs",
155+
]);
156+
});
157+
});

site/src/api/queries/organizations.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ import type {
66
UpdateOrganizationRequest,
77
} from "api/typesGenerated";
88
import {
9-
type AnyOrganizationPermissions,
109
type OrganizationPermissionName,
1110
type OrganizationPermissions,
12-
anyOrganizationPermissionChecks,
1311
organizationPermissionChecks,
1412
} from "modules/management/organizationPermissions";
1513
import type { QueryClient } from "react-query";
@@ -266,21 +264,6 @@ export const organizationsPermissions = (
266264
};
267265
};
268266

269-
export const anyOrganizationPermissionsKey = [
270-
"authorization",
271-
"anyOrganization",
272-
];
273-
274-
export const anyOrganizationPermissions = () => {
275-
return {
276-
queryKey: anyOrganizationPermissionsKey,
277-
queryFn: () =>
278-
API.checkAuthorization({
279-
checks: anyOrganizationPermissionChecks,
280-
}) as Promise<AnyOrganizationPermissions>,
281-
};
282-
};
283-
284267
export const getOrganizationIdpSyncClaimFieldValuesKey = (
285268
organization: string,
286269
field: string,

site/src/contexts/auth/AuthProvider.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
useContext,
1919
} from "react";
2020
import { useMutation, useQuery, useQueryClient } from "react-query";
21-
import { type Permissions, permissionsToCheck } from "./permissions";
21+
import { type Permissions, permissionChecks } from "./permissions";
2222

2323
export type AuthContextValue = {
2424
isLoading: boolean;
@@ -50,13 +50,13 @@ export const AuthProvider: FC<PropsWithChildren> = ({ children }) => {
5050
const hasFirstUserQuery = useQuery(hasFirstUser(userMetadataState));
5151

5252
const permissionsQuery = useQuery({
53-
...checkAuthorization({ checks: permissionsToCheck }),
53+
...checkAuthorization({ checks: permissionChecks }),
5454
enabled: userQuery.data !== undefined,
5555
});
5656

5757
const queryClient = useQueryClient();
5858
const loginMutation = useMutation(
59-
login({ checks: permissionsToCheck }, queryClient),
59+
login({ checks: permissionChecks }, queryClient),
6060
);
6161

6262
const logoutMutation = useMutation(logout(queryClient));

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy