diff --git a/site/src/api/queries/users.ts b/site/src/api/queries/users.ts index 7dcd157f7bc6c..cf70038e7ca23 100644 --- a/site/src/api/queries/users.ts +++ b/site/src/api/queries/users.ts @@ -249,3 +249,10 @@ export const updateAppearanceSettings = ( }, }; }; + +export const myOrganizations = () => { + return { + queryKey: ["organizations", "me"], + queryFn: () => API.getOrganizations(), + }; +}; diff --git a/site/src/contexts/auth/RequireAuth.tsx b/site/src/contexts/auth/RequireAuth.tsx index b1def94fd9485..6172ba8212ac5 100644 --- a/site/src/contexts/auth/RequireAuth.tsx +++ b/site/src/contexts/auth/RequireAuth.tsx @@ -67,7 +67,7 @@ export const RequireAuth: FC = () => { }; type RequireKeys = Omit & { - [K in keyof Pick]: NonNullable; + [K in keyof Pick]-?: NonNullable; }; // We can do some TS magic here but I would rather to be explicit on what diff --git a/site/src/modules/dashboard/Navbar/NavbarView.stories.tsx b/site/src/modules/dashboard/Navbar/NavbarView.stories.tsx index cf5522c56203a..2490234bd36e1 100644 --- a/site/src/modules/dashboard/Navbar/NavbarView.stories.tsx +++ b/site/src/modules/dashboard/Navbar/NavbarView.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { chromaticWithTablet } from "testHelpers/chromatic"; import { MockUser, MockUser2 } from "testHelpers/entities"; +import { withDashboardProvider } from "testHelpers/storybook"; import { NavbarView } from "./NavbarView"; const meta: Meta = { @@ -10,6 +11,7 @@ const meta: Meta = { args: { user: MockUser, }, + decorators: [withDashboardProvider], }; export default meta; diff --git a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx index 04e18fc3d49f0..c7652eb460c77 100644 --- a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx +++ b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.stories.tsx @@ -1,6 +1,7 @@ import type { Meta, StoryObj } from "@storybook/react"; import { expect, screen, userEvent, within, waitFor } from "@storybook/test"; import { MockBuildInfo, MockUser } from "testHelpers/entities"; +import { withDashboardProvider } from "testHelpers/storybook"; import { UserDropdown } from "./UserDropdown"; const meta: Meta = { @@ -16,6 +17,7 @@ const meta: Meta = { { icon: "/icon/aws.svg", name: "Amazon Web Services", target: "" }, ], }, + decorators: [withDashboardProvider], }; export default meta; diff --git a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.tsx b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.tsx index b42858157d142..1efdfec9df0ed 100644 --- a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.tsx +++ b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.tsx @@ -1,6 +1,8 @@ import { css, type Interpolation, type Theme, useTheme } from "@emotion/react"; import Badge from "@mui/material/Badge"; import type { FC } from "react"; +import { useQuery } from "react-query"; +import { myOrganizations } from "api/queries/users"; import type * as TypesGen from "api/typesGenerated"; import { DropdownArrow } from "components/DropdownArrow/DropdownArrow"; import { @@ -9,6 +11,7 @@ import { PopoverTrigger, } from "components/Popover/Popover"; import { UserAvatar } from "components/UserAvatar/UserAvatar"; +import { useDashboard } from "modules/dashboard/useDashboard"; import { BUTTON_SM_HEIGHT, navHeight } from "theme/constants"; import { UserDropdownContent } from "./UserDropdownContent"; @@ -26,6 +29,11 @@ export const UserDropdown: FC = ({ onSignOut, }) => { const theme = useTheme(); + const organizationsQuery = useQuery({ + ...myOrganizations(), + enabled: Boolean(localStorage.getItem("enableMultiOrganizationUi")), + }); + const { organizationId, setOrganizationId } = useDashboard(); return ( @@ -63,6 +71,9 @@ export const UserDropdown: FC = ({ user={user} buildInfo={buildInfo} supportLinks={supportLinks} + organizations={organizationsQuery.data} + organizationId={organizationId} + setOrganizationId={setOrganizationId} onSignOut={onSignOut} /> diff --git a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx index fa3f64c37cb18..8dc0f23d34f73 100644 --- a/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx +++ b/site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx @@ -84,14 +84,20 @@ const styles = { export interface UserDropdownContentProps { user: TypesGen.User; + organizations?: TypesGen.Organization[]; + organizationId?: string; + setOrganizationId?: (id: string) => void; buildInfo?: TypesGen.BuildInfoResponse; supportLinks?: readonly TypesGen.LinkConfig[]; onSignOut: () => void; } export const UserDropdownContent: FC = ({ - buildInfo, user, + organizations, + organizationId, + setOrganizationId, + buildInfo, supportLinks, onSignOut, }) => { @@ -128,6 +134,43 @@ export const UserDropdownContent: FC = ({ + {organizations && ( + <> +
+
+ My teams +
+ {organizations.map((org) => ( + { + setOrganizationId?.(org.id); + popover.setIsOpen(false); + }} + > + {/* */} + + {org.name} + {organizationId === org.id && ( + Current + )} + + + ))} +
+ + + )} +