diff --git a/Data/Server/WebUI/src/Devices/Device_Details.jsx b/Data/Server/WebUI/src/Devices/Device_Details.jsx index 9dd1cee..b103856 100644 --- a/Data/Server/WebUI/src/Devices/Device_Details.jsx +++ b/Data/Server/WebUI/src/Devices/Device_Details.jsx @@ -209,7 +209,7 @@ export default function DeviceDetails({ device, onBack }) { const summary = details.summary || {}; const summaryItems = [ - { label: "Device Name", value: summary.hostname || agent.hostname || device?.hostname || "unknown" }, + { label: "Hostname", value: summary.hostname || agent.hostname || device?.hostname || "unknown" }, { label: "Operating System", value: summary.operating_system || agent.agent_operating_system || "unknown" }, { label: "Device Type", value: summary.device_type || "unknown" }, { label: "Last User", value: ( diff --git a/Data/Server/WebUI/src/Devices/Device_List.jsx b/Data/Server/WebUI/src/Devices/Device_List.jsx index 1fb8a26..93c80f3 100644 --- a/Data/Server/WebUI/src/Devices/Device_List.jsx +++ b/Data/Server/WebUI/src/Devices/Device_List.jsx @@ -17,10 +17,12 @@ import { Menu, MenuItem, Popover, - TextField + TextField, + Tooltip } from "@mui/material"; import MoreVertIcon from "@mui/icons-material/MoreVert"; import FilterListIcon from "@mui/icons-material/FilterList"; +import ViewColumnIcon from "@mui/icons-material/ViewColumn"; import { DeleteDeviceDialog } from "../Dialogs.jsx"; import QuickJob from "../Scheduling/Quick_Job.jsx"; @@ -59,26 +61,44 @@ export default function DeviceList({ onSelectDevice }) { const [quickJobOpen, setQuickJobOpen] = useState(false); // Column configuration and rearranging state + const COL_LABELS = useMemo( + () => ({ + status: "Status", + hostname: "Hostname", + description: "Description", + lastUser: "Last User", + type: "Type", + os: "OS", + internalIp: "Internal IP", + externalIp: "External IP", + lastReboot: "Last Reboot", + created: "Created", + lastSeen: "Last Seen", + }), + [] + ); + const defaultColumns = useMemo( () => [ - { id: "status", label: "Status" }, - { id: "hostname", label: "Hostname" }, - { id: "lastUser", label: "Last User" }, - { id: "type", label: "Type" }, - { id: "os", label: "OS" }, - { id: "created", label: "Created" } + { id: "status", label: COL_LABELS.status }, + { id: "hostname", label: COL_LABELS.hostname }, + { id: "description", label: COL_LABELS.description }, + { id: "lastUser", label: COL_LABELS.lastUser }, + { id: "type", label: COL_LABELS.type }, + { id: "os", label: COL_LABELS.os }, ], - [] + [COL_LABELS] ); const [columns, setColumns] = useState(defaultColumns); const dragColId = useRef(null); + const [colChooserAnchor, setColChooserAnchor] = useState(null); // Per-column filters const [filters, setFilters] = useState({}); const [filterAnchor, setFilterAnchor] = useState(null); // { id, anchorEl } // Cache device details to avoid re-fetching every refresh - const [detailsByHost, setDetailsByHost] = useState({}); // hostname -> { lastUser, created, createdTs } + const [detailsByHost, setDetailsByHost] = useState({}); // hostname -> cached fields const fetchAgents = useCallback(async () => { try { @@ -98,6 +118,10 @@ export default function DeviceList({ onSelectDevice }) { type: a.device_type || details.type || "", created: details.created || "", createdTs: details.createdTs || 0, + internalIp: details.internalIp || "", + externalIp: details.externalIp || "", + lastReboot: details.lastReboot || "", + description: details.description || "", }; }); setRows(arr); @@ -129,9 +153,22 @@ export default function DeviceList({ onSelectDevice }) { createdTs = isNaN(parsed) ? 0 : Math.floor(parsed / 1000); } const deviceType = (summary.device_type || "").trim(); + const internalIp = summary.internal_ip || ""; + const externalIp = summary.external_ip || ""; + const lastReboot = summary.last_reboot || ""; + const description = summary.description || ""; setDetailsByHost((prev) => ({ ...prev, - [h]: { lastUser, created: createdRaw, createdTs, type: deviceType }, + [h]: { + lastUser, + created: createdRaw, + createdTs, + type: deviceType, + internalIp, + externalIp, + lastReboot, + description, + }, })); } catch { // ignore per-host failure @@ -150,6 +187,10 @@ export default function DeviceList({ onSelectDevice }) { type: det.type || r.type, created: det.created || r.created, createdTs: det.createdTs || r.createdTs, + internalIp: det.internalIp || r.internalIp, + externalIp: det.externalIp || r.externalIp, + lastReboot: det.lastReboot || r.lastReboot, + description: det.description || r.description, }; }) ); @@ -176,14 +217,24 @@ export default function DeviceList({ onSelectDevice }) { return row.status || ""; case "hostname": return row.hostname || ""; + case "description": + return row.description || ""; case "lastUser": return row.lastUser || ""; case "type": return row.type || ""; case "os": return row.os || ""; + case "internalIp": + return row.internalIp || ""; + case "externalIp": + return row.externalIp || ""; + case "lastReboot": + return row.lastReboot || ""; case "created": return formatCreated(row.created, row.createdTs); + case "lastSeen": + return formatLastSeen(row.lastSeen); default: return ""; } @@ -310,7 +361,16 @@ export default function DeviceList({ onSelectDevice }) { Devices - + + + setColChooserAnchor(e.currentTarget)} + sx={{ color: "#bbb", mr: 1 }} + > + + + + + + {/* Filter popover */}