perf: frontend request cache, poll pause, and code-split shell (#1052)

Host/status caching, shell code-split, SSH pool waits, host-metrics concurrency, background-tab idle, per-host status subscriptions, homepage poll quieting, and virtualized host sidebar + file manager lists.
This commit is contained in:
ZacharyZcR
2026-07-14 13:58:28 +08:00
committed by GitHub
parent 6e66a5a4ef
commit 867058bddd
53 changed files with 2663 additions and 831 deletions
+25 -4
View File
@@ -801,6 +801,7 @@ function CardItem({
onAddServiceLink,
onDeleteServiceLink,
statusLoading,
isVisible = true,
}: {
slot: CardSlot;
editMode: boolean;
@@ -830,6 +831,7 @@ function CardItem({
onAddServiceLink: (label: string, url: string) => Promise<void>;
onDeleteServiceLink: (id: number) => Promise<void>;
statusLoading?: boolean;
isVisible?: boolean;
}) {
const cardRef = useRef<HTMLDivElement | null>(null);
@@ -926,6 +928,7 @@ function CardItem({
{slot.id === "network_graph" && (
<NetworkGraphCard
embedded={true}
isVisible={isVisible}
onOpenInNewTab={() => onOpenSingletonTab("network_graph")}
/>
)}
@@ -1055,6 +1058,7 @@ type PanelColumnProps = {
onAddServiceLink: (label: string, url: string) => Promise<void>;
onDeleteServiceLink: (id: number) => Promise<void>;
statusLoading: boolean;
isVisible?: boolean;
};
function PanelColumn({
@@ -1086,6 +1090,7 @@ function PanelColumn({
onAddServiceLink,
onDeleteServiceLink,
statusLoading,
isVisible = true,
}: PanelColumnProps) {
const { t } = useTranslation();
const sorted = [...slots].sort((a, b) => a.order - b.order);
@@ -1142,6 +1147,7 @@ function PanelColumn({
onAddServiceLink={onAddServiceLink}
onDeleteServiceLink={onDeleteServiceLink}
statusLoading={statusLoading}
isVisible={isVisible}
/>
</div>
))}
@@ -1192,9 +1198,12 @@ function ColumnDivider({
export function DashboardTab({
onOpenSingletonTab,
onOpenTab,
isVisible = true,
}: {
onOpenSingletonTab: (type: TabType, pendingEvent?: string) => void;
onOpenTab: (host: Host, type: TabType) => void;
/** When false, pause dashboard metrics refresh while the tab stays mounted. */
isVisible?: boolean;
}) {
const { t, i18n } = useTranslation();
const { initialLoadComplete } = useServerStatus();
@@ -1349,7 +1358,9 @@ export function DashboardTab({
const mapped = raw.map(sshHostToHost);
const statusHosts = mapped.filter(isStatusCheckEnabled);
if (mounted) setHosts(mapped);
fetchMetrics(statusHosts).catch(() => {});
if (isVisible) {
fetchMetrics(statusHosts).catch(() => {});
}
};
load();
@@ -1399,7 +1410,14 @@ export function DashboardTab({
})
.catch(() => {});
if (!isVisible) {
return () => {
mounted = false;
};
}
const metricsInterval = setInterval(async () => {
if (document.visibilityState === "hidden") return;
const raw = await getSSHHosts().catch(() => []);
const mapped = raw.map(sshHostToHost);
const statusHosts = mapped.filter(isStatusCheckEnabled);
@@ -1411,17 +1429,18 @@ export function DashboardTab({
mounted = false;
clearInterval(metricsInterval);
};
}, [fetchMetrics]);
}, [fetchMetrics, isVisible]);
useEffect(() => {
if (viewerSessionsRef.current.size === 0) return;
if (!isVisible || viewerSessionsRef.current.size === 0) return;
const heartbeat = setInterval(async () => {
if (document.visibilityState === "hidden") return;
for (const [, sessionId] of viewerSessionsRef.current) {
sendMetricsHeartbeat(sessionId).catch(() => {});
}
}, 30000);
return () => clearInterval(heartbeat);
}, [hostMetrics]);
}, [hostMetrics, isVisible]);
const handleClearActivity = async () => {
try {
@@ -1594,6 +1613,7 @@ export function DashboardTab({
onAddServiceLink: handleAddServiceLink,
onDeleteServiceLink: handleDeleteServiceLink,
statusLoading,
isVisible,
};
const isMobile = useIsMobile();
@@ -1733,6 +1753,7 @@ export function DashboardTab({
{slot.id === "network_graph" && (
<NetworkGraphCard
embedded={true}
isVisible={isVisible}
onOpenInNewTab={() => onOpenSingletonTab("network_graph")}
/>
)}
+16 -2
View File
@@ -92,6 +92,8 @@ interface NetworkGraphCardProps {
rightSidebarWidth?: number;
embedded?: boolean;
onOpenInNewTab?: () => void;
/** When false, pause status refresh while the surface stays mounted. */
isVisible?: boolean;
}
type NetworkElement = NetworkTopologyNode | NetworkTopologyEdge;
@@ -195,6 +197,7 @@ function buildNodeSvg(
export function NetworkGraphCard({
embedded = true,
onOpenInNewTab,
isVisible = true,
}: NetworkGraphCardProps): React.ReactElement {
const { t } = useTranslation();
const { addTab } = useTabsSafe();
@@ -269,8 +272,19 @@ export function NetworkGraphCard({
}, [hostMap]);
useEffect(() => {
if (!isVisible) {
if (statusIntervalRef.current) {
clearInterval(statusIntervalRef.current);
statusIntervalRef.current = null;
}
return;
}
loadData();
statusIntervalRef.current = setInterval(updateHostStatuses, 30000);
statusIntervalRef.current = setInterval(() => {
if (document.visibilityState === "hidden") return;
updateHostStatuses();
}, 30000);
const onClickOutside = (e: MouseEvent) => {
if (
contextMenuRef.current &&
@@ -293,7 +307,7 @@ export function NetworkGraphCard({
document.removeEventListener("mousedown", onClickOutside, true);
themeObserver.disconnect();
};
}, []);
}, [isVisible]);
const loadData = async () => {
setLoading(true);