feat: Phase 2 — Mission rotation management + multi-file upload
- Backend: add terrain field to Arma3MissionManager.list_missions() - Backend: add missions field to ServerConfig Pydantic model - Backend: add GET /missions/rotation and PUT /missions/rotation endpoints - Frontend: Mission type gains terrain field; new MissionRotationEntry type - Frontend: useServerMissionRotation and useUpdateMissionRotation hooks - Frontend: useUploadMission updated to accept File[] with sequential upload - Frontend: MissionList redesigned with Available Missions + Mission Rotation sections - Frontend: per-file upload progress tracking, terrain badges, difficulty select - Tests: 5 new tests; fixed existing useUploadMission test for File[] API; 141 pass
This commit is contained in:
@@ -102,6 +102,12 @@ export interface Mission {
|
||||
name: string;
|
||||
filename: string;
|
||||
size_bytes: number;
|
||||
terrain: string;
|
||||
}
|
||||
|
||||
export interface MissionRotationEntry {
|
||||
name: string;
|
||||
difficulty: string;
|
||||
}
|
||||
|
||||
export interface MissionsResponse {
|
||||
@@ -311,15 +317,43 @@ export function useRevokeBan(serverId: number) {
|
||||
});
|
||||
}
|
||||
|
||||
export function useServerMissionRotation(serverId: number) {
|
||||
return useQuery({
|
||||
queryKey: ["missions", serverId, "rotation"],
|
||||
queryFn: async () => {
|
||||
const res = await apiClient.get<{
|
||||
success: boolean;
|
||||
data: { missions: MissionRotationEntry[] };
|
||||
}>(`/api/servers/${serverId}/missions/rotation`);
|
||||
return res.data.data.missions;
|
||||
},
|
||||
enabled: serverId > 0,
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateMissionRotation(serverId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (data: { missions: MissionRotationEntry[]; config_version: number }) =>
|
||||
apiClient.put(`/api/servers/${serverId}/missions/rotation`, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["missions", serverId, "rotation"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["servers", serverId, "config", "server"] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useUploadMission(serverId: number) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (file: File) => {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
return apiClient.post(`/api/servers/${serverId}/missions`, formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
mutationFn: async (files: File[]) => {
|
||||
for (const file of files) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
await apiClient.post(`/api/servers/${serverId}/missions`, formData, {
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
});
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["missions", serverId] });
|
||||
|
||||
Reference in New Issue
Block a user