Skip to content

Commit 092c129

Browse files
authored
chore: perform several small frontend permissions refactors (coder#16735)
1 parent 54745b1 commit 092c129

File tree

57 files changed

+158
-174
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+158
-174
lines changed

enterprise/coderd/groups.go

-2
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,6 @@ func (api *API) patchGroup(rw http.ResponseWriter, r *http.Request) {
167167
})
168168
return
169169
}
170-
// TODO: It would be nice to enforce this at the schema level
171-
// but unfortunately our org_members table does not have an ID.
172170
_, err := database.ExpectOne(api.Database.OrganizationMembers(ctx, database.OrganizationMembersParams{
173171
OrganizationID: group.OrganizationID,
174172
UserID: uuid.MustParse(id),

site/e2e/constants.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ export const defaultPassword = "SomeSecurePassword!";
2020

2121
// Credentials for users
2222
export const users = {
23-
admin: {
24-
username: "admin",
23+
owner: {
24+
username: "owner",
2525
password: defaultPassword,
26-
email: "admin@coder.com",
26+
email: "owner@coder.com",
2727
},
2828
templateAdmin: {
2929
username: "template-admin",
@@ -41,7 +41,7 @@ export const users = {
4141
username: "auditor",
4242
password: defaultPassword,
4343
email: "auditor@coder.com",
44-
roles: ["Template Admin", "Auditor"],
44+
roles: ["Auditor"],
4545
},
4646
member: {
4747
username: "member",

site/e2e/helpers.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export type LoginOptions = {
6767
password: string;
6868
};
6969

70-
export async function login(page: Page, options: LoginOptions = users.admin) {
70+
export async function login(page: Page, options: LoginOptions = users.owner) {
7171
const ctx = page.context();
7272
// biome-ignore lint/suspicious/noExplicitAny: reset the current user
7373
(ctx as any)[Symbol.for("currentUser")] = undefined;

site/e2e/setup/addUsersAndLicense.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,16 @@ test("setup deployment", async ({ page }) => {
1616
}
1717

1818
// Setup first user
19-
await page.getByLabel(Language.emailLabel).fill(users.admin.email);
20-
await page.getByLabel(Language.passwordLabel).fill(users.admin.password);
19+
await page.getByLabel(Language.emailLabel).fill(users.owner.email);
20+
await page.getByLabel(Language.passwordLabel).fill(users.owner.password);
2121
await page.getByTestId("create").click();
2222

2323
await expectUrl(page).toHavePathName("/workspaces");
2424
await page.getByTestId("button-select-template").isVisible();
2525

2626
for (const user of Object.values(users)) {
2727
// Already created as first user
28-
if (user.username === "admin") {
28+
if (user.username === "owner") {
2929
continue;
3030
}
3131

site/e2e/tests/auditLogs.spec.ts

+21-19
Original file line numberDiff line numberDiff line change
@@ -13,62 +13,63 @@ test.describe.configure({ mode: "parallel" });
1313

1414
test.beforeEach(async ({ page }) => {
1515
beforeCoderTest(page);
16-
await login(page, users.auditor);
1716
});
1817

19-
async function resetSearch(page: Page) {
18+
async function resetSearch(page: Page, username: string) {
2019
const clearButton = page.getByLabel("Clear search");
2120
if (await clearButton.isVisible()) {
2221
await clearButton.click();
2322
}
2423

2524
// Filter by the auditor test user to prevent race conditions
26-
const user = currentUser(page);
2725
await expect(page.getByText("All users")).toBeVisible();
28-
await page.getByPlaceholder("Search...").fill(`username:${user.username}`);
26+
await page.getByPlaceholder("Search...").fill(`username:${username}`);
2927
await expect(page.getByText("All users")).not.toBeVisible();
3028
}
3129

3230
test("logins are logged", async ({ page }) => {
3331
requiresLicense();
3432

3533
// Go to the audit history
34+
await login(page, users.auditor);
3635
await page.goto("/audit");
36+
const username = users.auditor.username;
3737

3838
const user = currentUser(page);
39-
const loginMessage = `${user.username} logged in`;
39+
const loginMessage = `${username} logged in`;
4040
// Make sure those things we did all actually show up
41-
await resetSearch(page);
41+
await resetSearch(page, username);
4242
await expect(page.getByText(loginMessage).first()).toBeVisible();
4343
});
4444

4545
test("creating templates and workspaces is logged", async ({ page }) => {
4646
requiresLicense();
4747

4848
// Do some stuff that should show up in the audit logs
49+
await login(page, users.templateAdmin);
50+
const username = users.templateAdmin.username;
4951
const templateName = await createTemplate(page);
5052
const workspaceName = await createWorkspace(page, templateName);
5153

5254
// Go to the audit history
55+
await login(page, users.auditor);
5356
await page.goto("/audit");
5457

55-
const user = currentUser(page);
56-
5758
// Make sure those things we did all actually show up
58-
await resetSearch(page);
59+
await resetSearch(page, username);
5960
await expect(
60-
page.getByText(`${user.username} created template ${templateName}`),
61+
page.getByText(`${username} created template ${templateName}`),
6162
).toBeVisible();
6263
await expect(
63-
page.getByText(`${user.username} created workspace ${workspaceName}`),
64+
page.getByText(`${username} created workspace ${workspaceName}`),
6465
).toBeVisible();
6566
await expect(
66-
page.getByText(`${user.username} started workspace ${workspaceName}`),
67+
page.getByText(`${username} started workspace ${workspaceName}`),
6768
).toBeVisible();
6869

6970
// Make sure we can inspect the details of the log item
7071
const createdWorkspace = page.locator(".MuiTableRow-root", {
71-
hasText: `${user.username} created workspace ${workspaceName}`,
72+
hasText: `${username} created workspace ${workspaceName}`,
7273
});
7374
await createdWorkspace.getByLabel("open-dropdown").click();
7475
await expect(
@@ -83,18 +84,19 @@ test("inspecting and filtering audit logs", async ({ page }) => {
8384
requiresLicense();
8485

8586
// Do some stuff that should show up in the audit logs
87+
await login(page, users.templateAdmin);
88+
const username = users.templateAdmin.username;
8689
const templateName = await createTemplate(page);
8790
const workspaceName = await createWorkspace(page, templateName);
8891

8992
// Go to the audit history
93+
await login(page, users.auditor);
9094
await page.goto("/audit");
91-
92-
const user = currentUser(page);
93-
const loginMessage = `${user.username} logged in`;
94-
const startedWorkspaceMessage = `${user.username} started workspace ${workspaceName}`;
95+
const loginMessage = `${username} logged in`;
96+
const startedWorkspaceMessage = `${username} started workspace ${workspaceName}`;
9597

9698
// Filter by resource type
97-
await resetSearch(page);
99+
await resetSearch(page, username);
98100
await page.getByText("All resource types").click();
99101
const workspaceBuildsOption = page.getByText("Workspace Build");
100102
await workspaceBuildsOption.scrollIntoViewIfNeeded({ timeout: 5000 });
@@ -107,7 +109,7 @@ test("inspecting and filtering audit logs", async ({ page }) => {
107109
await expect(page.getByText("All resource types")).toBeVisible();
108110

109111
// Filter by action type
110-
await resetSearch(page);
112+
await resetSearch(page, username);
111113
await page.getByText("All actions").click();
112114
await page.getByText("Login", { exact: true }).click();
113115
// Logins should be visible

site/e2e/tests/deployment/general.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ test("experiments", async ({ page }) => {
1616
const availableExperiments = await API.getAvailableExperiments();
1717

1818
// Verify if the site lists the same experiments
19-
await page.goto("/deployment/general", { waitUntil: "networkidle" });
19+
await page.goto("/deployment/overview", { waitUntil: "domcontentloaded" });
2020

2121
const experimentsLocator = page.locator(
2222
"div.options-table tr.option-experiments ul.option-array",

site/e2e/tests/roles.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ test.describe("roles admin settings access", () => {
8282
]);
8383
});
8484

85-
test("admin can see admin settings", async ({ page }) => {
86-
await login(page, users.admin);
85+
test("owner can see admin settings", async ({ page }) => {
86+
await login(page, users.owner);
8787
await page.goto("/", { waitUntil: "domcontentloaded" });
8888

8989
await hasAccessToAdminSettings(page, [

site/src/@types/storybook.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
SerpentOption,
77
User,
88
} from "api/typesGenerated";
9-
import type { Permissions } from "contexts/auth/permissions";
9+
import type { Permissions } from "modules/permissions";
1010
import type { QueryKey } from "react-query";
1111

1212
declare module "@storybook/react" {

site/src/api/queries/organizations.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
type OrganizationPermissionName,
1010
type OrganizationPermissions,
1111
organizationPermissionChecks,
12-
} from "modules/management/organizationPermissions";
12+
} from "modules/permissions/organizations";
1313
import type { QueryClient } from "react-query";
1414
import { meKey } from "./users";
1515

site/src/contexts/auth/AuthProvider.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import type { UpdateUserProfileRequest, User } from "api/typesGenerated";
1111
import { displaySuccess } from "components/GlobalSnackbar/utils";
1212
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
13+
import { type Permissions, permissionChecks } from "modules/permissions";
1314
import {
1415
type FC,
1516
type PropsWithChildren,
@@ -18,7 +19,6 @@ import {
1819
useContext,
1920
} from "react";
2021
import { useMutation, useQuery, useQueryClient } from "react-query";
21-
import { type Permissions, permissionChecks } from "./permissions";
2222

2323
export type AuthContextValue = {
2424
isLoading: boolean;

site/src/modules/dashboard/DashboardLayout.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import { useUpdateCheck } from "./useUpdateCheck";
1616

1717
export const DashboardLayout: FC = () => {
1818
const { permissions } = useAuthenticated();
19-
const updateCheck = useUpdateCheck(permissions.viewUpdateCheck);
20-
const canViewDeployment = Boolean(permissions.viewDeploymentValues);
19+
const updateCheck = useUpdateCheck(permissions.viewDeploymentConfig);
20+
const canViewDeployment = Boolean(permissions.viewDeploymentConfig);
2121

2222
return (
2323
<>

site/src/modules/dashboard/DashboardProvider.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import type {
1111
import { ErrorAlert } from "components/Alert/ErrorAlert";
1212
import { Loader } from "components/Loader/Loader";
1313
import { useAuthenticated } from "contexts/auth/RequireAuth";
14-
import { canViewAnyOrganization } from "contexts/auth/permissions";
1514
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
15+
import { canViewAnyOrganization } from "modules/permissions";
1616
import { type FC, type PropsWithChildren, createContext } from "react";
1717
import { useQuery } from "react-query";
1818
import { selectFeatureVisibility } from "./entitlements";

site/src/modules/dashboard/DeploymentBanner/DeploymentBanner.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ export const DeploymentBanner: FC = () => {
1010
const deploymentStatsQuery = useQuery(deploymentStats());
1111
const healthQuery = useQuery({
1212
...health(),
13-
enabled: permissions.viewDeploymentValues,
13+
enabled: permissions.viewDeploymentConfig,
1414
});
1515

16-
if (!permissions.viewDeploymentValues || !deploymentStatsQuery.data) {
16+
if (!permissions.viewDeploymentConfig || !deploymentStatsQuery.data) {
1717
return null;
1818
}
1919

site/src/modules/dashboard/Navbar/Navbar.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { buildInfo } from "api/queries/buildInfo";
22
import { useProxy } from "contexts/ProxyContext";
33
import { useAuthenticated } from "contexts/auth/RequireAuth";
4-
import { canViewDeploymentSettings } from "contexts/auth/permissions";
54
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
65
import { useDashboard } from "modules/dashboard/useDashboard";
6+
import { canViewDeploymentSettings } from "modules/permissions";
77
import type { FC } from "react";
88
import { useQuery } from "react-query";
99
import { useFeatureVisibility } from "../useFeatureVisibility";

site/src/modules/dashboard/Navbar/ProxyMenu.stories.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { fn, userEvent, within } from "@storybook/test";
33
import { getAuthorizationKey } from "api/queries/authCheck";
44
import { getPreferredProxy } from "contexts/ProxyContext";
55
import { AuthProvider } from "contexts/auth/AuthProvider";
6-
import { permissionChecks } from "contexts/auth/permissions";
6+
import { permissionChecks } from "modules/permissions";
77
import {
88
MockAuthMethodsAll,
99
MockPermissions,

site/src/modules/management/DeploymentSettingsProvider.tsx renamed to site/src/modules/management/DeploymentConfigProvider.tsx

+10-10
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,26 @@ import { type FC, createContext, useContext } from "react";
66
import { useQuery } from "react-query";
77
import { Outlet } from "react-router-dom";
88

9-
export const DeploymentSettingsContext = createContext<
10-
DeploymentSettingsValue | undefined
9+
export const DeploymentConfigContext = createContext<
10+
DeploymentConfigValue | undefined
1111
>(undefined);
1212

13-
type DeploymentSettingsValue = Readonly<{
13+
type DeploymentConfigValue = Readonly<{
1414
deploymentConfig: DeploymentConfig;
1515
}>;
1616

17-
export const useDeploymentSettings = (): DeploymentSettingsValue => {
18-
const context = useContext(DeploymentSettingsContext);
17+
export const useDeploymentConfig = (): DeploymentConfigValue => {
18+
const context = useContext(DeploymentConfigContext);
1919
if (!context) {
2020
throw new Error(
21-
`${useDeploymentSettings.name} should be used inside of ${DeploymentSettingsProvider.name}`,
21+
`${useDeploymentConfig.name} should be used inside of ${DeploymentConfigProvider.name}`,
2222
);
2323
}
2424

2525
return context;
2626
};
2727

28-
const DeploymentSettingsProvider: FC = () => {
28+
const DeploymentConfigProvider: FC = () => {
2929
const deploymentConfigQuery = useQuery(deploymentConfig());
3030

3131
if (deploymentConfigQuery.error) {
@@ -37,12 +37,12 @@ const DeploymentSettingsProvider: FC = () => {
3737
}
3838

3939
return (
40-
<DeploymentSettingsContext.Provider
40+
<DeploymentConfigContext.Provider
4141
value={{ deploymentConfig: deploymentConfigQuery.data }}
4242
>
4343
<Outlet />
44-
</DeploymentSettingsContext.Provider>
44+
</DeploymentConfigContext.Provider>
4545
);
4646
};
4747

48-
export default DeploymentSettingsProvider;
48+
export default DeploymentConfigProvider;

site/src/modules/management/DeploymentSettingsLayout.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import {
77
} from "components/Breadcrumb/Breadcrumb";
88
import { Loader } from "components/Loader/Loader";
99
import { useAuthenticated } from "contexts/auth/RequireAuth";
10-
import { RequirePermission } from "contexts/auth/RequirePermission";
11-
import { canViewDeploymentSettings } from "contexts/auth/permissions";
10+
import { canViewDeploymentSettings } from "modules/permissions";
11+
import { RequirePermission } from "modules/permissions/RequirePermission";
1212
import { type FC, Suspense } from "react";
1313
import { Navigate, Outlet, useLocation } from "react-router-dom";
1414
import { DeploymentSidebar } from "./DeploymentSidebar";
@@ -21,8 +21,8 @@ const DeploymentSettingsLayout: FC = () => {
2121
return (
2222
<Navigate
2323
to={
24-
permissions.viewDeploymentValues
25-
? "/deployment/general"
24+
permissions.viewDeploymentConfig
25+
? "/deployment/overview"
2626
: "/deployment/users"
2727
}
2828
replace

site/src/modules/management/DeploymentSidebarView.stories.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ export const NoDeploymentValues: Story = {
4747
args: {
4848
permissions: {
4949
...MockPermissions,
50-
viewDeploymentValues: false,
51-
editDeploymentValues: false,
50+
viewDeploymentConfig: false,
51+
editDeploymentConfig: false,
5252
},
5353
},
5454
};

0 commit comments

Comments
 (0)