Files
portainer/app/react/docker/images/queries/useExportImageMutation.ts
T
2026-03-18 16:01:17 +13:00

72 lines
1.8 KiB
TypeScript

import { RawAxiosRequestHeaders } from 'axios';
import { useMutation } from '@tanstack/react-query';
import { saveAs } from 'file-saver';
import axios, { parseAxiosError } from '@/portainer/services/axios/axios';
import { EnvironmentId } from '@/react/portainer/environments/types';
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
import { buildDockerProxyUrl } from '../../proxy/queries/buildDockerProxyUrl';
export function useExportMutation() {
const environmentId = useEnvironmentId();
return useMutation({
mutationFn: (
args: Omit<Parameters<typeof exportImage>[0], 'environmentId'>
) => exportImage({ ...args, environmentId }),
});
}
export async function exportImage({
environmentId,
nodeName,
images,
}: {
environmentId: EnvironmentId;
nodeName?: string;
images: Array<{ tags?: Array<string>; id: string }>;
}) {
const { names } = getImagesNamesForDownload(images);
const headers: RawAxiosRequestHeaders = {};
if (nodeName) {
headers['X-PortainerAgent-Target'] = nodeName;
}
try {
const { headers: responseHeaders, data } = await axios.get(
buildDockerProxyUrl(environmentId, 'images', 'get'),
{
headers,
responseType: 'blob',
params: {
names,
},
}
);
const contentDispositionHeader =
responseHeaders['content-disposition'] || '';
const filename = contentDispositionHeader
.replace('attachment; filename=', '')
.trim();
saveAs(data, filename);
} catch (err) {
throw parseAxiosError(err as Error, 'Unable to export image');
}
}
export function getImagesNamesForDownload(
images: Array<{ tags?: Array<string>; id: string }>
) {
const names = images.map((image) =>
image.tags?.length && image.tags[0] !== '<none>:<none>'
? image.tags[0]
: image.id
);
return {
names,
};
}