diff --git a/src/app/(dashboard)/peer/page.tsx b/src/app/(dashboard)/peer/page.tsx index 250a4890..2f885a63 100644 --- a/src/app/(dashboard)/peer/page.tsx +++ b/src/app/(dashboard)/peer/page.tsx @@ -31,6 +31,7 @@ import dayjs from "dayjs"; import { isEmpty, trim } from "lodash"; import { Cpu, + Barcode, FlagIcon, Globe, History, @@ -429,6 +430,17 @@ function PeerInformationCard({ peer }: { peer: Peer }) { } value={peer.os} /> + + + + Serial Number + + } + value={peer.serial_number} + /> + @@ -465,6 +477,7 @@ function PeerInformationCard({ peer }: { peer: Peer }) { } value={peer.ui_version?.replace("netbird-desktop-ui/", "")} /> + ); diff --git a/src/interfaces/Peer.ts b/src/interfaces/Peer.ts index 9e09bc86..6c9e793d 100644 --- a/src/interfaces/Peer.ts +++ b/src/interfaces/Peer.ts @@ -23,4 +23,5 @@ export interface Peer { city_name: string; country_code: string; connection_ip: string; + serial_number: string; } diff --git a/src/modules/groups/AssignPeerToGroupModal.tsx b/src/modules/groups/AssignPeerToGroupModal.tsx index 9e15305b..493dbb51 100644 --- a/src/modules/groups/AssignPeerToGroupModal.tsx +++ b/src/modules/groups/AssignPeerToGroupModal.tsx @@ -367,6 +367,6 @@ const PeersTableColumns: ColumnDef[] = [ header: ({ column }) => { return OS; }, - cell: ({ row }) => , + cell: ({ row }) => , }, ]; diff --git a/src/modules/groups/GroupSelector.tsx b/src/modules/groups/GroupSelector.tsx index c3b77d80..e6ee559c 100644 --- a/src/modules/groups/GroupSelector.tsx +++ b/src/modules/groups/GroupSelector.tsx @@ -21,17 +21,23 @@ import { Group } from "@/interfaces/Group"; interface MultiSelectProps { values: string[]; - onChange: (items: string[]) => void; + exactValue?: string; + onChange: (items: string[], exactItem?: string) => void; disabled?: boolean; popoverWidth?: "auto" | number; groups: Group[] | undefined; + unassignedCount?: number; + defaultGroupName?: string; } export function GroupSelector({ onChange, values, + exactValue, disabled = false, popoverWidth = 400, groups, + unassignedCount, + defaultGroupName = "All", //defined as a property, no clue if this value may change in the future }: MultiSelectProps) { const searchRef = React.useRef(null); const [inputRef, { width }] = useElementSize(); @@ -40,9 +46,20 @@ export function GroupSelector({ const toggle = (code: string) => { const isSelected = values.find((c) => c == code) != undefined; if (isSelected) { - onChange && onChange(values.filter((c) => c != code)); + onChange && onChange(values.filter((c) => c != code), undefined); } else { - onChange && onChange([...values, code]); + onChange && onChange([...values, code], undefined); + setSearch(""); + } + }; + + const toggleExactGroup = (code: string) => { + const isSelected = exactValue == code; + if (isSelected) { + onChange && onChange([], undefined); + setSearch(""); + } else { + onChange && onChange([], code); setSearch(""); } }; @@ -65,11 +82,13 @@ export function GroupSelector({ )} - - - {!isUser && ( + { + !isUser + && tableGroups.length > 1 // if length == 1, it means only "All" group exists, case not relevant + && ( { - table.setPageIndex(0); - if (groups.length == 0) { - table.getColumn("group_names")?.setFilterValue(undefined); - return; - } else { - table.getColumn("group_names")?.setFilterValue(groups); - } - resetSelectedRows(); + exactValue={ + (table + .getColumn("exact_group_name_strings") + ?.getFilterValue() as string) || undefined + } + onChange={(groups, exactItem) => { + const group_filter = groups.length == 0 ? undefined : groups; + overrideTableFilter( table, [ + { + id: "group_names", + value: group_filter + }, + { + id: "exact_group_name_strings", + value: exactItem + } + ]); }} groups={tableGroups} + unassignedCount={unassignedCount} + defaultGroupName={DEFAULT_GROUP_NAME} /> )} + + {