mirror of
https://github.com/portainer/portainer.git
synced 2025-07-25 08:19:40 +02:00
134 lines
3.3 KiB
TypeScript
134 lines
3.3 KiB
TypeScript
import axiosOrigin, { AxiosError, AxiosRequestConfig } from 'axios';
|
|
import { loadProgressBar } from 'axios-progress-bar';
|
|
|
|
import 'axios-progress-bar/dist/nprogress.css';
|
|
import PortainerError from '@/portainer/error';
|
|
|
|
import {
|
|
portainerAgentManagerOperation,
|
|
portainerAgentTargetHeader,
|
|
} from './http-request.helper';
|
|
|
|
const axios = axiosOrigin.create({ baseURL: 'api' });
|
|
|
|
loadProgressBar(undefined, axios);
|
|
|
|
export default axios;
|
|
|
|
export const agentTargetHeader = 'X-PortainerAgent-Target';
|
|
|
|
export function agentInterceptor(config: AxiosRequestConfig) {
|
|
if (!config.url || !config.url.includes('/docker/')) {
|
|
return config;
|
|
}
|
|
|
|
const newConfig = { headers: config.headers || {}, ...config };
|
|
const target = portainerAgentTargetHeader();
|
|
if (target) {
|
|
newConfig.headers[agentTargetHeader] = target;
|
|
}
|
|
|
|
if (portainerAgentManagerOperation()) {
|
|
newConfig.headers['X-PortainerAgent-ManagerOperation'] = '1';
|
|
}
|
|
|
|
return newConfig;
|
|
}
|
|
|
|
axios.interceptors.request.use(agentInterceptor);
|
|
|
|
axios.interceptors.response.use(undefined, (error) => {
|
|
if (
|
|
error.response?.status === 401 &&
|
|
!error.config.url.includes('/v2/') &&
|
|
!error.config.url.includes('/api/v4/') &&
|
|
isTransitionRequiresAuthentication()
|
|
) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('Unauthorized request, logging out');
|
|
window.location.hash = '/logout';
|
|
window.location.reload();
|
|
}
|
|
|
|
return Promise.reject(error);
|
|
});
|
|
|
|
const UNAUTHENTICATED_ROUTES = [
|
|
'/logout',
|
|
'/internal-auth',
|
|
'/auth',
|
|
'/init/admin',
|
|
];
|
|
function isTransitionRequiresAuthentication() {
|
|
return !UNAUTHENTICATED_ROUTES.some((route) =>
|
|
window.location.hash.includes(route)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Parses an Axios error and returns a PortainerError.
|
|
* @param err The original error.
|
|
* @param msg An optional error message to prepend.
|
|
* @param parseError A function to parse AxiosErrors. Defaults to defaultErrorParser.
|
|
* @returns A PortainerError with the parsed error message and details.
|
|
*/
|
|
export function parseAxiosError(
|
|
err: unknown,
|
|
msg = '',
|
|
parseError = defaultErrorParser
|
|
) {
|
|
let resultErr = err;
|
|
let resultMsg = msg;
|
|
|
|
if (isAxiosError(err)) {
|
|
const { error, details } = parseError(err);
|
|
resultErr = error;
|
|
if (msg && details) {
|
|
resultMsg = `${msg}: ${details}`;
|
|
} else {
|
|
resultMsg = msg || details;
|
|
}
|
|
}
|
|
|
|
return new PortainerError(resultMsg, resultErr);
|
|
}
|
|
|
|
export function defaultErrorParser(axiosError: AxiosError) {
|
|
const message = axiosError.response?.data.message || '';
|
|
const details = axiosError.response?.data.details || message;
|
|
const error = new Error(message);
|
|
return { error, details };
|
|
}
|
|
|
|
export function isAxiosError<
|
|
ResponseType = { message: string; details: string },
|
|
>(error: unknown): error is AxiosError<ResponseType> {
|
|
return axiosOrigin.isAxiosError(error);
|
|
}
|
|
|
|
export function arrayToJson<T>(arr?: Array<T>) {
|
|
if (!arr) {
|
|
return '';
|
|
}
|
|
|
|
return JSON.stringify(arr);
|
|
}
|
|
|
|
export function json2formData(json: Record<string, unknown>) {
|
|
const formData = new FormData();
|
|
|
|
Object.entries(json).forEach(([key, value]) => {
|
|
if (typeof value === 'undefined' || value === null) {
|
|
return;
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
formData.append(key, arrayToJson(value));
|
|
return;
|
|
}
|
|
|
|
formData.append(key, value as string);
|
|
});
|
|
|
|
return formData;
|
|
}
|