mirror of
https://github.com/coder/coder.git
synced 2026-09-21 20:51:01 +08:00
fix: add groups to deployment settings (#16185)
fixes #16182 <img width="1177" alt="Screenshot 2025-01-17 at 23 20 04" src="https://github.com/user-attachments/assets/e0eec4bb-6b50-45e9-a27b-d3a89552562a" /> <img width="1163" alt="Screenshot 2025-01-17 at 23 20 12" src="https://github.com/user-attachments/assets/d8a7129c-0240-4ef5-9f21-84cda5631366" /> <img width="1161" alt="Screenshot 2025-01-17 at 23 20 22" src="https://github.com/user-attachments/assets/0ec78f3d-ec96-46a6-8def-aad4700712ac" />
This commit is contained in:
+5
-3
@@ -293,13 +293,15 @@ export const createTemplate = async (
|
||||
* random name.
|
||||
*/
|
||||
export const createGroup = async (page: Page): Promise<string> => {
|
||||
await page.goto("/groups/create", { waitUntil: "domcontentloaded" });
|
||||
await expectUrl(page).toHavePathName("/groups/create");
|
||||
await page.goto("/deployment/groups/create", {
|
||||
waitUntil: "domcontentloaded",
|
||||
});
|
||||
await expectUrl(page).toHavePathName("/deployment/groups/create");
|
||||
|
||||
const name = randomName();
|
||||
await page.getByLabel("Name", { exact: true }).fill(name);
|
||||
await page.getByRole("button", { name: /save/i }).click();
|
||||
await expectUrl(page).toHavePathName(`/groups/${name}`);
|
||||
await expectUrl(page).toHavePathName(`/deployment/groups/${name}`);
|
||||
return name;
|
||||
};
|
||||
|
||||
|
||||
@@ -99,6 +99,9 @@ const DeploymentSettingsNavigation: FC<DeploymentSettingsNavigationProps> = ({
|
||||
{permissions.viewAllUsers && (
|
||||
<SidebarNavItem href="/deployment/users">Users</SidebarNavItem>
|
||||
)}
|
||||
{permissions.viewAnyGroup && (
|
||||
<SidebarNavItem href="/deployment/groups">Groups</SidebarNavItem>
|
||||
)}
|
||||
{permissions.viewNotificationTemplate && (
|
||||
<SidebarNavItem href="/deployment/notifications">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
|
||||
@@ -19,7 +19,7 @@ export const CreateGroupPage: FC = () => {
|
||||
<CreateGroupPageView
|
||||
onSubmit={async (data) => {
|
||||
const newGroup = await createGroupMutation.mutateAsync(data);
|
||||
navigate(`/groups/${newGroup.name}`);
|
||||
navigate(`/deployment/groups/${newGroup.name}`);
|
||||
}}
|
||||
error={createGroupMutation.error}
|
||||
isLoading={createGroupMutation.isLoading}
|
||||
|
||||
@@ -50,7 +50,7 @@ export const CreateGroupPageView: FC<CreateGroupPageViewProps> = ({
|
||||
initialTouched,
|
||||
});
|
||||
const getFieldHelpers = getFormHelpers<CreateGroupRequest>(form, error);
|
||||
const onCancel = () => navigate("/groups");
|
||||
const onCancel = () => navigate("/deployment/groups");
|
||||
|
||||
return (
|
||||
<Margins>
|
||||
|
||||
@@ -211,7 +211,7 @@ export const GroupPage: FC = () => {
|
||||
try {
|
||||
await deleteGroupMutation.mutateAsync(groupId);
|
||||
displaySuccess("Group deleted successfully.");
|
||||
navigate("/groups");
|
||||
navigate("/deployment/groups");
|
||||
} catch (error) {
|
||||
displayError(getErrorMessage(error, "Failed to delete group."));
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ export const GroupsPageView: FC<GroupsPageViewProps> = ({
|
||||
canCreateGroup && (
|
||||
<Button
|
||||
component={RouterLink}
|
||||
to="/groups/create"
|
||||
to="/deployment/groups/create"
|
||||
startIcon={<AddOutlined />}
|
||||
variant="contained"
|
||||
>
|
||||
@@ -95,7 +95,7 @@ export const GroupsPageView: FC<GroupsPageViewProps> = ({
|
||||
|
||||
<Cond>
|
||||
{groups?.map((group) => {
|
||||
const groupPageLink = `/groups/${group.name}`;
|
||||
const groupPageLink = `/deployment/groups/${group.name}`;
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
|
||||
@@ -18,7 +18,7 @@ export const SettingsGroupPage: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const navigateToGroup = () => {
|
||||
navigate(`/groups/${groupName}`);
|
||||
navigate(`/deployment/groups/${groupName}`);
|
||||
};
|
||||
|
||||
const helmet = (
|
||||
@@ -56,7 +56,7 @@ export const SettingsGroupPage: FC = () => {
|
||||
add_users: [],
|
||||
remove_users: [],
|
||||
});
|
||||
navigate(`/groups/${data.name}`, { replace: true });
|
||||
navigate(`/deployment/groups/${data.name}`, { replace: true });
|
||||
} catch (error) {
|
||||
displayError(getErrorMessage(error, "Failed to update group"));
|
||||
}
|
||||
|
||||
@@ -1,80 +1,39 @@
|
||||
import GroupAdd from "@mui/icons-material/GroupAddOutlined";
|
||||
import PersonAdd from "@mui/icons-material/PersonAddOutlined";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Loader } from "components/Loader/Loader";
|
||||
import { Margins } from "components/Margins/Margins";
|
||||
import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader";
|
||||
import { TAB_PADDING_Y, TabLink, Tabs, TabsList } from "components/Tabs/Tabs";
|
||||
import { useAuthenticated } from "contexts/auth/RequireAuth";
|
||||
import { useDashboard } from "modules/dashboard/useDashboard";
|
||||
import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
|
||||
import { linkToUsers } from "modules/navigation";
|
||||
import { type FC, Suspense } from "react";
|
||||
import {
|
||||
Outlet,
|
||||
Link as RouterLink,
|
||||
useLocation,
|
||||
useNavigate,
|
||||
} from "react-router-dom";
|
||||
import { Outlet, Link as RouterLink } from "react-router-dom";
|
||||
|
||||
export const UsersLayout: FC = () => {
|
||||
const { permissions } = useAuthenticated();
|
||||
const { showOrganizations } = useDashboard();
|
||||
const navigate = useNavigate();
|
||||
const feats = useFeatureVisibility();
|
||||
const location = useLocation();
|
||||
const activeTab = location.pathname.endsWith("groups") ? "groups" : "users";
|
||||
|
||||
return (
|
||||
<>
|
||||
<Margins>
|
||||
<PageHeader
|
||||
actions={
|
||||
<>
|
||||
{permissions.createUser && (
|
||||
<Button
|
||||
onClick={() => {
|
||||
navigate("/users/create");
|
||||
}}
|
||||
startIcon={<PersonAdd />}
|
||||
>
|
||||
Create user
|
||||
</Button>
|
||||
)}
|
||||
<div>
|
||||
{permissions.createGroup && feats.template_rbac && (
|
||||
<Button
|
||||
component={RouterLink}
|
||||
startIcon={<GroupAdd />}
|
||||
to="/groups/create"
|
||||
to="/deployment/groups/create"
|
||||
>
|
||||
Create group
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<PageHeaderTitle>Users</PageHeaderTitle>
|
||||
<PageHeaderTitle>Groups</PageHeaderTitle>
|
||||
</PageHeader>
|
||||
</Margins>
|
||||
|
||||
{!showOrganizations && (
|
||||
<Tabs
|
||||
css={{ marginBottom: 40, marginTop: -TAB_PADDING_Y }}
|
||||
active={activeTab}
|
||||
>
|
||||
<Margins>
|
||||
<TabsList>
|
||||
<TabLink to={linkToUsers} value="users">
|
||||
Users
|
||||
</TabLink>
|
||||
<TabLink to="/groups" value="groups">
|
||||
Groups
|
||||
</TabLink>
|
||||
</TabsList>
|
||||
</Margins>
|
||||
</Tabs>
|
||||
)}
|
||||
|
||||
<Margins>
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Outlet />
|
||||
|
||||
+14
-3
@@ -353,7 +353,7 @@ const templateRouter = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const groupsRouter = () => {
|
||||
const organizationGroupsRouter = () => {
|
||||
return (
|
||||
<Route path="groups">
|
||||
<Route index element={<OrganizationGroupsPage />} />
|
||||
@@ -433,7 +433,7 @@ export const router = createBrowserRouter(
|
||||
|
||||
<Route path=":organization" element={<OrganizationSidebarLayout />}>
|
||||
<Route index element={<OrganizationMembersPage />} />
|
||||
{groupsRouter()}
|
||||
{organizationGroupsRouter()}
|
||||
<Route path="roles">
|
||||
<Route index element={<OrganizationCustomRolesPage />} />
|
||||
<Route path="create" element={<CreateEditRolePage />} />
|
||||
@@ -488,7 +488,18 @@ export const router = createBrowserRouter(
|
||||
|
||||
<Route path="users" element={<UsersPage />} />
|
||||
<Route path="users/create" element={<CreateUserPage />} />
|
||||
{groupsRouter()}
|
||||
<Route path="groups">
|
||||
<Route element={<UsersLayout />}>
|
||||
<Route index element={<GroupsPage />} />
|
||||
</Route>
|
||||
|
||||
<Route path="create" element={<CreateGroupPage />} />
|
||||
<Route path=":groupName" element={<GroupPage />} />
|
||||
<Route
|
||||
path=":groupName/settings"
|
||||
element={<SettingsGroupPage />}
|
||||
/>
|
||||
</Route>
|
||||
</Route>
|
||||
|
||||
<Route path="/settings" element={<UserSettingsLayout />}>
|
||||
|
||||
Reference in New Issue
Block a user