fix: resolve frontend routing, API mismatches, and missing UI components

- Add servers list page and missing routes (servers, settings redirect, account security)
- Fix members page .map error (API returns { data } wrapper, not flat array)
- Fix auth store fetchUser expecting flat User but API returns { user } wrapper
- Add node token display dialog after creation
- Add allocation management UI to node detail page
- Add account security page with password change
- Add change-password API endpoint
- Add node servers and stats API endpoints
- Fix config save using PATCH instead of PUT, add api.put method
- Fix audit logs field name mismatch (userName vs username)
- Replace admin nodes page to avoid orgId dependency
- Remove duplicate sidebar nav items

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hibna
2026-02-22 13:07:00 +03:00
parent d7d8fd5339
commit c9fe2bd9fe
14 changed files with 618 additions and 17 deletions
+70
View File
@@ -0,0 +1,70 @@
import { useQuery } from '@tanstack/react-query';
import { Network, Wifi, WifiOff } from 'lucide-react';
import { api } from '@/lib/api';
import { formatBytes } from '@/lib/utils';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
interface NodeItem {
id: string;
name: string;
fqdn: string;
daemonPort: number;
grpcPort: number;
memoryTotal: number;
diskTotal: number;
isOnline: boolean;
organizationId: string;
}
export function AdminNodesPage() {
const { data } = useQuery({
queryKey: ['admin-nodes'],
queryFn: () => api.get<{ data: NodeItem[] }>('/admin/nodes'),
});
const nodes = data?.data ?? [];
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold">All Nodes</h1>
<p className="text-muted-foreground">{nodes.length} nodes across all organizations</p>
</div>
<div className="grid gap-4 sm:grid-cols-2">
{nodes.map((node) => (
<Card key={node.id}>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<div className="flex items-center gap-3">
<Network className="h-5 w-5 text-primary" />
<CardTitle className="text-base">{node.name}</CardTitle>
</div>
<Badge variant={node.isOnline ? 'default' : 'destructive'}>
{node.isOnline ? (
<><Wifi className="mr-1 h-3 w-3" /> Online</>
) : (
<><WifiOff className="mr-1 h-3 w-3" /> Offline</>
)}
</Badge>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">{node.fqdn}:{node.daemonPort}</p>
<div className="mt-3 flex gap-4 text-sm">
<span>{formatBytes(node.memoryTotal)} RAM</span>
<span>{formatBytes(node.diskTotal)} Disk</span>
</div>
</CardContent>
</Card>
))}
{nodes.length === 0 && (
<Card>
<CardContent className="py-12 text-center text-muted-foreground">
No nodes registered
</CardContent>
</Card>
)}
</div>
</div>
);
}