@@ -14,13 +14,15 @@ import {
1414 ColumnDef ,
1515 RowSelectionState ,
1616 SortingState ,
17+ VisibilityState ,
1718} from "@tanstack/react-table" ;
1819import { uniqBy } from "lodash" ;
1920import { ExternalLinkIcon } from "lucide-react" ;
2021import { usePathname } from "next/navigation" ;
2122import React , { useState } from "react" ;
2223import { useSWRConfig } from "swr" ;
2324import PeerIcon from "@/assets/icons/PeerIcon" ;
25+ import DataTableToolTipButton from "@/components/table/DataTableToolTipButton" ;
2426import PeerProvider from "@/contexts/PeerProvider" ;
2527import { useLoggedInUser } from "@/contexts/UsersProvider" ;
2628import { useLocalStorage } from "@/hooks/useLocalStorage" ;
@@ -40,6 +42,7 @@ import PeerVersionCell from "@/modules/peers/PeerVersionCell";
4042const PeersTableColumns : ColumnDef < Peer > [ ] = [
4143 {
4244 id : "select" ,
45+ enableHiding : false ,
4346 header : ( { table } ) => (
4447 < div className = { "min-w-[20px] max-w-[20px]" } >
4548 < Checkbox
@@ -60,10 +63,10 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
6063 </ div >
6164 ) ,
6265 enableSorting : false ,
63- enableHiding : false ,
6466 } ,
6567 {
6668 accessorKey : "name" ,
69+ enableHiding : false ,
6770 header : ( { column } ) => {
6871 return < DataTableHeader column = { column } > Name</ DataTableHeader > ;
6972 } ,
@@ -82,6 +85,7 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
8285 accessorFn : ( peer ) => peer . connected ,
8386 } ,
8487 {
88+ id : "ip" ,
8589 accessorKey : "ip" ,
8690 sortingFn : "text" ,
8791 } ,
@@ -94,18 +98,30 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
9498 accessorFn : ( peer ) => ( peer . user ? peer . user ?. email : "Unknown" ) ,
9599 } ,
96100 {
101+ id : "dns_label" ,
102+ enableHiding : false ,
97103 accessorKey : "dns_label" ,
98104 header : ( { column } ) => {
99105 return < DataTableHeader column = { column } > Address</ DataTableHeader > ;
100106 } ,
101107 cell : ( { row } ) => < PeerAddressCell peer = { row . original } /> ,
102108 } ,
103109 {
110+ id : "group_name_strings" ,
104111 accessorKey : "group_name_strings" ,
105112 accessorFn : ( peer ) => peer . groups ?. map ( ( g ) => g ?. name || "" ) . join ( ", " ) ,
106113 sortingFn : "text" ,
107114 } ,
108115 {
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" ,
109125 accessorKey : "group_names" ,
110126 accessorFn : ( peer ) => peer . groups ?. map ( ( g ) => g ?. name || "" ) ,
111127 sortingFn : "text" ,
@@ -124,6 +140,7 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
124140 ) ,
125141 } ,
126142 {
143+ id : "last_seen" ,
127144 accessorKey : "last_seen" ,
128145 header : ( { column } ) => {
129146 return < DataTableHeader column = { column } > Last seen</ DataTableHeader > ;
@@ -132,13 +149,23 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
132149 cell : ( { row } ) => < PeerLastSeenCell peer = { row . original } /> ,
133150 } ,
134151 {
152+ id : "os" ,
135153 accessorKey : "os" ,
136154 header : ( { column } ) => {
137155 return < DataTableHeader column = { column } > OS</ DataTableHeader > ;
138156 } ,
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" ,
140166 } ,
141167 {
168+ id : "version" ,
142169 accessorKey : "version" ,
143170 header : ( { column } ) => {
144171 return < DataTableHeader column = { column } > Version</ DataTableHeader > ;
@@ -165,8 +192,10 @@ const PeersTableColumns: ColumnDef<Peer>[] = [
165192 } ,
166193 {
167194 id : "actions" ,
195+ enableHiding : false ,
168196 accessorKey : "id" ,
169197 header : "" ,
198+
170199 cell : ( { row } ) => (
171200 < PeerProvider peer = { row . original } >
172201 < PeerActionCell />
@@ -213,6 +242,25 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
213242
214243 const [ selectedRows , setSelectedRows ] = useState < RowSelectionState > ( { } ) ;
215244
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+
216264 const resetSelectedRows = ( ) => {
217265 if ( Object . keys ( selectedRows ) . length > 0 ) {
218266 setSelectedRows ( { } ) ;
@@ -226,28 +274,19 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
226274 onCanceled = { ( ) => setSelectedRows ( { } ) }
227275 />
228276 < DataTable
277+ keepStateInLocalStorage = { true }
229278 headingTarget = { headingTarget }
230279 rowSelection = { selectedRows }
231280 setRowSelection = { setSelectedRows }
232281 useRowId = { true }
233282 text = { "Peers" }
234283 sorting = { sorting }
235284 setSorting = { setSorting }
285+ setColumnVisibility = { setColumnVisibility }
236286 columns = { PeersTableColumns }
237287 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 }
251290 isLoading = { isLoading }
252291 getStartedCard = {
253292 < GetStartedTest
@@ -393,7 +432,7 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
393432 table . setPageIndex ( 0 ) ;
394433 let current =
395434 table . getColumn ( "approval_required" ) ?. getFilterValue ( ) ===
396- undefined
435+ undefined
397436 ? true
398437 : undefined ;
399438
@@ -412,7 +451,7 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
412451 } }
413452 variant = {
414453 table . getColumn ( "approval_required" ) ?. getFilterValue ( ) ===
415- true
454+ true
416455 ? "tertiary"
417456 : "secondary"
418457 }
@@ -446,6 +485,29 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) {
446485 />
447486 ) }
448487
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+
449511 < DataTableRefreshButton
450512 isDisabled = { peers ?. length == 0 }
451513 onClick = { ( ) => {
0 commit comments