@@ -22,28 +22,45 @@ import { Group } from "@/interfaces/Group";
22
22
23
23
interface MultiSelectProps {
24
24
values : string [ ] ;
25
- onChange : ( items : string [ ] ) => void ;
25
+ exclusiveValue ?: string ;
26
+ onChange : ( anyOfValues : string [ ] , exclusiveValue ?: string ) => void ;
26
27
disabled ?: boolean ;
27
28
popoverWidth ?: "auto" | number ;
28
29
groups : Group [ ] | undefined ;
30
+ unassignedCount ?: number ;
31
+ defaultGroupName ?: string ;
29
32
}
30
33
export function GroupSelector ( {
31
34
onChange,
32
35
values,
36
+ exclusiveValue,
33
37
disabled = false ,
34
38
popoverWidth = 400 ,
35
39
groups,
40
+ unassignedCount,
41
+ defaultGroupName = "All" , //defined as a property, no clue if this value may change in the future
36
42
} : MultiSelectProps ) {
37
43
const searchRef = React . useRef < HTMLInputElement > ( null ) ;
38
44
const [ inputRef , { width } ] = useElementSize < HTMLButtonElement > ( ) ;
39
45
const [ search , setSearch ] = useState ( "" ) ;
40
46
41
- const toggle = ( code : string ) => {
47
+ const toggleAnyOf = ( code : string ) => {
42
48
const isSelected = values . find ( ( c ) => c == code ) != undefined ;
43
49
if ( isSelected ) {
44
- onChange && onChange ( values . filter ( ( c ) => c != code ) ) ;
50
+ onChange && onChange ( values . filter ( ( c ) => c != code ) , undefined ) ;
45
51
} 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 ) ;
47
64
setSearch ( "" ) ;
48
65
}
49
66
} ;
@@ -63,14 +80,16 @@ export function GroupSelector({
63
80
} }
64
81
>
65
82
< PopoverTrigger asChild = { true } >
66
- < Button variant = { "secondary" } disabled = { disabled } ref = { inputRef } >
83
+ < Button variant = { "secondary" } disabled = { disabled } ref = { inputRef } className = "w-[200px] justify-between" >
67
84
< FolderGit2 size = { 16 } className = { "shrink-0" } />
68
85
< 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
+ }
74
93
< div className = { "pl-2" } >
75
94
< ChevronsUpDown size = { 18 } className = { "shrink-0" } />
76
95
</ div >
@@ -133,7 +152,6 @@ export function GroupSelector({
133
152
</ div >
134
153
</ div >
135
154
</ div >
136
-
137
155
< ScrollArea
138
156
className = {
139
157
"max-h-[380px] overflow-y-auto flex flex-col gap-1 pl-2 py-2 pr-3"
@@ -142,7 +160,48 @@ export function GroupSelector({
142
160
< CommandGroup >
143
161
< div className = { "" } >
144
162
< 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 ) => {
146
205
const value = item ?. name || "" ;
147
206
if ( value === "" ) return null ;
148
207
const isSelected =
@@ -154,7 +213,7 @@ export function GroupSelector({
154
213
value = { value }
155
214
className = { "p-1" }
156
215
onSelect = { ( ) => {
157
- toggle ( value ) ;
216
+ toggleAnyOf ( value ) ;
158
217
searchRef . current ?. focus ( ) ;
159
218
} }
160
219
onClick = { ( e ) => e . preventDefault ( ) }
0 commit comments