diff --git a/Data/Engine/web-interface/src/Devices/Device_List.jsx b/Data/Engine/web-interface/src/Devices/Device_List.jsx
index e61164cb..640e9934 100644
--- a/Data/Engine/web-interface/src/Devices/Device_List.jsx
+++ b/Data/Engine/web-interface/src/Devices/Device_List.jsx
@@ -27,8 +27,8 @@ import AddDevice from "./Add_Device.jsx";
ModuleRegistry.registerModules([AllCommunityModule]);
const myTheme = themeQuartz.withParams({
- accentColor: "#FFA6FF",
- backgroundColor: "#1f2836",
+ accentColor: "#8b5cf6",
+ backgroundColor: "#070b1a",
browserColorScheme: "dark",
chromeBackgroundColor: {
ref: "foregroundColor",
@@ -38,7 +38,7 @@ const myTheme = themeQuartz.withParams({
fontFamily: {
googleFont: "IBM Plex Sans",
},
- foregroundColor: "#FFF",
+ foregroundColor: "#f4f7ff",
headerFontSize: 14,
});
@@ -46,6 +46,86 @@ const themeClassName = myTheme.themeName || "ag-theme-quartz";
const gridFontFamily = '"IBM Plex Sans", "Helvetica Neue", Arial, sans-serif';
const iconFontFamily = '"Quartz Regular"';
+const MAGIC_UI = {
+ shellBg:
+ "radial-gradient(120% 120% at 0% 0%, rgba(76, 186, 255, 0.16), transparent 55%), " +
+ "radial-gradient(120% 120% at 100% 0%, rgba(214, 130, 255, 0.18), transparent 60%), #040711",
+ panelBg:
+ "linear-gradient(135deg, rgba(10, 16, 31, 0.98) 0%, rgba(6, 10, 24, 0.94) 60%, rgba(15, 6, 26, 0.96) 100%)",
+ panelBorder: "rgba(148, 163, 184, 0.35)",
+ glassBorder: "rgba(94, 234, 212, 0.35)",
+ glow: "0 25px 80px rgba(6, 12, 30, 0.8)",
+ textMuted: "#94a3b8",
+ textBright: "#e2e8f0",
+ accentA: "#7dd3fc",
+ accentB: "#c084fc",
+ accentC: "#f472b6",
+ warning: "#f97316",
+ success: "#34d399",
+ surfaceOverlay: "rgba(15, 23, 42, 0.72)",
+};
+
+const StatTile = React.memo(function StatTile({ label, value, meta, gradient }) {
+ return (
+
+
+ {label}
+
+
+ {value}
+
+ {meta ? (
+ {meta}
+ ) : null}
+
+ );
+});
+
+const HERO_BADGE_SX = {
+ px: 1.5,
+ py: 0.4,
+ borderRadius: 999,
+ border: "1px solid rgba(255,255,255,0.18)",
+ background: "rgba(12,18,35,0.85)",
+ fontSize: "0.72rem",
+ letterSpacing: 0.35,
+ textTransform: "uppercase",
+ color: MAGIC_UI.textBright,
+ display: "inline-flex",
+ alignItems: "center",
+ gap: 0.5,
+};
+
+const RAINBOW_BUTTON_SX = {
+ borderRadius: 999,
+ textTransform: "none",
+ fontWeight: 600,
+ px: 2.5,
+ color: "#f8fafc",
+ border: "1px solid transparent",
+ backgroundImage:
+ "linear-gradient(#05070f, #05070f), linear-gradient(120deg, #ff7c7c, #ffd36b, #7dffb7, #7dd3fc, #c084fc)",
+ backgroundOrigin: "border-box",
+ backgroundClip: "padding-box, border-box",
+ boxShadow: "0 18px 40px rgba(129, 140, 248, 0.35)",
+ "&:hover": {
+ boxShadow: "0 25px 55px rgba(99, 102, 241, 0.45)",
+ },
+};
+
const getOsIconClass = (osName) => {
const value = (osName || "").toString().toLowerCase();
if (!value) return "";
@@ -513,6 +593,105 @@ export default function DeviceList({
return agentHash === repo ? "Up-to-Date" : "Needs Updated";
}, []);
+ const heroStats = useMemo(() => {
+ const now = Date.now() / 1000;
+ const siteSet = new Set();
+ let online = 0;
+ let offline = 0;
+ let stale = 0;
+ let needsUpdate = 0;
+ rows.forEach((row) => {
+ const lastSeen =
+ row.lastSeen ??
+ row.summary?.last_seen ??
+ row.summary?.lastSeen ??
+ row.summary?.last_heartbeat;
+ if (lastSeen && now - lastSeen > 3600) {
+ stale += 1;
+ }
+ const siteName = (row.site || row.summary?.site_name || "").trim();
+ if (siteName && siteName.toLowerCase() !== "not configured") {
+ siteSet.add(siteName);
+ }
+ const statusRaw =
+ row.status ||
+ row.summary?.status ||
+ statusFromHeartbeat(lastSeen);
+ if ((statusRaw || "").toLowerCase() === "online") online += 1;
+ else offline += 1;
+ const agentHash =
+ row.agentHash ||
+ row.summary?.agent_hash ||
+ row.summary?.agentHash ||
+ row.summary?.agent_hash_value;
+ if (repoHash && computeAgentVersion(agentHash, repoHash) === "Needs Updated") {
+ needsUpdate += 1;
+ }
+ });
+ return {
+ total: rows.length,
+ online,
+ offline,
+ sites: siteSet.size,
+ stale,
+ needsUpdate,
+ };
+ }, [rows, repoHash, computeAgentVersion]);
+
+ const shortRepoSha = useMemo(() => (repoHash || "").slice(0, 7), [repoHash]);
+
+ const statTiles = useMemo(() => {
+ const total = heroStats.total || 1;
+ const onlinePct = Math.round((heroStats.online / total) * 100);
+ return [
+ {
+ key: "online",
+ label: "Online",
+ value: heroStats.online,
+ meta: `${onlinePct}% live`,
+ gradient: "linear-gradient(135deg, rgba(56, 189, 248, 0.35), rgba(34, 197, 94, 0.45))",
+ },
+ {
+ key: "stale",
+ label: "Stale (>1h)",
+ value: heroStats.stale,
+ meta: heroStats.stale ? "Needs attention" : "All synced",
+ gradient: "linear-gradient(135deg, rgba(249, 115, 22, 0.55), rgba(239, 68, 68, 0.55))",
+ },
+ {
+ key: "updates",
+ label: "Needs Agent Update",
+ value: heroStats.needsUpdate,
+ meta: repoHash ? `Repo Hash: ${shortRepoSha}` : "Syncing repo…",
+ gradient: "linear-gradient(135deg, rgba(192, 132, 252, 0.4), rgba(14, 165, 233, 0.35))",
+ },
+ {
+ key: "sites",
+ label: "Sites",
+ value: heroStats.sites,
+ meta: heroStats.sites === 1 ? "Single site" : "Multi-site",
+ gradient: "linear-gradient(135deg, rgba(125, 183, 255, 0.45), rgba(148, 163, 184, 0.35))",
+ },
+ ];
+ }, [heroStats, repoHash, shortRepoSha]);
+
+ const activeFilterCount = useMemo(
+ () => Object.keys(filters || {}).length,
+ [filters]
+ );
+ const hasActiveFilters = activeFilterCount > 0;
+
+ const heroSubtitle = useMemo(() => {
+ if (!heroStats.total) {
+ return "Connect your first device to start streaming telemetry into Borealis.";
+ }
+ const sitePart =
+ heroStats.sites > 0
+ ? `across ${heroStats.sites} ${heroStats.sites === 1 ? "managed site" : "managed sites"}`
+ : "across emerging sites";
+ return `Monitoring ${heroStats.total} managed endpoint(s) ${sitePart}.`;
+ }, [heroStats]);
+
const fetchDevices = useCallback(async (options = {}) => {
const { refreshRepo = false } = options || {};
let repoSha = repoHash;
@@ -1363,119 +1542,215 @@ export default function DeviceList({
return (
- {/* Header area with title on left and controls on right */}
-
-
-
- {computedTitle}
-
-
- {/* Views dropdown + add button */}
-
- {
- const val = e.target.value;
- setSelectedViewId(val);
- if (val === "default") applyView({ id: "default" });
- else {
- const v = views.find((x) => String(x.id) === String(val));
- if (v) applyView(v);
- }
- }}
- sx={{
- minWidth: 220,
- mr: 0,
- '& .MuiOutlinedInput-root': {
- height: 32,
- pr: 0,
- borderTopRightRadius: 0,
- borderBottomRightRadius: 0,
- '& fieldset': { borderColor: '#555', borderRight: '1px solid #555' },
- '&:hover fieldset': { borderColor: '#888' },
- },
- '& .MuiSelect-select': {
- display: 'flex',
- alignItems: 'center',
- py: 0,
- },
- }}
- SelectProps={{
- MenuProps: {
- PaperProps: { sx: { bgcolor: '#1e1e1e', color: '#fff' } },
- },
- renderValue: (val) => {
- if (val === "default") return "Default View";
- const v = views.find((x) => String(x.id) === String(val));
- return v ? v.name : "Default View";
- }
- }}
- >
-
- {views.map((v) => (
-
- ))}
-
- { setNewViewName(""); setCreateDialogOpen(true); }}
- sx={{
- ml: '-1px',
- border: '1px solid #555',
- borderLeft: '1px solid #555',
- borderRadius: '0 4px 4px 0',
- color: '#bbb',
- height: 32,
- width: 32,
- }}
- >
-
-
+
+
+
+
+ {computedTitle}
+
+ {heroSubtitle}
+
+ {hasActiveFilters ? (
+
+ Filters
+
+ {activeFilterCount}
+
+
+ ) : null}
+ {selectedIds.size > 0 ? (
+
+ Selected
+
+ {selectedIds.size}
+
+
+ ) : null}
-
- fetchDevices({ refreshRepo: true })}
- sx={{ color: "#bbb", mr: 1 }}
- >
-
-
+
+
+
+ {statTiles.map((tile) => (
+
+ ))}
+
+
+
+
+
+
+ Custom View
+
+
+
+ {
+ const val = e.target.value;
+ setSelectedViewId(val);
+ if (val === "default") applyView({ id: "default" });
+ else {
+ const v = views.find((x) => String(x.id) === String(val));
+ if (v) applyView(v);
+ }
+ }}
+ sx={{
+ minWidth: 220,
+ mr: 0,
+ "& .MuiOutlinedInput-root": {
+ height: 36,
+ pr: 0,
+ borderTopRightRadius: 0,
+ borderBottomRightRadius: 0,
+ background: "rgba(4,7,17,0.6)",
+ "& fieldset": { borderColor: "rgba(148,163,184,0.4)", borderRight: "1px solid rgba(148,163,184,0.4)" },
+ "&:hover fieldset": { borderColor: MAGIC_UI.accentA },
+ },
+ "& .MuiSelect-select": {
+ display: "flex",
+ alignItems: "center",
+ py: 0,
+ },
+ }}
+ SelectProps={{
+ MenuProps: {
+ PaperProps: { sx: { bgcolor: "rgba(8,12,24,0.98)", color: "#fff" } },
+ },
+ renderValue: (val) => {
+ if (val === "default") return "Default View";
+ const v = views.find((x) => String(x.id) === String(val));
+ return v ? v.name : "Default View";
+ },
+ }}
+ >
+
+ {views.map((v) => (
+
+ ))}
+
+ {
+ setNewViewName("");
+ setCreateDialogOpen(true);
+ }}
+ sx={{
+ ml: "-1px",
+ border: "1px solid rgba(148,163,184,0.4)",
+ borderRadius: "0 8px 8px 0",
+ color: MAGIC_UI.textBright,
+ height: 36,
+ width: 36,
+ background: "rgba(12,18,35,0.8)",
+ "&:hover": { borderColor: MAGIC_UI.accentA },
+ }}
+ >
+
+
+
+
+
+
+
+ fetchDevices({ refreshRepo: true })}
+ sx={{ color: MAGIC_UI.textBright, border: "1px solid rgba(148,163,184,0.35)", borderRadius: 2 }}
+ >
+
+
+
-
+
setColChooserAnchor(e.currentTarget)}
- sx={{ color: "#bbb", mr: 1 }}
+ sx={{ color: MAGIC_UI.textBright, border: "1px solid rgba(148,163,184,0.35)", borderRadius: 2 }}
>
@@ -1485,7 +1760,8 @@ export default function DeviceList({
variant="contained"
size="small"
startIcon={}
- sx={{ bgcolor: "#58a6ff", color: "#0b0f19" }}
+ disableElevation
+ sx={RAINBOW_BUTTON_SX}
onClick={() => {
setAddDeviceType(derivedDefaultType ?? null);
setAddDeviceOpen(true);
@@ -1496,25 +1772,8 @@ export default function DeviceList({
)}
- {/* Second row: Quick Job button aligned under header title */}
-
-
-
- {/* The Size of the Grid itself and its margins relative to the overall page */}
-
+
{ setViewActionAnchor(null); setViewActionTarget(null); }}
- PaperProps={{ sx: { bgcolor: '#1e1e1e', color: '#fff', fontSize: '13px' } }}
+ PaperProps={{
+ sx: {
+ bgcolor: "rgba(8,12,24,0.96)",
+ color: "#fff",
+ fontSize: "13px",
+ border: "1px solid rgba(148,163,184,0.3)",
+ backdropFilter: "blur(16px)",
+ },
+ }}
>