@@ -22,28 +22,45 @@ import { Group } from "@/interfaces/Group";
2222
2323interface MultiSelectProps {
2424 values : string [ ] ;
25- onChange : ( items : string [ ] ) => void ;
25+ exclusiveValue ?: string ;
26+ onChange : ( anyOfValues : string [ ] , exclusiveValue ?: string ) => void ;
2627 disabled ?: boolean ;
2728 popoverWidth ?: "auto" | number ;
2829 groups : Group [ ] | undefined ;
30+ unassignedCount ?: number ;
31+ defaultGroupName ?: string ;
2932}
3033export function GroupSelector ( {
3134 onChange,
3235 values,
36+ exclusiveValue,
3337 disabled = false ,
3438 popoverWidth = 400 ,
3539 groups,
40+ unassignedCount,
41+ defaultGroupName = "All" , //defined as a property, no clue if this value may change in the future
3642} : MultiSelectProps ) {
3743 const searchRef = React . useRef < HTMLInputElement > ( null ) ;
3844 const [ inputRef , { width } ] = useElementSize < HTMLButtonElement > ( ) ;
3945 const [ search , setSearch ] = useState ( "" ) ;
4046
41- const toggle = ( code : string ) => {
47+ const toggleAnyOf = ( code : string ) => {
4248 const isSelected = values . find ( ( c ) => c == code ) != undefined ;
4349 if ( isSelected ) {
44- onChange && onChange ( values . filter ( ( c ) => c != code ) ) ;
50+ onChange && onChange ( values . filter ( ( c ) => c != code ) , undefined ) ;
4551 } else {
46- onChange && onChange ( [ ...values , code ] ) ;
52+ onChange && onChange ( [ ...values , code ] , undefined ) ;
53+ setSearch ( "" ) ;
54+ }
55+ } ;
56+
57+ const toggleExclusive = ( code : string ) => {
58+ const isSelected = exclusiveValue == code ;
59+ if ( isSelected ) {
60+ onChange && onChange ( [ ] , undefined ) ;
61+ setSearch ( "" ) ;
62+ } else {
63+ onChange && onChange ( [ ] , code ) ;
4764 setSearch ( "" ) ;
4865 }
4966 } ;
@@ -63,14 +80,16 @@ export function GroupSelector({
6380 } }
6481 >
6582 < PopoverTrigger asChild = { true } >
66- < Button variant = { "secondary" } disabled = { disabled } ref = { inputRef } >
83+ < Button variant = { "secondary" } disabled = { disabled } ref = { inputRef } className = "w-[200px] justify-between" >
6784 < FolderGit2 size = { 16 } className = { "shrink-0" } />
6885 < div className = { "w-full flex justify-between" } >
69- { values . length > 0 ? (
70- < div > { values . length } Group(s)</ div >
71- ) : (
72- "All Groups"
73- ) }
86+ {
87+ exclusiveValue != undefined
88+ ? ( "Unassigned peers" )
89+ : values . length > 0
90+ ? ( `${ values . length } Group(s)` )
91+ : ( "All Groups" )
92+ }
7493 < div className = { "pl-2" } >
7594 < ChevronsUpDown size = { 18 } className = { "shrink-0" } />
7695 </ div >
@@ -133,7 +152,6 @@ export function GroupSelector({
133152 </ div >
134153 </ div >
135154 </ div >
136-
137155 < ScrollArea
138156 className = {
139157 "max-h-[380px] overflow-y-auto flex flex-col gap-1 pl-2 py-2 pr-3"
@@ -142,7 +160,48 @@ export function GroupSelector({
142160 < CommandGroup >
143161 < div className = { "" } >
144162 < div className = { "grid grid-cols-1 gap-1" } >
145- { orderBy ( groups , "name" ) ?. map ( ( item ) => {
163+ < CommandItem
164+ className = { "p-1" }
165+ onSelect = { ( ) => {
166+ toggleExclusive ( defaultGroupName ) ;
167+ searchRef . current ?. focus ( ) ;
168+ } }
169+ onClick = { ( e ) => e . preventDefault ( ) }
170+ >
171+ < div
172+ className = {
173+ "text-neutral-500 dark:text-nb-gray-300 font-medium flex items-center gap-3 py-1 px-1 w-full"
174+ }
175+ >
176+ < Checkbox checked = { exclusiveValue == defaultGroupName } />
177+ < div
178+ className = {
179+ "flex justify-between items-center w-full"
180+ }
181+ >
182+ < div
183+ className = {
184+ "flex items-center gap-2 whitespace-nowrap text-sm"
185+ }
186+ >
187+ < FolderGit2 size = { 13 } className = { "shrink-0" } />
188+ < TextWithTooltip text = { "Unassigned peers" } />
189+ </ div >
190+ < div
191+ className = {
192+ "flex items-center gap-2 text-xs text-nb-gray-200/60"
193+ }
194+ >
195+ < MonitorSmartphoneIcon size = { 13 } />
196+ { unassignedCount } Peer(s)
197+ </ div >
198+ </ div >
199+ </ div >
200+ </ CommandItem >
201+ < hr />
202+ { orderBy ( groups , "name" )
203+ ?. filter ( ( group ) => group . name != defaultGroupName ) // Ignore default group
204+ ?. map ( ( item ) => {
146205 const value = item ?. name || "" ;
147206 if ( value === "" ) return null ;
148207 const isSelected =
@@ -154,7 +213,7 @@ export function GroupSelector({
154213 value = { value }
155214 className = { "p-1" }
156215 onSelect = { ( ) => {
157- toggle ( value ) ;
216+ toggleAnyOf ( value ) ;
158217 searchRef . current ?. focus ( ) ;
159218 } }
160219 onClick = { ( e ) => e . preventDefault ( ) }
0 commit comments