diff --git a/src/components/table/DataTableToolTipButton.tsx b/src/components/table/DataTableToolTipButton.tsx new file mode 100644 index 00000000..c6acebbf --- /dev/null +++ b/src/components/table/DataTableToolTipButton.tsx @@ -0,0 +1,48 @@ +import Button from "@components/Button"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@components/Tooltip"; +import { motion } from "framer-motion"; +import { RefreshCcw } from "lucide-react"; +import * as React from "react"; +import { useState } from "react"; + +type Props = { + onClick: () => void; + disabled?: boolean; + variant?: "default" | "primary" | "secondary" | "input" | "dotted" | "tertiary" | "white" | "outline" | "danger-outline" | "default-outline" | "danger" | null | undefined; + title?:any; + children: any; +}; +export default function DataTableToolTipButton({ onClick, disabled, variant, title, children }: Props) { + const [rotate, setRotate] = useState(false); + //const [disabled, setDisabled] = useState(false); + const [hovered, setHovered] = useState(false); + + return ( + + + + + + { + if (hovered) event.preventDefault(); + }} + > + + {title} + + + + ); +} 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/peers/PeerOSCell.tsx b/src/modules/peers/PeerOSCell.tsx index 85df9933..a9f1ad8d 100644 --- a/src/modules/peers/PeerOSCell.tsx +++ b/src/modules/peers/PeerOSCell.tsx @@ -13,8 +13,9 @@ import AppleLogo from "@/assets/os-icons/apple.svg"; import FreeBSDLogo from "@/assets/os-icons/FreeBSD.png"; import { getOperatingSystem } from "@/hooks/useOperatingSystem"; import { OperatingSystem } from "@/interfaces/OperatingSystem"; +import { Barcode, Laptop } from "lucide-react"; -export function PeerOSCell({ os }: { os: string }) { +export function PeerOSCell({ os, serial }: { os: string, serial?: string }) { return ( @@ -34,13 +35,50 @@ export function PeerOSCell({ os }: { os: string }) { -
{os}
+ } + label={"OS"} + value={os} + /> + { (serial !== undefined) && + } + label={"Serial"} + value={serial} + /> + }
); } +const ListItem = ({ + icon, + label, + value, +}: { + icon: React.ReactNode; + label: string; + value: string | React.ReactNode; +}) => { + return ( +
+
+ {icon} + {label} +
+
{value}
+
+ ); +}; + + export function OSLogo({ os }: { os: string }) { const icon = useMemo(() => { return getOperatingSystem(os); diff --git a/src/modules/peers/PeersTable.tsx b/src/modules/peers/PeersTable.tsx index 3f98c381..a775e7ab 100644 --- a/src/modules/peers/PeersTable.tsx +++ b/src/modules/peers/PeersTable.tsx @@ -14,6 +14,7 @@ import { ColumnDef, RowSelectionState, SortingState, + VisibilityState, } from "@tanstack/react-table"; import { uniqBy } from "lodash"; import { ExternalLinkIcon } from "lucide-react"; @@ -21,6 +22,7 @@ import { usePathname } from "next/navigation"; import React, { useState } from "react"; import { useSWRConfig } from "swr"; import PeerIcon from "@/assets/icons/PeerIcon"; +import DataTableToolTipButton from "@/components/table/DataTableToolTipButton"; import PeerProvider from "@/contexts/PeerProvider"; import { useLoggedInUser } from "@/contexts/UsersProvider"; import { useLocalStorage } from "@/hooks/useLocalStorage"; @@ -40,6 +42,7 @@ import PeerVersionCell from "@/modules/peers/PeerVersionCell"; const PeersTableColumns: ColumnDef[] = [ { id: "select", + enableHiding: false, header: ({ table }) => (
[] = [
), enableSorting: false, - enableHiding: false, }, { accessorKey: "name", + enableHiding: false, header: ({ column }) => { return Name; }, @@ -82,6 +85,7 @@ const PeersTableColumns: ColumnDef[] = [ accessorFn: (peer) => peer.connected, }, { + id: "ip", accessorKey: "ip", sortingFn: "text", }, @@ -94,6 +98,8 @@ const PeersTableColumns: ColumnDef[] = [ accessorFn: (peer) => (peer.user ? peer.user?.email : "Unknown"), }, { + id: "dns_label", + enableHiding: false, accessorKey: "dns_label", header: ({ column }) => { return Address; @@ -101,11 +107,21 @@ const PeersTableColumns: ColumnDef[] = [ cell: ({ row }) => , }, { + id: "group_name_strings", accessorKey: "group_name_strings", accessorFn: (peer) => peer.groups?.map((g) => g?.name || "").join(", "), sortingFn: "text", }, { + // used for exact group matching + id: "exact_group_name_strings", + accessorKey: "exact_group_name_strings", + accessorFn: (peer) => peer.groups?.map((g) => g?.name || "").join("|"), + sortingFn: "text", + filterFn: "equals" + }, + { + id: "group_names", accessorKey: "group_names", accessorFn: (peer) => peer.groups?.map((g) => g?.name || ""), sortingFn: "text", @@ -124,6 +140,7 @@ const PeersTableColumns: ColumnDef[] = [ ), }, { + id: "last_seen", accessorKey: "last_seen", header: ({ column }) => { return Last seen; @@ -132,13 +149,23 @@ const PeersTableColumns: ColumnDef[] = [ cell: ({ row }) => , }, { + id: "os", accessorKey: "os", header: ({ column }) => { return OS; }, - cell: ({ row }) => , + cell: ({ row }) => , + }, + { + id: "serial", + header: ({ column }) => { + return Serial number; + }, + accessorFn: (peer) => peer.serial_number, + sortingFn: "text", }, { + id: "version", accessorKey: "version", header: ({ column }) => { return Version; @@ -165,8 +192,10 @@ const PeersTableColumns: ColumnDef[] = [ }, { id: "actions", + enableHiding: false, accessorKey: "id", header: "", + cell: ({ row }) => ( @@ -213,6 +242,25 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) { const [selectedRows, setSelectedRows] = useState({}); + const colVisibility: VisibilityState = { + select: !isUser, + actions: !isUser, + groups: !isUser, + connected: false, + approval_required: false, + + // hidden, but usefull for lookup + serial: false, + group_name_strings: false, + exact_group_name_strings: false, + group_names: false, + ip: false, + user_name: false, + user_email: false, + } + + const [resultingColumnVisibility, setColumnVisibility] = useState(colVisibility); + const resetSelectedRows = () => { if (Object.keys(selectedRows).length > 0) { setSelectedRows({}); @@ -226,6 +274,7 @@ export default function PeersTable({ peers, isLoading, headingTarget }: Props) { onCanceled={() => setSelectedRows({})} /> )} + { + table.setPageIndex(0); + if (table.getColumn("exact_group_name_strings")?.getFilterValue() !== undefined) { + table.resetColumnFilters(); + return; + } + table.setColumnFilters([ + { + id: "exact_group_name_strings", + value: "All" + } + ]) + }} + variant={table.getColumn("exact_group_name_strings")?.getFilterValue() !== undefined + ? "tertiary" + : "secondary"} + title="filter peers assigned to the uniq group: 'All'" + > + All group only + + {