Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2c6df5a

Browse files
fix: sort orgs alphabetically in dropdown (#16583)
resolvescoder/internal#352<img width="312" alt="Screenshot 2025-02-18 at 12 16 09 PM"src="https://github.com/user-attachments/assets/c7863bfd-c7cc-4fa6-be88-68a03cd19c1f"/>---------Co-authored-by: Jaayden Halko <jaayden.halko@gmail.com>
1 parent53f0007 commit2c6df5a

File tree

2 files changed

+139
-15
lines changed

2 files changed

+139
-15
lines changed

‎site/src/modules/management/OrganizationSidebarView.stories.tsx

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
importtype{Meta,StoryObj}from"@storybook/react";
22
import{expect,userEvent,waitFor,within}from"@storybook/test";
3+
importtype{AuthorizationResponse}from"api/typesGenerated";
34
import{
45
MockNoPermissions,
56
MockOrganization,
67
MockOrganization2,
78
MockPermissions,
89
}from"testHelpers/entities";
910
import{withDashboardProvider}from"testHelpers/storybook";
10-
import{OrganizationSidebarView}from"./OrganizationSidebarView";
11+
import{
12+
OrganizationSidebarView,
13+
typeOrganizationWithPermissions,
14+
}from"./OrganizationSidebarView";
1115

1216
constmeta:Meta<typeofOrganizationSidebarView>={
1317
title:"modules/management/OrganizationSidebarView",
@@ -286,3 +290,114 @@ export const OrgsDisabled: Story = {
286290
showOrganizations:false,
287291
},
288292
};
293+
294+
constcommonPerms:AuthorizationResponse={
295+
editOrganization:true,
296+
editMembers:true,
297+
editGroups:true,
298+
auditOrganization:true,
299+
};
300+
301+
constactiveOrganization:OrganizationWithPermissions={
302+
...MockOrganization,
303+
display_name:"Omega org",
304+
name:"omega",
305+
id:"1",
306+
permissions:{
307+
...commonPerms,
308+
},
309+
};
310+
311+
exportconstOrgsSortedAlphabetically:Story={
312+
args:{
313+
activeOrganization,
314+
permissions:{
315+
...MockPermissions,
316+
createOrganization:true,
317+
},
318+
organizations:[
319+
{
320+
...MockOrganization,
321+
display_name:"Zeta Org",
322+
id:"2",
323+
name:"zeta",
324+
permissions:commonPerms,
325+
},
326+
{
327+
...MockOrganization,
328+
display_name:"alpha Org",
329+
id:"3",
330+
name:"alpha",
331+
permissions:commonPerms,
332+
},
333+
activeOrganization,
334+
],
335+
},
336+
play:async({ canvasElement})=>{
337+
constcanvas=within(canvasElement);
338+
awaituserEvent.click(canvas.getByRole("button",{name:/Omegaorg/i}));
339+
340+
// dropdown is not in #storybook-root so must query full document
341+
constglobalScreen=within(document.body);
342+
343+
awaitwaitFor(()=>{
344+
expect(globalScreen.queryByText("alpha Org")).toBeInTheDocument();
345+
expect(globalScreen.queryByText("Zeta Org")).toBeInTheDocument();
346+
});
347+
348+
constorgElements=globalScreen.getAllByRole("option");
349+
// filter out Create btn
350+
constfilteredElems=orgElements.slice(0,3);
351+
352+
constorgNames=filteredElems.map(
353+
// handling fuzzy matching
354+
(el)=>el.textContent?.replace(/^[A-Z]/,"").trim()||"",
355+
);
356+
357+
// active name first
358+
expect(orgNames).toEqual(["Omega org","alpha Org","Zeta Org"]);
359+
},
360+
};
361+
362+
exportconstSearchForOrg:Story={
363+
args:{
364+
activeOrganization,
365+
permissions:MockPermissions,
366+
organizations:[
367+
{
368+
...MockOrganization,
369+
display_name:"Zeta Org",
370+
id:"2",
371+
name:"zeta",
372+
permissions:commonPerms,
373+
},
374+
{
375+
...MockOrganization,
376+
display_name:"alpha Org",
377+
id:"3",
378+
name:"fish",
379+
permissions:commonPerms,
380+
},
381+
activeOrganization,
382+
],
383+
},
384+
play:async({ canvasElement})=>{
385+
constcanvas=within(canvasElement);
386+
awaituserEvent.click(canvas.getByRole("button",{name:/Omegaorg/i}));
387+
388+
// dropdown is not in #storybook-root so must query full document
389+
constglobalScreen=within(document.body);
390+
constsearchInput=
391+
awaitglobalScreen.getByPlaceholderText("Find organization");
392+
393+
awaituserEvent.type(searchInput,"ALPHA");
394+
395+
constfilteredResult=awaitglobalScreen.findByText("alpha Org");
396+
expect(filteredResult).toBeInTheDocument();
397+
398+
// Omega org remains visible as the default org
399+
awaitwaitFor(()=>{
400+
expect(globalScreen.queryByText("Zeta Org")).not.toBeInTheDocument();
401+
});
402+
},
403+
};

‎site/src/modules/management/OrganizationSidebarView.tsx

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import { Avatar } from "components/Avatar/Avatar";
33
import{Button}from"components/Button/Button";
44
import{
55
Command,
6+
CommandEmpty,
67
CommandGroup,
8+
CommandInput,
79
CommandItem,
810
CommandList,
11+
CommandSeparator,
912
}from"components/Command/Command";
1013
import{Loader}from"components/Loader/Loader";
1114
import{
@@ -88,11 +91,15 @@ const OrganizationsSettingsNavigation: FC<
8891
return<Loader/>;
8992
}
9093

91-
// Sort organizations to put active organization first
92-
constsortedOrganizations=[
93-
activeOrganization,
94-
...organizations.filter((org)=>org.id!==activeOrganization.id),
95-
];
94+
constsortedOrganizations=[...organizations].sort((a,b)=>{
95+
// active org first
96+
if(a.id===activeOrganization.id)return-1;
97+
if(b.id===activeOrganization.id)return1;
98+
99+
returna.display_name
100+
.toLowerCase()
101+
.localeCompare(b.display_name.toLowerCase());
102+
});
96103

97104
const[isPopoverOpen,setIsPopoverOpen]=useState(false);
98105
constnavigate=useNavigate();
@@ -123,14 +130,16 @@ const OrganizationsSettingsNavigation: FC<
123130
</PopoverTrigger>
124131
<PopoverContentalign="start"className="w-60">
125132
<Commandloop>
133+
<CommandInputplaceholder="Find organization"/>
126134
<CommandList>
135+
<CommandEmpty>No organization found.</CommandEmpty>
127136
<CommandGroupclassName="pb-2">
128137
{sortedOrganizations.length>1&&(
129138
<divclassName="flex flex-col max-h-[260px] overflow-y-auto">
130139
{sortedOrganizations.map((organization)=>(
131140
<CommandItem
132141
key={organization.id}
133-
value={organization.name}
142+
value={`${organization.display_name}${organization.name}`}
134143
onSelect={()=>{
135144
setIsPopoverOpen(false);
136145
navigate(urlForSubpage(organization.name));
@@ -158,11 +167,11 @@ const OrganizationsSettingsNavigation: FC<
158167
))}
159168
</div>
160169
)}
161-
{permissions.createOrganization&&(
162-
<>
163-
{organizations.length>1&&(
164-
<hrclassName="h-px my-2 border-none bg-border -mx-2"/>
165-
)}
170+
</CommandGroup>
171+
{permissions.createOrganization&&(
172+
<>
173+
{organizations.length>1&&<CommandSeparator/>}
174+
<CommandGroup>
166175
<CommandItem
167176
className="flex justify-center data-[selected=true]:bg-transparent"
168177
onSelect={()=>{
@@ -174,9 +183,9 @@ const OrganizationsSettingsNavigation: FC<
174183
>
175184
<Plus/> Create Organization
176185
</CommandItem>
177-
</>
178-
)}
179-
</CommandGroup>
186+
</CommandGroup>
187+
</>
188+
)}
180189
</CommandList>
181190
</Command>
182191
</PopoverContent>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp