Add panel feature updates across API, daemon, and web

This commit is contained in:
2026-03-02 21:53:54 +00:00
parent 6b463c2b1a
commit afc64b83c1
49 changed files with 7040 additions and 305 deletions
@@ -1,6 +1,6 @@
import { Outlet, useParams, Link, useLocation } from 'react-router';
import { useQuery } from '@tanstack/react-query';
import { Terminal, FolderOpen, Settings, Calendar, HardDrive, Users, Puzzle, Settings2 } from 'lucide-react';
import { Terminal, FolderOpen, Settings, Calendar, HardDrive, Users, Puzzle, Settings2, Database as DatabaseIcon } from 'lucide-react';
import { cn } from '@source/ui';
import { api } from '@/lib/api';
import { Badge } from '@/components/ui/badge';
@@ -26,6 +26,7 @@ const tabs = [
{ label: 'Console', path: 'console', icon: Terminal },
{ label: 'Files', path: 'files', icon: FolderOpen },
{ label: 'Config', path: 'config', icon: Settings2 },
{ label: 'Databases', path: 'databases', icon: DatabaseIcon },
{ label: 'Plugins', path: 'plugins', icon: Puzzle },
{ label: 'Backups', path: 'backups', icon: HardDrive },
{ label: 'Schedules', path: 'schedules', icon: Calendar },
@@ -40,6 +41,7 @@ export function ServerLayout() {
const { data: server } = useQuery({
queryKey: ['server', orgId, serverId],
queryFn: () => api.get<ServerDetail>(`/organizations/${orgId}/servers/${serverId}`),
refetchInterval: 3_000,
});
const currentTab = location.pathname.split('/').pop();
@@ -7,6 +7,7 @@ import {
Users,
Shield,
Gamepad2,
Puzzle,
ScrollText,
ChevronLeft,
} from 'lucide-react';
@@ -40,6 +41,7 @@ export function Sidebar() {
? [
{ label: 'Users', href: '/admin/users', icon: Users },
{ label: 'Games', href: '/admin/games', icon: Gamepad2 },
{ label: 'Plugins', href: '/admin/plugins', icon: Puzzle },
{ label: 'Nodes', href: '/admin/nodes', icon: Network },
{ label: 'Audit Logs', href: '/admin/audit-logs', icon: ScrollText },
]
@@ -19,14 +19,38 @@ interface PowerControlsProps {
status: string;
}
type PowerAction = 'start' | 'stop' | 'restart' | 'kill';
interface CachedServerDetail {
status: string;
[key: string]: unknown;
}
export function PowerControls({ serverId, orgId, status }: PowerControlsProps) {
const queryClient = useQueryClient();
const serverQueryKey = ['server', orgId, serverId] as const;
const powerMutation = useMutation({
mutationFn: (action: string) =>
mutationFn: (action: PowerAction) =>
api.post(`/organizations/${orgId}/servers/${serverId}/power`, { action }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['server', orgId, serverId] });
onMutate: (action) => {
const nextStatusByAction: Record<PowerAction, string> = {
start: 'starting',
stop: 'stopping',
restart: 'stopping',
kill: 'stopped',
};
queryClient.setQueryData<CachedServerDetail | undefined>(serverQueryKey, (current) => {
if (!current) return current;
return {
...current,
status: nextStatusByAction[action],
};
});
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: serverQueryKey });
queryClient.invalidateQueries({ queryKey: ['servers', orgId] });
},
});