1- import { ButtonGroup } from "@components/ButtonGroup" ;
1+ import ButtonGroup from "@components/ButtonGroup" ;
22import { DataTable } from "@components/table/DataTable" ;
33import DataTableHeader from "@components/table/DataTableHeader" ;
4- import DataTableRowsPerPage from "@components/table/DataTableRowsPerPage" ;
5- import GroupNameCell from "@components/ui/GroupNameCell" ;
4+ import { DataTableRowsPerPage } from "@components/table/DataTableRowsPerPage" ;
65import NoResults from "@components/ui/NoResults" ;
7- import { useGroups } from "@/contexts/GroupsProvider" ;
8- import { Group } from "@/interfaces/Group" ;
9- import { useDataTable } from "@/modules/common/hooks/useDataTable" ;
6+ import { ColumnDef , SortingState } from "@tanstack/react-table" ;
7+ import { FolderGit2Icon , Layers3Icon } from "lucide-react" ;
8+ import { usePathname } from "next/navigation" ;
9+ import React from "react" ;
10+ import AccessControlIcon from "@/assets/icons/AccessControlIcon" ;
11+ import DNSIcon from "@/assets/icons/DNSIcon" ;
12+ import NetworkRoutesIcon from "@/assets/icons/NetworkRoutesIcon" ;
13+ import PeerIcon from "@/assets/icons/PeerIcon" ;
14+ import SetupKeysIcon from "@/assets/icons/SetupKeysIcon" ;
15+ import TeamIcon from "@/assets/icons/TeamIcon" ;
16+ import { useLocalStorage } from "@/hooks/useLocalStorage" ;
17+ import GroupsActionCell from "@/modules/settings/GroupsActionCell" ;
1018import GroupsCountCell from "@/modules/settings/GroupsCountCell" ;
1119import GroupsNameCell from "@/modules/settings/GroupsNameCell" ;
1220import useGroupsUsage , { GroupUsage } from "@/modules/settings/useGroupsUsage" ;
1321
1422// Peers, Access Controls, DNS, Routes, Setup Keys, Users
15-
16- const GroupsTableColumns : ColumnDef < Group > [ ] = [
23+ export const GroupsTableColumns : ColumnDef < GroupUsage > [ ] = [
1724 {
1825 accessorKey : "name" ,
1926 header : ( { column } ) => {
2027 return < DataTableHeader column = { column } > Name</ DataTableHeader > ;
2128 } ,
22- cell : GroupsNameCell ,
29+ cell : ( { row } ) => {
30+ const in_use = ! ! row . getValue ( "in_use" ) ;
31+ return (
32+ < GroupsNameCell
33+ active = { in_use }
34+ group = { {
35+ id : row . original ?. id ,
36+ issued : row . original ?. issued ,
37+ name : row . original ?. name ,
38+ } }
39+ />
40+ ) ;
41+ } ,
42+ sortingFn : "text" ,
43+ } ,
44+ {
45+ accessorKey : "setup_keys_count" ,
46+ header : ( { column } ) => {
47+ return (
48+ < DataTableHeader
49+ column = { column }
50+ center = { true }
51+ tooltip = { < div className = { "text-sm normal-case" } > Setup Keys</ div > }
52+ >
53+ < SetupKeysIcon size = { 12 } />
54+ </ DataTableHeader >
55+ ) ;
56+ } ,
57+ cell : ( { row } ) => (
58+ < GroupsCountCell
59+ icon = { < SetupKeysIcon size = { 10 } /> }
60+ groupName = { row . original . name }
61+ text = { "Setup Key(s)" }
62+ count = { row . original . setup_keys_count }
63+ />
64+ ) ,
2365 } ,
2466 {
2567 accessorKey : "peers_count" ,
2668 header : ( { column } ) => {
27- return < DataTableHeader column = { column } > Peers</ DataTableHeader > ;
69+ return (
70+ < DataTableHeader
71+ column = { column }
72+ tooltip = { < div className = { "text-sm normal-case" } > Peers</ div > }
73+ >
74+ < PeerIcon size = { 12 } />
75+ </ DataTableHeader >
76+ ) ;
2877 } ,
29- cell : ( { row } ) => row . original . peers_count ,
78+ cell : ( { row } ) => (
79+ < GroupsCountCell
80+ icon = { < PeerIcon size = { 10 } /> }
81+ groupName = { row . original . name }
82+ text = { "Peer(s)" }
83+ count = { row . original . peers_count }
84+ />
85+ ) ,
3086 } ,
3187 {
32- accessorKey : "access_control_rules_count " ,
88+ accessorKey : "nameservers_count " ,
3389 header : ( { column } ) => {
3490 return (
35- < DataTableHeader column = { column } > Access Controls</ DataTableHeader >
91+ < DataTableHeader
92+ column = { column }
93+ tooltip = { < div className = { "text-sm normal-case" } > DNS</ div > }
94+ >
95+ < DNSIcon size = { 12 } />
96+ </ DataTableHeader >
3697 ) ;
3798 } ,
38- cell : ( { row } ) => < GroupsCountCell row = { row } type = { "access-control" } /> ,
99+ cell : ( { row } ) => (
100+ < GroupsCountCell
101+ icon = { < DNSIcon size = { 10 } /> }
102+ groupName = { row . original . name }
103+ text = { "DNS" }
104+ count = { row . original . nameservers_count }
105+ />
106+ ) ,
39107 } ,
40108 {
41- accessorKey : "dns_settings_count " ,
109+ accessorKey : "policies_count " ,
42110 header : ( { column } ) => {
43- return < DataTableHeader column = { column } > DNS</ DataTableHeader > ;
111+ return (
112+ < DataTableHeader
113+ column = { column }
114+ tooltip = { < div className = { "text-sm normal-case" } > Access Controls</ div > }
115+ >
116+ < AccessControlIcon size = { 12 } />
117+ </ DataTableHeader >
118+ ) ;
44119 } ,
45- cell : ( { row } ) => < GroupsCountCell row = { row } type = { "dns" } /> ,
120+ cell : ( { row } ) => (
121+ < GroupsCountCell
122+ icon = { < AccessControlIcon size = { 10 } /> }
123+ groupName = { row . original . name }
124+ text = { "Access Control(s)" }
125+ count = { row . original . policies_count }
126+ />
127+ ) ,
46128 } ,
47129 {
48130 accessorKey : "routes_count" ,
49131 header : ( { column } ) => {
50- return < DataTableHeader column = { column } > Routes</ DataTableHeader > ;
132+ return (
133+ < DataTableHeader
134+ column = { column }
135+ tooltip = { < div className = { "text-sm normal-case" } > Network Routes</ div > }
136+ >
137+ < NetworkRoutesIcon size = { 12 } />
138+ </ DataTableHeader >
139+ ) ;
51140 } ,
52- cell : ( { row } ) => < GroupsCountCell row = { row } type = { "route" } /> ,
141+ cell : ( { row } ) => (
142+ < GroupsCountCell
143+ icon = { < NetworkRoutesIcon size = { 10 } /> }
144+ groupName = { row . original . name }
145+ text = { "Network Route(s)" }
146+ count = { row . original . routes_count }
147+ />
148+ ) ,
53149 } ,
54150 {
55- accessorKey : "setup_keys_count " ,
151+ accessorKey : "resources_count " ,
56152 header : ( { column } ) => {
57- return < DataTableHeader column = { column } > Setup Keys</ DataTableHeader > ;
153+ return (
154+ < DataTableHeader
155+ column = { column }
156+ tooltip = {
157+ < div className = { "text-sm normal-case" } > Network Resources</ div >
158+ }
159+ >
160+ < Layers3Icon size = { 12 } />
161+ </ DataTableHeader >
162+ ) ;
58163 } ,
59- cell : ( { row } ) => < GroupsCountCell row = { row } type = { "setup-key" } /> ,
164+ cell : ( { row } ) => (
165+ < GroupsCountCell
166+ icon = { < Layers3Icon size = { 10 } /> }
167+ groupName = { row . original . name }
168+ text = { "Network Resource(s)" }
169+ count = { row . original . resources_count }
170+ />
171+ ) ,
60172 } ,
61173 {
62174 accessorKey : "users_count" ,
63175 header : ( { column } ) => {
64- return < DataTableHeader column = { column } > Users</ DataTableHeader > ;
176+ return (
177+ < DataTableHeader
178+ column = { column }
179+ tooltip = { < div className = { "text-sm normal-case" } > Users</ div > }
180+ >
181+ < TeamIcon size = { 12 } />
182+ </ DataTableHeader >
183+ ) ;
65184 } ,
66- cell : ( { row } ) => < GroupsCountCell row = { row } type = { "user" } /> ,
185+ cell : ( { row } ) => (
186+ < GroupsCountCell
187+ icon = { < TeamIcon size = { 10 } /> }
188+ groupName = { row . original . name }
189+ text = { "User(s)" }
190+ count = { row . original . users_count }
191+ />
192+ ) ,
67193 } ,
68194 {
69195 id : "in_use" ,
70- accessorFn : ( row ) => row . in_use ,
71- filterFn : "equals" ,
196+ header : ( { column } ) => {
197+ return < DataTableHeader column = { column } > In Use</ DataTableHeader > ;
198+ } ,
199+ sortingFn : "basic" ,
200+ accessorFn : ( row ) => {
201+ return (
202+ row . peers_count > 0 ||
203+ row . nameservers_count > 0 ||
204+ row . policies_count > 0 ||
205+ row . routes_count > 0 ||
206+ row . setup_keys_count > 0 ||
207+ row . users_count > 0 ||
208+ row . resources_count > 0
209+ ) ;
210+ } ,
211+ } ,
212+ {
213+ accessorKey : "id" ,
214+ header : "" ,
215+ cell : ( { row } ) => (
216+ < GroupsActionCell group = { row . original } in_use = { row . getValue ( "in_use" ) } />
217+ ) ,
72218 } ,
73219] ;
74220
75- export const GroupsTable = ( { headingTarget } : { headingTarget : any } ) => {
76- const { groups, createGroup, updateGroup, deleteGroups, renameGroup } =
77- useGroups ( ) ;
78- const { groupUsage } = useGroupsUsage ( ) ;
221+ type Props = {
222+ headingTarget ?: HTMLHeadingElement | null ;
223+ } ;
79224
80- const groupsWithUsage = useMemo ( ( ) => {
81- return (
82- groups ?. map ( ( group ) => {
83- const usage = groupUsage ?. find ( ( g ) => g . id === group . id ) ;
84- return {
85- ...group ,
86- ...usage ,
87- in_use : usage ? Object . values ( usage ) . some ( ( v ) => v > 0 ) : false ,
88- } as GroupUsage & Group ;
89- } ) || [ ]
90- ) ;
91- } , [ groups , groupUsage ] ) ;
225+ export default function GroupsTable ( { headingTarget } : Readonly < Props > ) {
226+ const groups = useGroupsUsage ( ) ;
227+ const path = usePathname ( ) ;
92228
93- const {
94- table,
95- sorting,
96- setSorting,
97- globalFilter,
98- setGlobalFilter,
99- columnFilters,
100- setColumnFilters,
101- } = useDataTable ( { data : groupsWithUsage , columns : GroupsTableColumns } ) ;
229+ // Default sorting state of the table
230+ const [ sorting , setSorting ] = useLocalStorage < SortingState > (
231+ "netbird-table-sort" + path ,
232+ [
233+ {
234+ id : "name" ,
235+ desc : true ,
236+ } ,
237+ ] ,
238+ ) ;
102239
103240 return (
104241 < >
@@ -110,7 +247,7 @@ export const GroupsTable = ({ headingTarget }: { headingTarget: any }) => {
110247 sorting = { sorting }
111248 setSorting = { setSorting }
112249 columns = { GroupsTableColumns }
113- data = { groupsWithUsage }
250+ data = { groups }
114251 searchPlaceholder = { "Search group..." }
115252 columnVisibility = { {
116253 in_use : false ,
@@ -170,13 +307,12 @@ export const GroupsTable = ({ headingTarget }: { headingTarget: any }) => {
170307 < div className = { "bg-white dark:bg-nb-gray-950 overflow-hidden" } >
171308 < NoResults
172309 className = { "py-3" }
173- title = { "Seems like you don't have any groups" }
174- description = {
175- "You can create a new group by clicking the button below."
176- }
310+ title = { "No groups" }
311+ description = { "You don't have any groups created yet." }
312+ icon = { < FolderGit2Icon size = { 20 } className = { "fill-nb-gray-300" } /> }
177313 />
178314 </ div >
179315 ) }
180316 </ >
181317 ) ;
182- } ;
318+ }
0 commit comments