Better support for Talos ISO downloads.

This commit is contained in:
2025-10-12 20:16:45 +00:00
parent e5bd3c36f5
commit 331777c5fd
12 changed files with 1245 additions and 221 deletions

View File

@@ -0,0 +1,42 @@
import { apiClient } from './client';
import type { AssetListResponse, Schematic, DownloadAssetRequest, AssetStatusResponse } from './types/asset';
// Get API base URL
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5055';
export const assetsApi = {
// List all schematics
list: async (): Promise<AssetListResponse> => {
const response = await apiClient.get('/api/v1/assets');
return response as AssetListResponse;
},
// Get schematic details
get: async (schematicId: string): Promise<Schematic> => {
const response = await apiClient.get(`/api/v1/assets/${schematicId}`);
return response as Schematic;
},
// Download assets for a schematic
download: async (schematicId: string, request: DownloadAssetRequest): Promise<{ message: string }> => {
const response = await apiClient.post(`/api/v1/assets/${schematicId}/download`, request);
return response as { message: string };
},
// Get download status
status: async (schematicId: string): Promise<AssetStatusResponse> => {
const response = await apiClient.get(`/api/v1/assets/${schematicId}/status`);
return response as AssetStatusResponse;
},
// Get download URL for an asset (includes base URL for direct download)
getAssetUrl: (schematicId: string, assetType: 'kernel' | 'initramfs' | 'iso'): string => {
return `${API_BASE_URL}/api/v1/assets/${schematicId}/pxe/${assetType}`;
},
// Delete a schematic and all its assets
delete: async (schematicId: string): Promise<{ message: string }> => {
const response = await apiClient.delete(`/api/v1/assets/${schematicId}`);
return response as { message: string };
},
};

View File

@@ -0,0 +1,58 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { assetsApi } from '../assets';
import type { DownloadAssetRequest } from '../types/asset';
export function useAssetList() {
return useQuery({
queryKey: ['assets'],
queryFn: assetsApi.list,
});
}
export function useAsset(schematicId: string | null | undefined) {
return useQuery({
queryKey: ['assets', schematicId],
queryFn: () => assetsApi.get(schematicId!),
enabled: !!schematicId,
});
}
export function useAssetStatus(schematicId: string | null | undefined) {
return useQuery({
queryKey: ['assets', schematicId, 'status'],
queryFn: () => assetsApi.status(schematicId!),
enabled: !!schematicId,
refetchInterval: (query) => {
const data = query.state.data;
// Poll every 2 seconds if downloading
return data?.downloading ? 2000 : false;
},
});
}
export function useDownloadAsset() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ schematicId, request }: { schematicId: string; request: DownloadAssetRequest }) =>
assetsApi.download(schematicId, request),
onSuccess: (_, variables) => {
queryClient.invalidateQueries({ queryKey: ['assets'] });
queryClient.invalidateQueries({ queryKey: ['assets', variables.schematicId] });
queryClient.invalidateQueries({ queryKey: ['assets', variables.schematicId, 'status'] });
},
});
}
export function useDeleteAsset() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (schematicId: string) => assetsApi.delete(schematicId),
onSuccess: (_, schematicId) => {
queryClient.invalidateQueries({ queryKey: ['assets'] });
queryClient.invalidateQueries({ queryKey: ['assets', schematicId] });
queryClient.invalidateQueries({ queryKey: ['assets', schematicId, 'status'] });
},
});
}

View File

@@ -10,6 +10,7 @@ export { operationsApi } from './operations';
export { dnsmasqApi } from './dnsmasq';
export { utilitiesApi } from './utilities';
export { pxeApi } from './pxe';
export { assetsApi } from './assets';
// React Query hooks
export { useInstance, useInstanceOperations, useInstanceClusterHealth } from './hooks/useInstance';
@@ -17,3 +18,4 @@ export { useOperations, useOperation, useCancelOperation } from './hooks/useOper
export { useClusterHealth, useClusterStatus, useClusterNodes } from './hooks/useCluster';
export { useDashboardToken, useClusterVersions, useNodeIPs, useControlPlaneIP, useCopySecret } from './hooks/useUtilities';
export { usePxeAssets, useDownloadPxeAsset, useDeletePxeAsset } from './hooks/usePxeAssets';
export { useAssetList, useAsset, useAssetStatus, useDownloadAsset } from './hooks/useAssets';

View File

@@ -0,0 +1,38 @@
export type AssetType = 'kernel' | 'initramfs' | 'iso';
export type Platform = 'amd64' | 'arm64';
// Simplified Asset interface matching backend
export interface Asset {
type: string;
path: string;
size: number;
sha256: string;
downloaded: boolean;
}
// Schematic representation matching backend
export interface Schematic {
schematic_id: string;
version: string;
path: string;
assets: Asset[];
}
export interface AssetListResponse {
schematics: Schematic[];
}
export interface DownloadAssetRequest {
version: string;
platform?: Platform;
assets?: AssetType[];
force?: boolean;
}
// Simplified status response matching backend
export interface AssetStatusResponse {
schematic_id: string;
version: string;
assets: Record<string, Asset>;
complete: boolean;
}

View File

@@ -7,3 +7,4 @@ export * from './cluster';
export * from './app';
export * from './service';
export * from './pxe';
export * from './asset';