diff --git a/site/src/modules/management/OrganizationSidebarView.stories.tsx b/site/src/modules/management/OrganizationSidebarView.stories.tsx index 4f1b17a27c181..6533a5e004ef5 100644 --- a/site/src/modules/management/OrganizationSidebarView.stories.tsx +++ b/site/src/modules/management/OrganizationSidebarView.stories.tsx @@ -1,5 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react"; import { expect, userEvent, waitFor, within } from "@storybook/test"; +import type { AuthorizationResponse } from "api/typesGenerated"; import { MockNoPermissions, MockOrganization, @@ -7,7 +8,10 @@ import { MockPermissions, } from "testHelpers/entities"; import { withDashboardProvider } from "testHelpers/storybook"; -import { OrganizationSidebarView } from "./OrganizationSidebarView"; +import { + OrganizationSidebarView, + type OrganizationWithPermissions, +} from "./OrganizationSidebarView"; const meta: Meta = { title: "modules/management/OrganizationSidebarView", @@ -286,3 +290,114 @@ export const OrgsDisabled: Story = { showOrganizations: false, }, }; + +const commonPerms: AuthorizationResponse = { + editOrganization: true, + editMembers: true, + editGroups: true, + auditOrganization: true, +}; + +const activeOrganization: OrganizationWithPermissions = { + ...MockOrganization, + display_name: "Omega org", + name: "omega", + id: "1", + permissions: { + ...commonPerms, + }, +}; + +export const OrgsSortedAlphabetically: Story = { + args: { + activeOrganization, + permissions: { + ...MockPermissions, + createOrganization: true, + }, + organizations: [ + { + ...MockOrganization, + display_name: "Zeta Org", + id: "2", + name: "zeta", + permissions: commonPerms, + }, + { + ...MockOrganization, + display_name: "alpha Org", + id: "3", + name: "alpha", + permissions: commonPerms, + }, + activeOrganization, + ], + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button", { name: /Omega org/i })); + + // dropdown is not in #storybook-root so must query full document + const globalScreen = within(document.body); + + await waitFor(() => { + expect(globalScreen.queryByText("alpha Org")).toBeInTheDocument(); + expect(globalScreen.queryByText("Zeta Org")).toBeInTheDocument(); + }); + + const orgElements = globalScreen.getAllByRole("option"); + // filter out Create btn + const filteredElems = orgElements.slice(0, 3); + + const orgNames = filteredElems.map( + // handling fuzzy matching + (el) => el.textContent?.replace(/^[A-Z]/, "").trim() || "", + ); + + // active name first + expect(orgNames).toEqual(["Omega org", "alpha Org", "Zeta Org"]); + }, +}; + +export const SearchForOrg: Story = { + args: { + activeOrganization, + permissions: MockPermissions, + organizations: [ + { + ...MockOrganization, + display_name: "Zeta Org", + id: "2", + name: "zeta", + permissions: commonPerms, + }, + { + ...MockOrganization, + display_name: "alpha Org", + id: "3", + name: "fish", + permissions: commonPerms, + }, + activeOrganization, + ], + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button", { name: /Omega org/i })); + + // dropdown is not in #storybook-root so must query full document + const globalScreen = within(document.body); + const searchInput = + await globalScreen.getByPlaceholderText("Find organization"); + + await userEvent.type(searchInput, "ALPHA"); + + const filteredResult = await globalScreen.findByText("alpha Org"); + expect(filteredResult).toBeInTheDocument(); + + // Omega org remains visible as the default org + await waitFor(() => { + expect(globalScreen.queryByText("Zeta Org")).not.toBeInTheDocument(); + }); + }, +}; diff --git a/site/src/modules/management/OrganizationSidebarView.tsx b/site/src/modules/management/OrganizationSidebarView.tsx index 8d913edf87df3..b618c4f72bd3d 100644 --- a/site/src/modules/management/OrganizationSidebarView.tsx +++ b/site/src/modules/management/OrganizationSidebarView.tsx @@ -3,9 +3,12 @@ import { Avatar } from "components/Avatar/Avatar"; import { Button } from "components/Button/Button"; import { Command, + CommandEmpty, CommandGroup, + CommandInput, CommandItem, CommandList, + CommandSeparator, } from "components/Command/Command"; import { Loader } from "components/Loader/Loader"; import { @@ -88,11 +91,15 @@ const OrganizationsSettingsNavigation: FC< return ; } - // Sort organizations to put active organization first - const sortedOrganizations = [ - activeOrganization, - ...organizations.filter((org) => org.id !== activeOrganization.id), - ]; + const sortedOrganizations = [...organizations].sort((a, b) => { + // active org first + if (a.id === activeOrganization.id) return -1; + if (b.id === activeOrganization.id) return 1; + + return a.display_name + .toLowerCase() + .localeCompare(b.display_name.toLowerCase()); + }); const [isPopoverOpen, setIsPopoverOpen] = useState(false); const navigate = useNavigate(); @@ -123,14 +130,16 @@ const OrganizationsSettingsNavigation: FC< + + No organization found. {sortedOrganizations.length > 1 && (
{sortedOrganizations.map((organization) => ( { setIsPopoverOpen(false); navigate(urlForSubpage(organization.name)); @@ -158,11 +167,11 @@ const OrganizationsSettingsNavigation: FC< ))}
)} - {permissions.createOrganization && ( - <> - {organizations.length > 1 && ( -
- )} +
+ {permissions.createOrganization && ( + <> + {organizations.length > 1 && } + { @@ -174,9 +183,9 @@ const OrganizationsSettingsNavigation: FC< > Create Organization - - )} - + + + )}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy