@@ -14,13 +14,15 @@ import {
14
14
ColumnDef ,
15
15
RowSelectionState ,
16
16
SortingState ,
17
+ VisibilityState ,
17
18
} from "@tanstack/react-table" ;
18
19
import { uniqBy } from "lodash" ;
19
20
import { ExternalLinkIcon } from "lucide-react" ;
20
21
import { usePathname } from "next/navigation" ;
21
22
import React , { useState } from "react" ;
22
23
import { useSWRConfig } from "swr" ;
23
24
import PeerIcon from "@/assets/icons/PeerIcon" ;
25
+ import DataTableToolTipButton from "@/components/table/DataTableToolTipButton" ;
24
26
import PeerProvider from "@/contexts/PeerProvider" ;
25
27
import { useLoggedInUser } from "@/contexts/UsersProvider" ;
26
28
import { useLocalStorage } from "@/hooks/useLocalStorage" ;
@@ -40,6 +42,7 @@ import PeerVersionCell from "@/modules/peers/PeerVersionCell";
40
42
const PeersTableColumns : ColumnDef < Peer > [ ] = [
41
43
{
42
44
id : "select" ,
45
+ enableHiding : false ,
43
46
header : ( { table } ) => (
44
47
< div className = { "min-w-[20px] max-w-[20px]" } >
45
48
< Checkbox
@@ -60,10 +63,10 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
60
63
</ div >
61
64
) ,
62
65
enableSorting : false ,
63
- enableHiding : false ,
64
66
} ,
65
67
{
66
68
accessorKey : "name" ,
69
+ enableHiding : false ,
67
70
header : ( { column } ) => {
68
71
return < DataTableHeader column = { column } > Name</ DataTableHeader > ;
69
72
} ,
@@ -82,6 +85,7 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
82
85
accessorFn : ( peer ) => peer . connected ,
83
86
} ,
84
87
{
88
+ id : "ip" ,
85
89
accessorKey : "ip" ,
86
90
sortingFn : "text" ,
87
91
} ,
@@ -94,18 +98,30 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
94
98
accessorFn : ( peer ) => ( peer . user ? peer . user ?. email : "Unknown" ) ,
95
99
} ,
96
100
{
101
+ id : "dns_label" ,
102
+ enableHiding : false ,
97
103
accessorKey : "dns_label" ,
98
104
header : ( { column } ) => {
99
105
return < DataTableHeader column = { column } > Address</ DataTableHeader > ;
100
106
} ,
101
107
cell : ( { row } ) => < PeerAddressCell peer = { row . original } /> ,
102
108
} ,
103
109
{
110
+ id : "group_name_strings" ,
104
111
accessorKey : "group_name_strings" ,
105
112
accessorFn : ( peer ) => peer . groups ?. map ( ( g ) => g ?. name || "" ) . join ( ", " ) ,
106
113
sortingFn : "text" ,
107
114
} ,
108
115
{
116
+ // used for exact group matching
117
+ id : "exact_group_name_strings" ,
118
+ accessorKey : "exact_group_name_strings" ,
119
+ accessorFn : ( peer ) => peer . groups ?. map ( ( g ) => g ?. name || "" ) . join ( "|" ) ,
120
+ sortingFn : "text" ,
121
+ filterFn : "equals"
122
+ } ,
123
+ {
124
+ id : "group_names" ,
109
125
accessorKey : "group_names" ,
110
126
accessorFn : ( peer ) => peer . groups ?. map ( ( g ) => g ?. name || "" ) ,
111
127
sortingFn : "text" ,
@@ -124,6 +140,7 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
124
140
) ,
125
141
} ,
126
142
{
143
+ id : "last_seen" ,
127
144
accessorKey : "last_seen" ,
128
145
header : ( { column } ) => {
129
146
return < DataTableHeader column = { column } > Last seen</ DataTableHeader > ;
@@ -132,13 +149,23 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
132
149
cell : ( { row } ) => < PeerLastSeenCell peer = { row . original } /> ,
133
150
} ,
134
151
{
152
+ id : "os" ,
135
153
accessorKey : "os" ,
136
154
header : ( { column } ) => {
137
155
return < DataTableHeader column = { column } > OS</ DataTableHeader > ;
138
156
} ,
139
- cell : ( { row } ) => < PeerOSCell os = { row . original . os } /> ,
157
+ cell : ( { row } ) => < PeerOSCell os = { row . original . os } serial = { row . original . serial_number } /> ,
158
+ } ,
159
+ {
160
+ id : "serial" ,
161
+ header : ( { column } ) => {
162
+ return < DataTableHeader column = { column } > Serial number</ DataTableHeader > ;
163
+ } ,
164
+ accessorFn : ( peer ) => peer . serial_number ,
165
+ sortingFn : "text" ,
140
166
} ,
141
167
{
168
+ id : "version" ,
142
169
accessorKey : "version" ,
143
170
header : ( { column } ) => {
144
171
return < DataTableHeader column = { column } > Version</ DataTableHeader > ;
@@ -165,8 +192,10 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
165
192
} ,
166
193
{
167
194
id : "actions" ,
195
+ enableHiding : false ,
168
196
accessorKey : "id" ,
169
197
header : "" ,
198
+
170
199
cell : ( { row } ) => (
171
200
< PeerProvider peer = { row . original } >
172
201
< PeerActionCell />
@@ -213,6 +242,25 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
213
242
214
243
const [ selectedRows , setSelectedRows ] = useState < RowSelectionState > ( { } ) ;
215
244
245
+ const colVisibility : VisibilityState = {
246
+ select : ! isUser ,
247
+ actions : ! isUser ,
248
+ groups : ! isUser ,
249
+ connected : false ,
250
+ approval_required : false ,
251
+
252
+ // hidden, but usefull for lookup
253
+ serial : false ,
254
+ group_name_strings : false ,
255
+ exact_group_name_strings : false ,
256
+ group_names : false ,
257
+ ip : false ,
258
+ user_name : false ,
259
+ user_email : false ,
260
+ }
261
+
262
+ const [ resultingColumnVisibility , setColumnVisibility ] = useState ( colVisibility ) ;
263
+
216
264
const resetSelectedRows = ( ) => {
217
265
if ( Object . keys ( selectedRows ) . length > 0 ) {
218
266
setSelectedRows ( { } ) ;
@@ -226,28 +274,19 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
226
274
onCanceled = { ( ) => setSelectedRows ( { } ) }
227
275
/>
228
276
< DataTable
277
+ keepStateInLocalStorage = { true }
229
278
headingTarget = { headingTarget }
230
279
rowSelection = { selectedRows }
231
280
setRowSelection = { setSelectedRows }
232
281
useRowId = { true }
233
282
text = { "Peers" }
234
283
sorting = { sorting }
235
284
setSorting = { setSorting }
285
+ setColumnVisibility = { setColumnVisibility }
236
286
columns = { PeersTableColumns }
237
287
data = { peers }
238
- searchPlaceholder = { "Search by name, IP, owner or group..." }
239
- columnVisibility = { {
240
- select : ! isUser ,
241
- connected : false ,
242
- approval_required : false ,
243
- group_name_strings : false ,
244
- group_names : false ,
245
- ip : false ,
246
- user_name : false ,
247
- user_email : false ,
248
- actions : ! isUser ,
249
- groups : ! isUser ,
250
- } }
288
+ searchPlaceholder = { "Search by name, IP, Serial, owner or group..." }
289
+ columnVisibility = { resultingColumnVisibility }
251
290
isLoading = { isLoading }
252
291
getStartedCard = {
253
292
< GetStartedTest
@@ -393,7 +432,7 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
393
432
table . setPageIndex ( 0 ) ;
394
433
let current =
395
434
table . getColumn ( "approval_required" ) ?. getFilterValue ( ) ===
396
- undefined
435
+ undefined
397
436
? true
398
437
: undefined ;
399
438
@@ -412,7 +451,7 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
412
451
} }
413
452
variant = {
414
453
table . getColumn ( "approval_required" ) ?. getFilterValue ( ) ===
415
- true
454
+ true
416
455
? "tertiary"
417
456
: "secondary"
418
457
}
@@ -446,6 +485,29 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
446
485
/>
447
486
) }
448
487
488
+ < DataTableToolTipButton
489
+ disabled = { peers ?. length == 0 }
490
+ onClick = { ( ) => {
491
+ table . setPageIndex ( 0 ) ;
492
+ if ( table . getColumn ( "exact_group_name_strings" ) ?. getFilterValue ( ) !== undefined ) {
493
+ table . resetColumnFilters ( ) ;
494
+ return ;
495
+ }
496
+ table . setColumnFilters ( [
497
+ {
498
+ id : "exact_group_name_strings" ,
499
+ value : "All"
500
+ }
501
+ ] )
502
+ } }
503
+ variant = { table . getColumn ( "exact_group_name_strings" ) ?. getFilterValue ( ) !== undefined
504
+ ? "tertiary"
505
+ : "secondary" }
506
+ title = "filter peers assigned to the uniq group: 'All'"
507
+ >
508
+ All group only
509
+ </ DataTableToolTipButton >
510
+
449
511
< DataTableRefreshButton
450
512
isDisabled = { peers ?. length == 0 }
451
513
onClick = { ( ) => {
0 commit comments