From 4c840c73362f35117e587d974df2097c0fc97d90 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 25 Jul 2024 18:26:46 +0000 Subject: [PATCH 1/8] feat: manage non-multi-org groups from deployment settings --- site/src/api/queries/groups.ts | 12 ++-- .../GroupsPage/CreateGroupPage.tsx | 2 +- .../GroupsPage/GroupPage.tsx | 2 +- .../GroupsPage/GroupSettingsPage.tsx | 2 +- .../GroupsPage/GroupsPage.tsx | 7 +-- .../ManagementSettingsLayout.tsx | 24 +++---- .../OrganizationSettingsPage.tsx | 23 +++++-- .../OrganizationSettingsPlaceholder.tsx | 37 ----------- .../pages/ManagementSettingsPage/Sidebar.tsx | 63 +++++++++++++------ site/src/router.tsx | 39 ++++++------ 10 files changed, 101 insertions(+), 110 deletions(-) delete mode 100644 site/src/pages/ManagementSettingsPage/OrganizationSettingsPlaceholder.tsx diff --git a/site/src/api/queries/groups.ts b/site/src/api/queries/groups.ts index e532ebcd81d43..40fc04037b1ab 100644 --- a/site/src/api/queries/groups.ts +++ b/site/src/api/queries/groups.ts @@ -6,10 +6,10 @@ import type { PatchGroupRequest, } from "api/typesGenerated"; -const GROUPS_QUERY_KEY = ["groups"]; type GroupSortOrder = "asc" | "desc"; const getGroupQueryKey = (organizationId: string, groupName: string) => [ + "organization", organizationId, "group", groupName, @@ -17,7 +17,7 @@ const getGroupQueryKey = (organizationId: string, groupName: string) => [ export const groups = (organizationId: string) => { return { - queryKey: GROUPS_QUERY_KEY, + queryKey: ["organization", organizationId, "groups"], queryFn: () => API.getGroups(organizationId), } satisfies UseQueryOptions; }; @@ -97,7 +97,11 @@ export const createGroup = ( mutationFn: (request: CreateGroupRequest) => API.createGroup(organizationId, request), onSuccess: async () => { - await queryClient.invalidateQueries(GROUPS_QUERY_KEY); + await queryClient.invalidateQueries([ + "organization", + organizationId, + "groups", + ]); }, }; }; @@ -146,7 +150,7 @@ export const invalidateGroup = ( groupId: string, ) => Promise.all([ - queryClient.invalidateQueries(GROUPS_QUERY_KEY), + queryClient.invalidateQueries(["organization", organizationId, "groups"]), queryClient.invalidateQueries(getGroupQueryKey(organizationId, groupId)), ]); diff --git a/site/src/pages/ManagementSettingsPage/GroupsPage/CreateGroupPage.tsx b/site/src/pages/ManagementSettingsPage/GroupsPage/CreateGroupPage.tsx index a51d67d63ce34..73353aa23a220 100644 --- a/site/src/pages/ManagementSettingsPage/GroupsPage/CreateGroupPage.tsx +++ b/site/src/pages/ManagementSettingsPage/GroupsPage/CreateGroupPage.tsx @@ -9,7 +9,7 @@ import CreateGroupPageView from "./CreateGroupPageView"; export const CreateGroupPage: FC = () => { const queryClient = useQueryClient(); const navigate = useNavigate(); - const { organization } = useParams() as { organization: string }; + const { organization = "default" } = useParams() as { organization: string }; const createGroupMutation = useMutation( createGroup(queryClient, organization), ); diff --git a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupPage.tsx b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupPage.tsx index 2ab2e0c2fd8b4..b3be7c472d11c 100644 --- a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupPage.tsx +++ b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupPage.tsx @@ -50,7 +50,7 @@ import { isEveryoneGroup } from "utils/groups"; import { pageTitle } from "utils/page"; export const GroupPage: FC = () => { - const { organization, groupName } = useParams() as { + const { organization = "default", groupName } = useParams() as { organization: string; groupName: string; }; diff --git a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupSettingsPage.tsx b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupSettingsPage.tsx index ca9b836c4ba5c..e07f44aeb99e6 100644 --- a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupSettingsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupSettingsPage.tsx @@ -11,7 +11,7 @@ import { pageTitle } from "utils/page"; import GroupSettingsPageView from "./GroupSettingsPageView"; export const GroupSettingsPage: FC = () => { - const { organization, groupName } = useParams() as { + const { organization = "default", groupName } = useParams() as { organization: string; groupName: string; }; diff --git a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx index 91d727589d8b2..067c4f6887077 100644 --- a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx @@ -3,7 +3,7 @@ import Button from "@mui/material/Button"; import { type FC, useEffect } from "react"; import { Helmet } from "react-helmet-async"; import { useQuery } from "react-query"; -import { Link as RouterLink } from "react-router-dom"; +import { Link as RouterLink, useParams } from "react-router-dom"; import { getErrorMessage } from "api/errors"; import { groups } from "api/queries/groups"; import { displayError } from "components/GlobalSnackbar/utils"; @@ -11,15 +11,14 @@ import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader"; import { useAuthenticated } from "contexts/auth/RequireAuth"; import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { pageTitle } from "utils/page"; -import { useOrganizationSettings } from "../ManagementSettingsLayout"; import GroupsPageView from "./GroupsPageView"; export const GroupsPage: FC = () => { const { permissions } = useAuthenticated(); - const { currentOrganizationId } = useOrganizationSettings(); const { createGroup: canCreateGroup } = permissions; const { template_rbac: isTemplateRBACEnabled } = useFeatureVisibility(); - const groupsQuery = useQuery(groups(currentOrganizationId!)); + const { organization = "default" } = useParams() as { organization: string }; + const groupsQuery = useQuery(groups(organization)); useEffect(() => { if (groupsQuery.error) { diff --git a/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx index 026358c18a99e..ce9afd7a0118f 100644 --- a/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx +++ b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx @@ -15,7 +15,7 @@ import { DeploySettingsContext } from "../DeploySettingsPage/DeploySettingsLayou import { Sidebar } from "./Sidebar"; type OrganizationSettingsContextValue = { - currentOrganizationId?: string; + // currentOrganizationId?: string; organizations: Organization[]; }; @@ -58,14 +58,14 @@ export const ManagementSettingsLayout: FC = () => { {organizationsQuery.data ? ( @@ -94,9 +94,3 @@ export const ManagementSettingsLayout: FC = () => { ); }; - -const getOrganizationIdByName = (organizations: Organization[], name: string) => - organizations.find((org) => org.name === name)?.id; - -const getOrganizationIdByDefault = (organizations: Organization[]) => - organizations.find((org) => org.is_default)?.id; diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx index 19831dc8cfbf6..7c52cc708fbcc 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx @@ -1,18 +1,23 @@ import type { FC } from "react"; import { useMutation, useQueryClient } from "react-query"; -import { useNavigate } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; import { updateOrganization, deleteOrganization, } from "api/queries/organizations"; +import type { Organization } from "api/typesGenerated"; import { EmptyState } from "components/EmptyState/EmptyState"; import { displaySuccess } from "components/GlobalSnackbar/utils"; import { useOrganizationSettings } from "./ManagementSettingsLayout"; import { OrganizationSettingsPageView } from "./OrganizationSettingsPageView"; const OrganizationSettingsPage: FC = () => { - const navigate = useNavigate(); + const { organization: organizationName } = useParams() as { + organization?: string; + }; + const { organizations } = useOrganizationSettings(); + const navigate = useNavigate(); const queryClient = useQueryClient(); const updateOrganizationMutation = useMutation( updateOrganization(queryClient), @@ -21,14 +26,14 @@ const OrganizationSettingsPage: FC = () => { deleteOrganization(queryClient), ); - const { currentOrganizationId, organizations } = useOrganizationSettings(); - - const org = organizations.find((org) => org.id === currentOrganizationId); + const org = organizationName + ? getOrganizationIdByName(organizations, organizationName) + : getOrganizationIdByDefault(organizations); const error = updateOrganizationMutation.error ?? deleteOrganizationMutation.error; - if (!currentOrganizationId || !org) { + if (!org) { return ; } @@ -55,3 +60,9 @@ const OrganizationSettingsPage: FC = () => { }; export default OrganizationSettingsPage; + +const getOrganizationIdByDefault = (organizations: Organization[]) => + organizations.find((org) => org.is_default); + +const getOrganizationIdByName = (organizations: Organization[], name: string) => + organizations.find((org) => org.name === name); diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPlaceholder.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPlaceholder.tsx deleted file mode 100644 index a1526ed53c102..0000000000000 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPlaceholder.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import type { FC } from "react"; -import { useMutation, useQueryClient } from "react-query"; -import { - createOrganization, - deleteOrganization, -} from "api/queries/organizations"; -import { ErrorAlert } from "components/Alert/ErrorAlert"; -import { Margins } from "components/Margins/Margins"; -import { useOrganizationSettings } from "./ManagementSettingsLayout"; - -const OrganizationSettingsPage: FC = () => { - const queryClient = useQueryClient(); - const addOrganizationMutation = useMutation(createOrganization(queryClient)); - const deleteOrganizationMutation = useMutation( - deleteOrganization(queryClient), - ); - - const { currentOrganizationId, organizations } = useOrganizationSettings(); - - const org = organizations.find((org) => org.id === currentOrganizationId)!; - - const error = - addOrganizationMutation.error ?? deleteOrganizationMutation.error; - - return ( - - {Boolean(error) && } - -

Organization settings

- -

Name: {org.name}

-

Display name: {org.display_name}

-
- ); -}; - -export default OrganizationSettingsPage; diff --git a/site/src/pages/ManagementSettingsPage/Sidebar.tsx b/site/src/pages/ManagementSettingsPage/Sidebar.tsx index fe34a6088a01b..1f9eb3c8b776e 100644 --- a/site/src/pages/ManagementSettingsPage/Sidebar.tsx +++ b/site/src/pages/ManagementSettingsPage/Sidebar.tsx @@ -3,7 +3,7 @@ import type { Interpolation, Theme } from "@emotion/react"; import AddIcon from "@mui/icons-material/Add"; import SettingsIcon from "@mui/icons-material/Settings"; import type { FC, ReactNode } from "react"; -import { Link, NavLink, useLocation } from "react-router-dom"; +import { Link, NavLink, useLocation, useParams } from "react-router-dom"; import type { Organization } from "api/typesGenerated"; import { Sidebar as BaseSidebar } from "components/Sidebar/Sidebar"; import { Stack } from "components/Stack/Stack"; @@ -11,36 +11,56 @@ import { UserAvatar } from "components/UserAvatar/UserAvatar"; import { type ClassName, useClassName } from "hooks/useClassName"; import { USERS_LINK } from "modules/navigation"; import { useOrganizationSettings } from "./ManagementSettingsLayout"; +import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; export const Sidebar: FC = () => { - const { currentOrganizationId, organizations } = useOrganizationSettings(); + const { organization: organizationName = "default" } = useParams() as { + organization: string; + }; + const { organizations } = useOrganizationSettings(); + const { multiple_organizations: organizationsEnabled } = + useFeatureVisibility(); // TODO: Do something nice to scroll to the active org. return ( -
Deployment
- -
Organizations
- } - > - New organization - - {organizations.map((organization) => ( - - ))} + {organizationsEnabled && ( +
Deployment
+ )} + + {organizationsEnabled && ( + <> +
Organizations
+ } + > + New organization + + {organizations.map((organization) => ( + + ))} + + )}
); }; -const DeploymentSettingsNavigation: FC = () => { +interface DeploymentSettingsNavigationProps { + organizationsEnabled?: boolean; +} + +const DeploymentSettingsNavigation: FC = ({ + organizationsEnabled, +}) => { const location = useLocation(); const active = location.pathname.startsWith("/deployment"); @@ -81,6 +101,9 @@ const DeploymentSettingsNavigation: FC = () => { Users + {!organizationsEnabled && ( + Groups + )} )} diff --git a/site/src/router.tsx b/site/src/router.tsx index c66a98b8a9a6e..3d54613fb98dd 100644 --- a/site/src/router.tsx +++ b/site/src/router.tsx @@ -242,10 +242,6 @@ const OrganizationGroupSettingsPage = lazy( const OrganizationMembersPage = lazy( () => import("./pages/ManagementSettingsPage/OrganizationMembersPage"), ); -const OrganizationSettingsPlaceholder = lazy( - () => - import("./pages/ManagementSettingsPage/OrganizationSettingsPlaceholder"), -); const TemplateEmbedPage = lazy( () => import("./pages/TemplatePage/TemplateEmbedPage/TemplateEmbedPage"), ); @@ -275,6 +271,21 @@ const RoutesWithSuspense = () => { ); }; +const groupsRouter = () => { + return ( + + } /> + + } /> + } /> + } + /> + + ); +}; + export const router = createBrowserRouter( createRoutesFromChildren( }> @@ -360,23 +371,8 @@ export const router = createBrowserRouter( } /> } /> - - } /> - - } - /> - } /> - } - /> - - } - /> + {groupsRouter()} + } /> @@ -409,6 +405,7 @@ export const router = createBrowserRouter( } /> } /> } /> + {groupsRouter()} }> From 5346d8eb9c1912f3149c8e44e2b09dffbf7a9ad6 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 25 Jul 2024 18:28:15 +0000 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ManagementSettingsLayout.tsx | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx index ce9afd7a0118f..6831fbc6a7db1 100644 --- a/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx +++ b/site/src/pages/ManagementSettingsPage/ManagementSettingsLayout.tsx @@ -1,6 +1,6 @@ import { createContext, type FC, Suspense, useContext } from "react"; import { useQuery } from "react-query"; -import { Outlet, useLocation, useParams } from "react-router-dom"; +import { Outlet } from "react-router-dom"; import { deploymentConfig } from "api/queries/deployment"; import { organizations } from "api/queries/organizations"; import type { Organization } from "api/typesGenerated"; @@ -15,7 +15,6 @@ import { DeploySettingsContext } from "../DeploySettingsPage/DeploySettingsLayou import { Sidebar } from "./Sidebar"; type OrganizationSettingsContextValue = { - // currentOrganizationId?: string; organizations: Organization[]; }; @@ -34,19 +33,13 @@ export const useOrganizationSettings = (): OrganizationSettingsContextValue => { }; export const ManagementSettingsLayout: FC = () => { - const location = useLocation(); const { permissions } = useAuthenticated(); const { experiments } = useDashboard(); - const { organization } = useParams() as { organization: string }; const deploymentConfigQuery = useQuery(deploymentConfig()); const organizationsQuery = useQuery(organizations()); const multiOrgExperimentEnabled = experiments.includes("multi-organization"); - const inOrganizationSettings = - location.pathname.startsWith("/organizations") && - location.pathname !== "/organizations/new"; - if (!multiOrgExperimentEnabled) { return ; } @@ -57,17 +50,7 @@ export const ManagementSettingsLayout: FC = () => { {organizationsQuery.data ? (
From 29dffc51c4e888bbccc2cb0af8fc2e8f230b8724 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 25 Jul 2024 20:38:37 +0000 Subject: [PATCH 3/8] of course --- site/src/pages/ManagementSettingsPage/Sidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/pages/ManagementSettingsPage/Sidebar.tsx b/site/src/pages/ManagementSettingsPage/Sidebar.tsx index 1f9eb3c8b776e..8ef03ada3ded6 100644 --- a/site/src/pages/ManagementSettingsPage/Sidebar.tsx +++ b/site/src/pages/ManagementSettingsPage/Sidebar.tsx @@ -9,9 +9,9 @@ import { Sidebar as BaseSidebar } from "components/Sidebar/Sidebar"; import { Stack } from "components/Stack/Stack"; import { UserAvatar } from "components/UserAvatar/UserAvatar"; import { type ClassName, useClassName } from "hooks/useClassName"; +import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { USERS_LINK } from "modules/navigation"; import { useOrganizationSettings } from "./ManagementSettingsLayout"; -import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; export const Sidebar: FC = () => { const { organization: organizationName = "default" } = useParams() as { From 7999b927bf0591f276cd06b9f8de7eeb45228b38 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 26 Jul 2024 17:03:53 +0000 Subject: [PATCH 4/8] require license, add key func --- site/src/api/queries/groups.ts | 22 ++++++++++--------- site/src/modules/dashboard/Navbar/Navbar.tsx | 5 ++++- .../GroupsPage/CreateGroupPage.tsx | 10 ++++++--- .../OrganizationSettingsPage.tsx | 8 +++---- .../pages/ManagementSettingsPage/Sidebar.tsx | 16 ++++++++------ 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/site/src/api/queries/groups.ts b/site/src/api/queries/groups.ts index 40fc04037b1ab..7658abd8e5304 100644 --- a/site/src/api/queries/groups.ts +++ b/site/src/api/queries/groups.ts @@ -8,20 +8,26 @@ import type { type GroupSortOrder = "asc" | "desc"; -const getGroupQueryKey = (organizationId: string, groupName: string) => [ +const getGroupsQueryKey = (organizationId: string) => [ "organization", organizationId, - "group", - groupName, + "groups", ]; export const groups = (organizationId: string) => { return { - queryKey: ["organization", organizationId, "groups"], + queryKey: getGroupsQueryKey(organizationId), queryFn: () => API.getGroups(organizationId), } satisfies UseQueryOptions; }; +const getGroupQueryKey = (organizationId: string, groupName: string) => [ + "organization", + organizationId, + "group", + groupName, +]; + export const group = (organizationId: string, groupName: string) => { return { queryKey: getGroupQueryKey(organizationId, groupName), @@ -97,11 +103,7 @@ export const createGroup = ( mutationFn: (request: CreateGroupRequest) => API.createGroup(organizationId, request), onSuccess: async () => { - await queryClient.invalidateQueries([ - "organization", - organizationId, - "groups", - ]); + await queryClient.invalidateQueries(getGroupsQueryKey(organizationId)); }, }; }; @@ -150,7 +152,7 @@ export const invalidateGroup = ( groupId: string, ) => Promise.all([ - queryClient.invalidateQueries(["organization", organizationId, "groups"]), + queryClient.invalidateQueries(getGroupsQueryKey(organizationId)), queryClient.invalidateQueries(getGroupQueryKey(organizationId, groupId)), ]); diff --git a/site/src/modules/dashboard/Navbar/Navbar.tsx b/site/src/modules/dashboard/Navbar/Navbar.tsx index cf1b3b842c4e3..b480f6a20891c 100644 --- a/site/src/modules/dashboard/Navbar/Navbar.tsx +++ b/site/src/modules/dashboard/Navbar/Navbar.tsx @@ -18,6 +18,9 @@ export const Navbar: FC = () => { const canViewAuditLog = featureVisibility["audit_log"] && Boolean(permissions.viewAuditLog); const canViewDeployment = Boolean(permissions.viewDeploymentValues); + const canViewOrganizations = + featureVisibility.multiple_organizations && + experiments.includes("multi-organization"); const canViewAllUsers = Boolean(permissions.readAllUsers); const proxyContextValue = useProxy(); const canViewHealth = canViewDeployment; @@ -30,7 +33,7 @@ export const Navbar: FC = () => { supportLinks={appearance.support_links} onSignOut={signOut} canViewDeployment={canViewDeployment} - canViewOrganizations={experiments.includes("multi-organization")} + canViewOrganizations={canViewOrganizations} canViewAllUsers={canViewAllUsers} canViewHealth={canViewHealth} canViewAuditLog={canViewAuditLog} diff --git a/site/src/pages/ManagementSettingsPage/GroupsPage/CreateGroupPage.tsx b/site/src/pages/ManagementSettingsPage/GroupsPage/CreateGroupPage.tsx index 73353aa23a220..310f51eda8eed 100644 --- a/site/src/pages/ManagementSettingsPage/GroupsPage/CreateGroupPage.tsx +++ b/site/src/pages/ManagementSettingsPage/GroupsPage/CreateGroupPage.tsx @@ -9,9 +9,9 @@ import CreateGroupPageView from "./CreateGroupPageView"; export const CreateGroupPage: FC = () => { const queryClient = useQueryClient(); const navigate = useNavigate(); - const { organization = "default" } = useParams() as { organization: string }; + const { organization } = useParams() as { organization: string }; const createGroupMutation = useMutation( - createGroup(queryClient, organization), + createGroup(queryClient, organization ?? "default"), ); return ( @@ -22,7 +22,11 @@ export const CreateGroupPage: FC = () => { { const newGroup = await createGroupMutation.mutateAsync(data); - navigate(`/organizations/${organization}/groups/${newGroup.name}`); + navigate( + organization + ? `/organizations/${organization}/groups/${newGroup.name}` + : `/deployment/groups/${newGroup.name}`, + ); }} error={createGroupMutation.error} isLoading={createGroupMutation.isLoading} diff --git a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx index 7c52cc708fbcc..a8cc5362b8d57 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationSettingsPage.tsx @@ -27,8 +27,8 @@ const OrganizationSettingsPage: FC = () => { ); const org = organizationName - ? getOrganizationIdByName(organizations, organizationName) - : getOrganizationIdByDefault(organizations); + ? getOrganizationByName(organizations, organizationName) + : getOrganizationByDefault(organizations); const error = updateOrganizationMutation.error ?? deleteOrganizationMutation.error; @@ -61,8 +61,8 @@ const OrganizationSettingsPage: FC = () => { export default OrganizationSettingsPage; -const getOrganizationIdByDefault = (organizations: Organization[]) => +const getOrganizationByDefault = (organizations: Organization[]) => organizations.find((org) => org.is_default); -const getOrganizationIdByName = (organizations: Organization[], name: string) => +const getOrganizationByName = (organizations: Organization[], name: string) => organizations.find((org) => org.name === name); diff --git a/site/src/pages/ManagementSettingsPage/Sidebar.tsx b/site/src/pages/ManagementSettingsPage/Sidebar.tsx index 8ef03ada3ded6..a07da66570897 100644 --- a/site/src/pages/ManagementSettingsPage/Sidebar.tsx +++ b/site/src/pages/ManagementSettingsPage/Sidebar.tsx @@ -14,10 +14,9 @@ import { USERS_LINK } from "modules/navigation"; import { useOrganizationSettings } from "./ManagementSettingsLayout"; export const Sidebar: FC = () => { - const { organization: organizationName = "default" } = useParams() as { - organization: string; - }; const { organizations } = useOrganizationSettings(); + const { organization = getOrganizationNameByDefault(organizations) } = + useParams() as { organization: string }; const { multiple_organizations: organizationsEnabled } = useFeatureVisibility(); @@ -41,11 +40,11 @@ export const Sidebar: FC = () => { > New organization - {organizations.map((organization) => ( + {organizations.map((org) => ( ))} @@ -282,3 +281,6 @@ const classNames = { font-weight: 600; `, } satisfies Record; + +const getOrganizationNameByDefault = (organizations: Organization[]) => + organizations.find((org) => org.is_default)?.name; From 01371eca7d8cf2cab01a1ee2065b0208517e1865 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 26 Jul 2024 17:58:09 +0000 Subject: [PATCH 5/8] add redirects and such --- .../GroupsPage/GroupsPage.tsx | 31 +++++++++++++++++-- site/src/pages/UsersPage/UsersPage.tsx | 4 +++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx index 067c4f6887077..67f21e7fc4b95 100644 --- a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx @@ -3,22 +3,36 @@ import Button from "@mui/material/Button"; import { type FC, useEffect } from "react"; import { Helmet } from "react-helmet-async"; import { useQuery } from "react-query"; -import { Link as RouterLink, useParams } from "react-router-dom"; +import { + Navigate, + Link as RouterLink, + useLocation, + useParams, +} from "react-router-dom"; import { getErrorMessage } from "api/errors"; import { groups } from "api/queries/groups"; import { displayError } from "components/GlobalSnackbar/utils"; import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader"; import { useAuthenticated } from "contexts/auth/RequireAuth"; +import { useDashboard } from "modules/dashboard/useDashboard"; import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { pageTitle } from "utils/page"; import GroupsPageView from "./GroupsPageView"; +import { useOrganizationSettings } from "../ManagementSettingsLayout"; +import { Organization } from "api/typesGenerated"; export const GroupsPage: FC = () => { const { permissions } = useAuthenticated(); const { createGroup: canCreateGroup } = permissions; - const { template_rbac: isTemplateRBACEnabled } = useFeatureVisibility(); + const { + multiple_organizations: organizationsEnabled, + template_rbac: isTemplateRBACEnabled, + } = useFeatureVisibility(); + const { experiments } = useDashboard(); + const location = useLocation(); const { organization = "default" } = useParams() as { organization: string }; const groupsQuery = useQuery(groups(organization)); + const { organizations } = useOrganizationSettings(); useEffect(() => { if (groupsQuery.error) { @@ -28,6 +42,16 @@ export const GroupsPage: FC = () => { } }, [groupsQuery.error]); + if ( + organizationsEnabled && + experiments.includes("multi-organization") && + location.pathname === "/deployment/groups" + ) { + const defaultName = + getOrganizationNameByDefault(organizations) ?? "default"; + return ; + } + return ( <> @@ -62,3 +86,6 @@ export const GroupsPage: FC = () => { }; export default GroupsPage; + +export const getOrganizationNameByDefault = (organizations: Organization[]) => + organizations.find((org) => org.is_default)?.name; diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx index 24880b94d80e3..b416c2d53734f 100644 --- a/site/src/pages/UsersPage/UsersPage.tsx +++ b/site/src/pages/UsersPage/UsersPage.tsx @@ -29,6 +29,7 @@ import { isNonInitialPage } from "components/PaginationWidget/utils"; import { useAuthenticated } from "contexts/auth/RequireAuth"; import { usePaginatedQuery } from "hooks/usePaginatedQuery"; import { useDashboard } from "modules/dashboard/useDashboard"; +import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { pageTitle } from "utils/page"; import { generateRandomString } from "utils/random"; import { ResetPasswordDialog } from "./ResetPasswordDialog"; @@ -43,6 +44,8 @@ const UsersPage: FC = () => { const { entitlements, experiments, organizationId } = useDashboard(); const [searchParams] = searchParamsResult; const isMultiOrg = experiments.includes("multi-organization"); + const { multiple_organizations: organizationsEnabled } = + useFeatureVisibility(); const groupsByUserIdQuery = useQuery(groupsByUserId(organizationId)); const authMethodsQuery = useQuery(authMethods()); @@ -104,6 +107,7 @@ const UsersPage: FC = () => { groupsByUserIdQuery.isLoading; if ( + organizationsEnabled && experiments.includes("multi-organization") && location.pathname !== "/deployment/users" ) { From f29bae0e2ea1b76d792be2b650134d063db6cede Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 26 Jul 2024 18:08:37 +0000 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=A7=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx index 67f21e7fc4b95..d8c756645363d 100644 --- a/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx +++ b/site/src/pages/ManagementSettingsPage/GroupsPage/GroupsPage.tsx @@ -11,15 +11,15 @@ import { } from "react-router-dom"; import { getErrorMessage } from "api/errors"; import { groups } from "api/queries/groups"; +import type { Organization } from "api/typesGenerated"; import { displayError } from "components/GlobalSnackbar/utils"; import { PageHeader, PageHeaderTitle } from "components/PageHeader/PageHeader"; import { useAuthenticated } from "contexts/auth/RequireAuth"; import { useDashboard } from "modules/dashboard/useDashboard"; import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { pageTitle } from "utils/page"; -import GroupsPageView from "./GroupsPageView"; import { useOrganizationSettings } from "../ManagementSettingsLayout"; -import { Organization } from "api/typesGenerated"; +import GroupsPageView from "./GroupsPageView"; export const GroupsPage: FC = () => { const { permissions } = useAuthenticated(); From 21ce3671f68461a81441209b435f73924c9817f3 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 26 Jul 2024 18:46:14 +0000 Subject: [PATCH 7/8] :) --- site/src/pages/UsersPage/UsersPage.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx index b416c2d53734f..b8aa4bd0cb542 100644 --- a/site/src/pages/UsersPage/UsersPage.tsx +++ b/site/src/pages/UsersPage/UsersPage.tsx @@ -43,9 +43,10 @@ const UsersPage: FC = () => { const searchParamsResult = useSearchParams(); const { entitlements, experiments, organizationId } = useDashboard(); const [searchParams] = searchParamsResult; - const isMultiOrg = experiments.includes("multi-organization"); const { multiple_organizations: organizationsEnabled } = useFeatureVisibility(); + const isMultiOrg = + organizationsEnabled && experiments.includes("multi-organization"); const groupsByUserIdQuery = useQuery(groupsByUserId(organizationId)); const authMethodsQuery = useQuery(authMethods()); From 9ed77d4cb3d684d8062903c7633169db4d20e33b Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 26 Jul 2024 19:00:32 +0000 Subject: [PATCH 8/8] ah, yes --- site/src/pages/UsersPage/UsersPage.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/site/src/pages/UsersPage/UsersPage.tsx b/site/src/pages/UsersPage/UsersPage.tsx index b8aa4bd0cb542..24880b94d80e3 100644 --- a/site/src/pages/UsersPage/UsersPage.tsx +++ b/site/src/pages/UsersPage/UsersPage.tsx @@ -29,7 +29,6 @@ import { isNonInitialPage } from "components/PaginationWidget/utils"; import { useAuthenticated } from "contexts/auth/RequireAuth"; import { usePaginatedQuery } from "hooks/usePaginatedQuery"; import { useDashboard } from "modules/dashboard/useDashboard"; -import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { pageTitle } from "utils/page"; import { generateRandomString } from "utils/random"; import { ResetPasswordDialog } from "./ResetPasswordDialog"; @@ -43,10 +42,7 @@ const UsersPage: FC = () => { const searchParamsResult = useSearchParams(); const { entitlements, experiments, organizationId } = useDashboard(); const [searchParams] = searchParamsResult; - const { multiple_organizations: organizationsEnabled } = - useFeatureVisibility(); - const isMultiOrg = - organizationsEnabled && experiments.includes("multi-organization"); + const isMultiOrg = experiments.includes("multi-organization"); const groupsByUserIdQuery = useQuery(groupsByUserId(organizationId)); const authMethodsQuery = useQuery(authMethods()); @@ -108,7 +104,6 @@ const UsersPage: FC = () => { groupsByUserIdQuery.isLoading; if ( - organizationsEnabled && experiments.includes("multi-organization") && location.pathname !== "/deployment/users" ) {