Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8b6a06d

Browse files
authored
chore: consolidate ManageSettingsLayout code (#14885)
Clean up a bunch of tangles that only existed to service the `"multi-organization"` experiment, which has now been removed
1 parent 04af56d commit 8b6a06d

File tree

78 files changed

+241
-339
lines changed

Some content is hidden

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

78 files changed

+241
-339
lines changed

site/e2e/tests/users/createUserWithPassword.spec.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import { beforeCoderTest } from "../../hooks";
55
test.beforeEach(async ({ page }) => await beforeCoderTest(page));
66

77
test("create user with password", async ({ page, baseURL }) => {
8-
await page.goto(`${baseURL}/users`, { waitUntil: "domcontentloaded" });
8+
await page.goto(`${baseURL}/deployment/users`, {
9+
waitUntil: "domcontentloaded",
10+
});
911
await expect(page).toHaveTitle("Users - Coder");
1012

1113
await page.getByRole("button", { name: "Create user" }).click();
@@ -37,7 +39,9 @@ test("create user with password", async ({ page, baseURL }) => {
3739
});
3840

3941
test("create user without full name is optional", async ({ page, baseURL }) => {
40-
await page.goto(`${baseURL}/users`, { waitUntil: "domcontentloaded" });
42+
await page.goto(`${baseURL}/deployment/users`, {
43+
waitUntil: "domcontentloaded",
44+
});
4145
await expect(page).toHaveTitle("Users - Coder");
4246

4347
await page.getByRole("button", { name: "Create user" }).click();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ const DeploymentDropdownContent: FC<DeploymentDropdownProps> = ({
114114
{canViewAllUsers && (
115115
<MenuItem
116116
component={NavLink}
117-
to={canViewOrganizations ? `/deployment${linkToUsers}` : linkToUsers}
117+
to={linkToUsers}
118118
css={styles.menuItem}
119119
onClick={onPopoverClose}
120120
>
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,37 @@
1+
import type { DeploymentConfig } from "api/api";
12
import { deploymentConfig } from "api/queries/deployment";
23
import type { AuthorizationResponse, Organization } from "api/typesGenerated";
4+
import { ErrorAlert } from "components/Alert/ErrorAlert";
35
import { Loader } from "components/Loader/Loader";
46
import { Margins } from "components/Margins/Margins";
57
import { Stack } from "components/Stack/Stack";
68
import { useAuthenticated } from "contexts/auth/RequireAuth";
79
import { RequirePermission } from "contexts/auth/RequirePermission";
810
import { useDashboard } from "modules/dashboard/useDashboard";
9-
import { type FC, Suspense } from "react";
11+
import { type FC, Suspense, createContext, useContext } from "react";
1012
import { useQuery } from "react-query";
11-
import { Outlet } from "react-router-dom";
12-
import { DeploySettingsContext } from "../DeploySettingsPage/DeploySettingsLayout";
13+
import { Outlet, useParams } from "react-router-dom";
1314
import { Sidebar } from "./Sidebar";
1415

15-
type OrganizationSettingsValue = Readonly<{
16+
export const ManagementSettingsContext = createContext<
17+
ManagementSettingsValue | undefined
18+
>(undefined);
19+
20+
type ManagementSettingsValue = Readonly<{
21+
deploymentValues: DeploymentConfig;
1622
organizations: readonly Organization[];
23+
organization?: Organization;
1724
}>;
1825

19-
export const useOrganizationSettings = (): OrganizationSettingsValue => {
20-
const { organizations } = useDashboard();
21-
return { organizations };
26+
export const useManagementSettings = (): ManagementSettingsValue => {
27+
const context = useContext(ManagementSettingsContext);
28+
if (!context) {
29+
throw new Error(
30+
"useManagementSettings should be used inside of ManagementSettingsLayout",
31+
);
32+
}
33+
34+
return context;
2235
};
2336

2437
/**
@@ -43,13 +56,11 @@ export const canEditOrganization = (
4356
*/
4457
export const ManagementSettingsLayout: FC = () => {
4558
const { permissions } = useAuthenticated();
46-
const deploymentConfigQuery = useQuery(
47-
// TODO: This is probably normally fine because we will not show links to
48-
// pages that need this data, but if you manually visit the page you
49-
// will see an endless loader when maybe we should show a "permission
50-
// denied" error or at least a 404 instead.
51-
permissions.viewDeploymentValues ? deploymentConfig() : { enabled: false },
52-
);
59+
const deploymentConfigQuery = useQuery(deploymentConfig());
60+
const { organizations } = useDashboard();
61+
const { organization: orgName } = useParams() as {
62+
organization?: string;
63+
};
5364

5465
// The deployment settings page also contains users, audit logs, groups and
5566
// organizations, so this page must be visible if you can see any of these.
@@ -59,24 +70,39 @@ export const ManagementSettingsLayout: FC = () => {
5970
permissions.editAnyOrganization ||
6071
permissions.viewAnyAuditLog;
6172

73+
if (deploymentConfigQuery.error) {
74+
return <ErrorAlert error={deploymentConfigQuery.error} />;
75+
}
76+
77+
if (!deploymentConfigQuery.data) {
78+
return <Loader />;
79+
}
80+
81+
const organization =
82+
organizations && orgName
83+
? organizations.find((org) => org.name === orgName)
84+
: undefined;
85+
6286
return (
6387
<RequirePermission isFeatureVisible={canViewDeploymentSettingsPage}>
64-
<Margins>
65-
<Stack css={{ padding: "48px 0" }} direction="row" spacing={6}>
66-
<Sidebar />
67-
<main css={{ width: "100%" }}>
68-
<DeploySettingsContext.Provider
69-
value={{
70-
deploymentValues: deploymentConfigQuery.data,
71-
}}
72-
>
88+
<ManagementSettingsContext.Provider
89+
value={{
90+
deploymentValues: deploymentConfigQuery.data,
91+
organizations,
92+
organization,
93+
}}
94+
>
95+
<Margins>
96+
<Stack css={{ padding: "48px 0" }} direction="row" spacing={6}>
97+
<Sidebar />
98+
<main css={{ width: "100%" }}>
7399
<Suspense fallback={<Loader />}>
74100
<Outlet />
75101
</Suspense>
76-
</DeploySettingsContext.Provider>
77-
</main>
78-
</Stack>
79-
</Margins>
102+
</main>
103+
</Stack>
104+
</Margins>
105+
</ManagementSettingsContext.Provider>
80106
</RequirePermission>
81107
);
82108
};

site/src/pages/ManagementSettingsPage/Sidebar.tsx renamed to site/src/modules/management/Sidebar.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { organizationsPermissions } from "api/queries/organizations";
22
import { useAuthenticated } from "contexts/auth/RequireAuth";
33
import { useDashboard } from "modules/dashboard/useDashboard";
4+
import {
5+
canEditOrganization,
6+
useManagementSettings,
7+
} from "modules/management/ManagementSettingsLayout";
48
import type { FC } from "react";
59
import { useQuery } from "react-query";
610
import { useLocation, useParams } from "react-router-dom";
7-
import {
8-
canEditOrganization,
9-
useOrganizationSettings,
10-
} from "./ManagementSettingsLayout";
1111
import { type OrganizationWithPermissions, SidebarView } from "./SidebarView";
1212

1313
/**
@@ -20,8 +20,7 @@ import { type OrganizationWithPermissions, SidebarView } from "./SidebarView";
2020
export const Sidebar: FC = () => {
2121
const location = useLocation();
2222
const { permissions } = useAuthenticated();
23-
const { experiments } = useDashboard();
24-
const { organizations } = useOrganizationSettings();
23+
const { organizations } = useManagementSettings();
2524
const { organization: organizationName } = useParams() as {
2625
organization?: string;
2726
};
@@ -56,7 +55,6 @@ export const Sidebar: FC = () => {
5655
activeOrganizationName={organizationName}
5756
organizations={editableOrgs}
5857
permissions={permissions}
59-
experiments={experiments}
6058
/>
6159
);
6260
};

site/src/pages/ManagementSettingsPage/SidebarView.stories.tsx renamed to site/src/modules/management/SidebarView.stories.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import { withDashboardProvider } from "testHelpers/storybook";
88
import { SidebarView } from "./SidebarView";
99

1010
const meta: Meta<typeof SidebarView> = {
11-
title: "components/MultiOrgSidebarView",
11+
title: "modules/management/SidebarView",
1212
component: SidebarView,
1313
decorators: [withDashboardProvider],
14+
parameters: { showOrganizations: true },
1415
args: {
1516
activeSettings: true,
1617
activeOrganizationName: undefined,
@@ -35,7 +36,6 @@ const meta: Meta<typeof SidebarView> = {
3536
},
3637
],
3738
permissions: MockPermissions,
38-
experiments: ["notifications"],
3939
},
4040
};
4141

@@ -223,3 +223,9 @@ export const SelectedMultiOrgAdminAndUserAdmin: Story = {
223223
],
224224
},
225225
};
226+
227+
export const OrgsDisabled: Story = {
228+
parameters: {
229+
showOrganizations: false,
230+
},
231+
};

site/src/pages/ManagementSettingsPage/SidebarView.tsx renamed to site/src/modules/management/SidebarView.tsx

Lines changed: 60 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ interface SidebarProps {
3131
organizations: OrganizationWithPermissions[] | undefined;
3232
/** Site-wide permissions. */
3333
permissions: AuthorizationResponse;
34-
/** Active experiments */
35-
experiments: Experiments;
3634
}
3735

3836
/**
@@ -43,25 +41,29 @@ export const SidebarView: FC<SidebarProps> = ({
4341
activeOrganizationName,
4442
organizations,
4543
permissions,
46-
experiments,
4744
}) => {
45+
const { showOrganizations } = useDashboard();
46+
4847
// TODO: Do something nice to scroll to the active org.
4948
return (
5049
<BaseSidebar>
51-
<header>
52-
<h2 css={styles.sidebarHeader}>Deployment</h2>
53-
</header>
50+
{showOrganizations && (
51+
<header>
52+
<h2 css={styles.sidebarHeader}>Deployment</h2>
53+
</header>
54+
)}
5455

5556
<DeploymentSettingsNavigation
5657
active={!activeOrganizationName && activeSettings}
57-
experiments={experiments}
58-
permissions={permissions}
59-
/>
60-
<OrganizationsSettingsNavigation
61-
activeOrganizationName={activeOrganizationName}
62-
organizations={organizations}
6358
permissions={permissions}
6459
/>
60+
{showOrganizations && (
61+
<OrganizationsSettingsNavigation
62+
activeOrganizationName={activeOrganizationName}
63+
organizations={organizations}
64+
permissions={permissions}
65+
/>
66+
)}
6567
</BaseSidebar>
6668
);
6769
};
@@ -71,8 +73,6 @@ interface DeploymentSettingsNavigationProps {
7173
active: boolean;
7274
/** Site-wide permissions. */
7375
permissions: AuthorizationResponse;
74-
/** Active experiments */
75-
experiments: Experiments;
7676
}
7777

7878
/**
@@ -85,7 +85,6 @@ interface DeploymentSettingsNavigationProps {
8585
const DeploymentSettingsNavigation: FC<DeploymentSettingsNavigationProps> = ({
8686
active,
8787
permissions,
88-
experiments,
8988
}) => {
9089
return (
9190
<div css={{ paddingBottom: 12 }}>
@@ -144,16 +143,14 @@ const DeploymentSettingsNavigation: FC<DeploymentSettingsNavigationProps> = ({
144143
</SidebarNavSubItem>
145144
)}
146145
{permissions.viewAllUsers && (
147-
<SidebarNavSubItem href={linkToUsers.slice(1)}>
148-
Users
149-
</SidebarNavSubItem>
146+
<SidebarNavSubItem href="users">Users</SidebarNavSubItem>
150147
)}
151-
<Stack direction="row" alignItems="center" css={{ gap: 0 }}>
152-
<SidebarNavSubItem href="notifications">
153-
Notifications
154-
</SidebarNavSubItem>
155-
<FeatureStageBadge contentType="beta" size="sm" />
156-
</Stack>
148+
<SidebarNavSubItem href="notifications">
149+
<Stack direction="row" alignItems="center" spacing={1}>
150+
<span>Notifications</span>
151+
<FeatureStageBadge contentType="beta" size="sm" />
152+
</Stack>
153+
</SidebarNavSubItem>
157154
</Stack>
158155
)}
159156
</div>
@@ -387,49 +384,49 @@ const styles = {
387384

388385
const classNames = {
389386
link: (css, theme) => css`
390-
color: inherit;
391-
display: block;
392-
font-size: 14px;
393-
text-decoration: none;
394-
padding: 10px 12px 10px 16px;
395-
border-radius: 4px;
396-
transition: background-color 0.15s ease-in-out;
397-
position: relative;
398-
399-
&:hover {
400-
background-color: ${theme.palette.action.hover};
401-
}
402-
403-
border-left: 3px solid transparent;
404-
`,
387+
color: inherit;
388+
display: block;
389+
font-size: 14px;
390+
text-decoration: none;
391+
padding: 10px 12px 10px 16px;
392+
border-radius: 4px;
393+
transition: background-color 0.15s ease-in-out;
394+
position: relative;
395+
396+
&:hover {
397+
background-color: ${theme.palette.action.hover};
398+
}
399+
400+
border-left: 3px solid transparent;
401+
`,
405402

406403
activeLink: (css, theme) => css`
407-
border-left-color: ${theme.palette.primary.main};
408-
border-top-left-radius: 0;
409-
border-bottom-left-radius: 0;
410-
`,
404+
border-left-color: ${theme.palette.primary.main};
405+
border-top-left-radius: 0;
406+
border-bottom-left-radius: 0;
407+
`,
411408

412409
subLink: (css, theme) => css`
413-
color: ${theme.palette.text.secondary};
414-
text-decoration: none;
415-
416-
display: block;
417-
font-size: 13px;
418-
margin-left: 44px;
419-
padding: 4px 12px;
420-
border-radius: 4px;
421-
transition: background-color 0.15s ease-in-out;
422-
margin-bottom: 1px;
423-
position: relative;
424-
425-
&:hover {
426-
color: ${theme.palette.text.primary};
427-
background-color: ${theme.palette.action.hover};
428-
}
429-
`,
410+
color: ${theme.palette.text.secondary};
411+
text-decoration: none;
412+
413+
display: block;
414+
font-size: 13px;
415+
margin-left: 44px;
416+
padding: 4px 12px;
417+
border-radius: 4px;
418+
transition: background-color 0.15s ease-in-out;
419+
margin-bottom: 1px;
420+
position: relative;
421+
422+
&:hover {
423+
color: ${theme.palette.text.primary};
424+
background-color: ${theme.palette.action.hover};
425+
}
426+
`,
430427

431428
activeSubLink: (css, theme) => css`
432-
color: ${theme.palette.text.primary};
433-
font-weight: 600;
434-
`,
429+
color: ${theme.palette.text.primary};
430+
font-weight: 600;
431+
`,
435432
} satisfies Record<string, ClassName>;

0 commit comments

Comments
 (0)