Dev 1.4.0 #138

Merged
LukeGus merged 13 commits from dev-1.4.0 into main 2025-09-01 05:11:26 +00:00
4 changed files with 24 additions and 15 deletions
Showing only changes of commit d46fafb421 - Show all commits
+18 -9
View File
@@ -370,7 +370,9 @@ async function pollStatusesOnce(): Promise<void> {
const checks = hosts.map(async (h) => { const checks = hosts.map(async (h) => {
const isOnline = await tcpPing(h.ip, h.port, 5000); const isOnline = await tcpPing(h.ip, h.port, 5000);
hostStatuses.set(h.id, {status: isOnline ? 'online' : 'offline', lastChecked: now}); const now = new Date().toISOString();
const statusEntry: StatusEntry = {status: isOnline ? 'online' : 'offline', lastChecked: now};
hostStatuses.set(h.id, statusEntry);
return isOnline; return isOnline;
}); });
@@ -396,15 +398,22 @@ app.get('/status/:id', async (req, res) => {
return res.status(400).json({error: 'Invalid id'}); return res.status(400).json({error: 'Invalid id'});
} }
if (!hostStatuses.has(id)) { try {
await pollStatusesOnce(); const host = await fetchHostById(id);
if (!host) {
return res.status(404).json({error: 'Host not found'});
}
const isOnline = await tcpPing(host.ip, host.port, 5000);
const now = new Date().toISOString();
const statusEntry: StatusEntry = {status: isOnline ? 'online' : 'offline', lastChecked: now};
hostStatuses.set(id, statusEntry);
res.json(statusEntry);
} catch (err) {
logger.error('Failed to check host status', err);
res.status(500).json({error: 'Failed to check host status'});
} }
const entry = hostStatuses.get(id);
if (!entry) {
return res.status(404).json({error: 'Host not found'});
}
res.json(entry);
}); });
app.post('/refresh', async (req, res) => { app.post('/refresh', async (req, res) => {
+2 -2
View File
@@ -6,7 +6,7 @@ import {Button} from "@/components/ui/button.tsx";
import {Progress} from "@/components/ui/progress" import {Progress} from "@/components/ui/progress"
import {Cpu, HardDrive, MemoryStick} from "lucide-react"; import {Cpu, HardDrive, MemoryStick} from "lucide-react";
import {Tunnel} from "@/ui/Apps/Tunnel/Tunnel.tsx"; import {Tunnel} from "@/ui/Apps/Tunnel/Tunnel.tsx";
import {getServerStatusById, getServerMetricsById, ServerMetrics} from "@/ui/main-axios.ts"; import {getServerStatusById, getServerMetricsById, type ServerMetrics} from "@/ui/main-axios.ts";
import {useTabs} from "@/ui/Navigation/Tabs/TabContext.tsx"; import {useTabs} from "@/ui/Navigation/Tabs/TabContext.tsx";
interface ServerProps { interface ServerProps {
@@ -102,7 +102,7 @@ export function Server({
fetchStatus(); fetchStatus();
fetchMetrics(); fetchMetrics();
} }
}, 300_000); }, 30000);
} }
return () => { return () => {
+1 -1
View File
@@ -58,7 +58,7 @@ export function Host({host}: HostProps): React.ReactElement {
fetchStatus(); fetchStatus();
intervalId = window.setInterval(fetchStatus, 30000); intervalId = window.setInterval(fetchStatus, 10000);
return () => { return () => {
cancelled = true; cancelled = true;
+3 -3
View File
@@ -429,7 +429,7 @@ export function LeftSidebar({
<Separator className="p-0.25"/> <Separator className="p-0.25"/>
<SidebarContent> <SidebarContent>
<SidebarGroup className="!m-0 !p-0 !-mb-2"> <SidebarGroup className="!m-0 !p-0 !-mb-2">
<Button className="m-2 flex flex-row font-semibold" variant="outline" <Button className="m-2 flex flex-row font-semibold border-2 !border-[#303032]" variant="outline"
onClick={openSshManagerTab} disabled={!!sshManagerTab || isSplitScreenActive} onClick={openSshManagerTab} disabled={!!sshManagerTab || isSplitScreenActive}
title={sshManagerTab ? 'SSH Manager already open' : isSplitScreenActive ? 'Disabled during split screen' : undefined}> title={sshManagerTab ? 'SSH Manager already open' : isSplitScreenActive ? 'Disabled during split screen' : undefined}>
<HardDrive strokeWidth="2.5"/> <HardDrive strokeWidth="2.5"/>
@@ -438,12 +438,12 @@ export function LeftSidebar({
</SidebarGroup> </SidebarGroup>
<Separator className="p-0.25"/> <Separator className="p-0.25"/>
<SidebarGroup className="flex flex-col gap-y-2 !-mt-2"> <SidebarGroup className="flex flex-col gap-y-2 !-mt-2">
<div className="bg-[#131316] rounded-lg"> <div className="!bg-[#222225] rounded-lg">
<Input <Input
value={search} value={search}
onChange={e => setSearch(e.target.value)} onChange={e => setSearch(e.target.value)}
placeholder="Search hosts by any info..." placeholder="Search hosts by any info..."
className="w-full h-8 text-sm border-2 border-[#272728] rounded-lg" className="w-full h-8 text-sm border-2 !bg-[#222225] border-[#303032] rounded-md"
autoComplete="off" autoComplete="off"
/> />
</div> </div>