feat: add automatic cluster sync and IPAM discovery with configurable intervals, firewall log file parsing, and enhanced flow prioritization
Add RuntimeSettingsRead/RuntimeSettingsUpdate schemas with auto_node_sync_enabled/auto_node_sync_interval_minutes/auto_ipam_sync_enabled/auto_ipam_sync_interval_minutes/last_node_auto_sync_at/last_ipam_auto_sync_at fields, implement firewall_log_lines_from_files to parse /var/log/pve-firewall.log with max_lines limit and error collection, extend collect_firewall_log
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { Activity, Cpu, Copy, RadioTower, ScrollText } from "lucide-react";
|
||||
import { Activity, Cpu, Copy, RadioTower, RefreshCcw, ScrollText } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
import { AgentInstallInfo, api, Node } from "../api/client";
|
||||
import { AgentInstallInfo, api, Node, RuntimeSettings } from "../api/client";
|
||||
import { DataTable } from "../components/DataTable";
|
||||
import { iconButtonClass, secondaryButtonClass } from "../components/FormControls";
|
||||
import { LoadingOverlay } from "../components/LoadingOverlay";
|
||||
@@ -11,6 +11,7 @@ import { PageHeader } from "../components/PageHeader";
|
||||
|
||||
export function Nodes() {
|
||||
const nodes = useQuery({ queryKey: ["nodes-agents"], queryFn: () => api<Node[]>("/nodes/agents") });
|
||||
const settings = useQuery({ queryKey: ["settings"], queryFn: () => api<RuntimeSettings>("/settings") });
|
||||
const [selectedNode, setSelectedNode] = useState<Node | null>(null);
|
||||
const [detailNode, setDetailNode] = useState<Node | null>(null);
|
||||
const [copied, setCopied] = useState(false);
|
||||
@@ -21,6 +22,13 @@ export function Nodes() {
|
||||
setCopied(false);
|
||||
},
|
||||
});
|
||||
const toggleAutoSync = useMutation({
|
||||
mutationFn: () => api<RuntimeSettings>("/settings", {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({ auto_node_sync_enabled: !settings.data?.auto_node_sync_enabled }),
|
||||
}),
|
||||
onSuccess: () => settings.refetch(),
|
||||
});
|
||||
|
||||
async function copyCommand() {
|
||||
if (!installInfo.data) {
|
||||
@@ -53,6 +61,18 @@ export function Nodes() {
|
||||
<>
|
||||
<PageHeader title="Nodes" subtitle="Cluster nodes, capacity, health, and NexaFabric agent enrollment." />
|
||||
<LoadingOverlay open={installInfo.isPending} message="Generating node agent installer..." />
|
||||
<div className="mb-4 flex flex-wrap items-center justify-between gap-3 rounded-md border border-border bg-panel p-3">
|
||||
<div>
|
||||
<div className="text-sm font-medium">Automatic node sync</div>
|
||||
<div className="text-xs text-slate-500">
|
||||
{settings.data?.auto_node_sync_enabled ? `Enabled every ${settings.data.auto_node_sync_interval_minutes} minutes` : "Disabled"}
|
||||
</div>
|
||||
</div>
|
||||
<button className={secondaryButtonClass} disabled={toggleAutoSync.isPending || !settings.data} onClick={() => toggleAutoSync.mutate()}>
|
||||
<RefreshCcw size={16} />
|
||||
{settings.data?.auto_node_sync_enabled ? "Disable Auto Sync" : "Enable Auto Sync"}
|
||||
</button>
|
||||
</div>
|
||||
{nodes.isLoading ? <div className="rounded-md border border-border bg-panel p-8 text-sm">Loading...</div> : null}
|
||||
{nodes.error ? <div className="rounded-md border border-danger p-4 text-sm text-danger">Failed to load nodes.</div> : null}
|
||||
{!nodes.isLoading && !nodes.error ? (
|
||||
|
||||
Reference in New Issue
Block a user