mirror of
https://github.com/directus/directus.git
synced 2026-01-30 00:37:55 -05:00
* Remove advanced filter sidebar detail So long, and thanks for all the fish. * Remove filter conversion logic * Start replacing/removing old skool filters * Add inline mode for usages in search bar * Make filter work in header bar * Emit empty string as null in filter * Move shared filter types to shared * Upgrade use-items * Fix manual sort on tabular * Cleanup styling in search bar usage * Tweak styling * Fix filtering issues * Update cards * Remove activeFilterCount from tabular * Update maps to work with new filters * Update calendar to new filter/sort structure * Fix activity module nav/search * Fix no-results message * Update file library filtering * Finalize user search * Allow filtering in drawer-collection * Handle cancelled responses semi-gracefully * Add loading start state timeout * Replace sort type in api * Last commit before redoing a bunch * Finish new visual style * Remove unused rounded prop from v-menu * Tweak sizing * Enough size tweaking for now * Count all filter operators instead of top * Fix archive casting * Fix api build * Add merge filters util * Split filter in user vs system * Fix export sidebar detail * Show field label on permissions configuration * Add migration for filter/sort * Use filters in insights
110 lines
3.0 KiB
TypeScript
110 lines
3.0 KiB
TypeScript
import { logout, LogoutReason, refresh } from '@/auth';
|
|
import { useRequestsStore } from '@/stores/';
|
|
import { getRootPath } from '@/utils/get-root-path';
|
|
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
import { addQueryToPath } from './utils/add-query-to-path';
|
|
import PQueue from 'p-queue';
|
|
|
|
const api = axios.create({
|
|
baseURL: getRootPath(),
|
|
withCredentials: true,
|
|
headers: {
|
|
'Cache-Control': 'no-store',
|
|
},
|
|
});
|
|
|
|
const queue = new PQueue({ concurrency: 5, intervalCap: 5, interval: 500, carryoverConcurrencyCount: true });
|
|
|
|
interface RequestConfig extends AxiosRequestConfig {
|
|
id: string;
|
|
}
|
|
|
|
interface Response extends AxiosResponse {
|
|
config: RequestConfig;
|
|
}
|
|
|
|
export interface RequestError extends AxiosError {
|
|
response: Response;
|
|
}
|
|
|
|
export const onRequest = (config: AxiosRequestConfig): Promise<RequestConfig> => {
|
|
const requestsStore = useRequestsStore();
|
|
const id = requestsStore.startRequest();
|
|
|
|
const requestConfig: RequestConfig = {
|
|
id: id,
|
|
...config,
|
|
};
|
|
|
|
return new Promise((resolve) => {
|
|
queue.add(() => resolve(requestConfig));
|
|
});
|
|
};
|
|
|
|
export const onResponse = (response: AxiosResponse | Response): AxiosResponse | Response => {
|
|
const requestsStore = useRequestsStore();
|
|
const id = (response.config as RequestConfig)?.id;
|
|
if (id) requestsStore.endRequest(id);
|
|
return response;
|
|
};
|
|
|
|
export const onError = async (error: RequestError): Promise<RequestError> => {
|
|
const requestsStore = useRequestsStore();
|
|
|
|
// Note: Cancelled requests don't respond with the config
|
|
const id = (error.response?.config as RequestConfig)?.id;
|
|
|
|
if (id) requestsStore.endRequest(id);
|
|
|
|
// If a request fails with the unauthorized error, it either means that your user doesn't have
|
|
// access, or that your session doesn't exist / has expired.
|
|
// In case of the second, we should force the app to logout completely and redirect to the login
|
|
// view.
|
|
const status = error.response?.status;
|
|
const code = error.response?.data?.errors?.[0]?.extensions?.code;
|
|
|
|
if (
|
|
status === 401 &&
|
|
code === 'INVALID_CREDENTIALS' &&
|
|
error.request.responseURL.includes('refresh') === false &&
|
|
error.request.responseURL.includes('login') === false &&
|
|
error.request.responseURL.includes('tfa') === false
|
|
) {
|
|
let newToken: string | undefined;
|
|
|
|
try {
|
|
newToken = await refresh();
|
|
} catch {
|
|
logout({ reason: LogoutReason.SESSION_EXPIRED });
|
|
return Promise.reject();
|
|
}
|
|
|
|
if (newToken) {
|
|
return api.request({
|
|
...error.config,
|
|
headers: {
|
|
Authorization: `Bearer ${newToken}`,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
return Promise.reject(error);
|
|
};
|
|
|
|
api.interceptors.request.use(onRequest);
|
|
api.interceptors.response.use(onResponse, onError);
|
|
|
|
export default api;
|
|
|
|
export function getToken(): string | null {
|
|
return api.defaults.headers?.['Authorization']?.split(' ')[1] || null;
|
|
}
|
|
|
|
export function addTokenToURL(url: string, token?: string): string {
|
|
const accessToken = token || getToken();
|
|
if (!accessToken) return url;
|
|
|
|
return addQueryToPath(url, { access_token: accessToken });
|
|
}
|