feat: implement phases 3-5 of Arma 3 UX enhancement plan
Phase 3 - Mod display names + split-pane selector:
- Parse mod.cpp/meta.cpp for display_name and workshop_id
- Rewrite ModList as two-pane available/selected interface
Phase 4 - Player kick/ban from Players tab:
- Add get_by_slot() to PlayerRepository
- Add get_rcon_client() class method to ThreadRegistry
- Add /players/{slot_id}/kick and /ban endpoints
- Rewrite PlayerTable with kick/ban modals and ban presets
Phase 5 - Historical log file browser:
- Add list_log_files() and get_log_file_path() to RPTParser
- Add logfiles_router with GET/download/DELETE endpoints
- Update LogViewer with collapsible log files section (download + delete)
This commit is contained in:
@@ -390,4 +390,58 @@ export function useSendCommand(serverId: number) {
|
||||
mutationFn: (command: string) =>
|
||||
apiClient.post(`/api/servers/${serverId}/rcon/command`, { command }),
|
||||
});
|
||||
}
|
||||
|
||||
export function useKickPlayer(serverId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ slotId, reason }: { slotId: number; reason: string }) =>
|
||||
apiClient.post(`/api/servers/${serverId}/players/${slotId}/kick`, { reason }),
|
||||
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["players", serverId] }),
|
||||
});
|
||||
}
|
||||
|
||||
export function useBanPlayer(serverId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ slotId, reason, durationMinutes }: { slotId: number; reason: string; durationMinutes?: number }) =>
|
||||
apiClient.post(`/api/servers/${serverId}/players/${slotId}/ban`, {
|
||||
reason,
|
||||
duration_minutes: durationMinutes ?? null,
|
||||
}),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["players", serverId] });
|
||||
queryClient.invalidateQueries({ queryKey: ["bans", serverId] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export interface LogFile {
|
||||
filename: string;
|
||||
size_bytes: number;
|
||||
modified_at: number;
|
||||
}
|
||||
|
||||
export function useServerLogFiles(serverId: number) {
|
||||
return useQuery({
|
||||
queryKey: ["servers", serverId, "logfiles"],
|
||||
queryFn: async () => {
|
||||
const res = await apiClient.get<{ success: boolean; data: LogFile[] }>(
|
||||
`/api/servers/${serverId}/logfiles`,
|
||||
);
|
||||
return res.data.data;
|
||||
},
|
||||
enabled: serverId > 0,
|
||||
refetchInterval: 30_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteLogFile(serverId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (filename: string) =>
|
||||
apiClient.delete(`/api/servers/${serverId}/logfiles/${encodeURIComponent(filename)}`),
|
||||
onSuccess: () =>
|
||||
queryClient.invalidateQueries({ queryKey: ["servers", serverId, "logfiles"] }),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user