mirror of
https://github.com/strapi/strapi.git
synced 2025-12-29 16:16:20 +00:00
chore: making upload work with fetchClient
This commit is contained in:
parent
7899cd5db8
commit
8f75d1e78a
@ -1,3 +1,4 @@
|
||||
import axios from 'axios';
|
||||
import pipe from 'lodash/fp/pipe';
|
||||
import qs from 'qs';
|
||||
|
||||
@ -21,6 +22,7 @@ export type FetchOptions = {
|
||||
params?: any;
|
||||
signal?: AbortSignal;
|
||||
headers?: Record<string, string>;
|
||||
onUploadProgress?: (progressEvent: any) => void;
|
||||
};
|
||||
|
||||
export type FetchConfig = {
|
||||
@ -106,6 +108,9 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => {
|
||||
Authorization: `Bearer ${getToken()}`,
|
||||
};
|
||||
|
||||
const isFormDataRequest = (headers: Headers) =>
|
||||
headers.has('Content-Type') && headers.get('Content-Type') === 'multipart/form-data';
|
||||
|
||||
const addPrependingSlash = (url: string) => (url.charAt(0) !== '/' ? `/${url}` : url);
|
||||
|
||||
// This regular expression matches a string that starts with either "http://" or "https://" or any other protocol name in lower case letters, followed by "://" and ends with anything else
|
||||
@ -186,14 +191,26 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => {
|
||||
...defaultHeader,
|
||||
...options?.headers,
|
||||
});
|
||||
|
||||
const createRequestUrl = makeCreateRequestUrl(options);
|
||||
|
||||
// Todo: remove this and replace it with a native implementation
|
||||
if (isFormDataRequest(headers)) {
|
||||
return axios.post(createRequestUrl(url), data, {
|
||||
headers: {
|
||||
...defaultHeader,
|
||||
...options?.headers,
|
||||
},
|
||||
signal: options?.signal ?? defaultOptions.signal,
|
||||
onUploadProgress: options?.onUploadProgress,
|
||||
});
|
||||
}
|
||||
|
||||
const response = await fetch(createRequestUrl(url), {
|
||||
signal: options?.signal ?? defaultOptions.signal,
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: options?.headers?.['Content-Type'].includes('multipart/form-data')
|
||||
? data
|
||||
: JSON.stringify(data),
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
return responseInterceptor<TData>(response);
|
||||
},
|
||||
@ -208,13 +225,24 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => {
|
||||
});
|
||||
|
||||
const createRequestUrl = makeCreateRequestUrl(options);
|
||||
|
||||
// Todo: remove this and replace it with a native implementation
|
||||
if (isFormDataRequest(headers)) {
|
||||
return axios.post(createRequestUrl(url), data, {
|
||||
headers: {
|
||||
...defaultHeader,
|
||||
...options?.headers,
|
||||
},
|
||||
signal: options?.signal ?? defaultOptions.signal,
|
||||
onUploadProgress: options?.onUploadProgress,
|
||||
});
|
||||
}
|
||||
|
||||
const response = await fetch(createRequestUrl(url), {
|
||||
signal: options?.signal ?? defaultOptions.signal,
|
||||
method: 'PUT',
|
||||
headers,
|
||||
body: options?.headers?.['Content-Type'].includes('multipart/form-data')
|
||||
? data
|
||||
: JSON.stringify(data),
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
return responseInterceptor<TData>(response);
|
||||
|
||||
@ -131,7 +131,7 @@ describe('useRemoveAsset', () => {
|
||||
|
||||
await waitFor(() =>
|
||||
expect(toggleNotification).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ type: 'danger', message: 'Request failed with status code 500' })
|
||||
expect.objectContaining({ type: 'danger', message: 'Unexpected end of JSON input' })
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useNotification, useFetchClient } from '@strapi/admin/strapi-admin';
|
||||
import axios from 'axios';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
|
||||
import pluginId from '../pluginId';
|
||||
import { getTrad } from '../utils';
|
||||
|
||||
const editAssetRequest = (asset, file, cancelToken, onProgress, post) => {
|
||||
const editAssetRequest = (asset, file, signal, onProgress, post) => {
|
||||
const endpoint = `/${pluginId}?id=${asset.id}`;
|
||||
|
||||
const formData = new FormData();
|
||||
@ -28,7 +27,7 @@ const editAssetRequest = (asset, file, cancelToken, onProgress, post) => {
|
||||
);
|
||||
|
||||
return post(endpoint, formData, {
|
||||
cancelToken: cancelToken.token,
|
||||
signal,
|
||||
onUploadProgress({ total, loaded }) {
|
||||
onProgress((loaded / total) * 100);
|
||||
},
|
||||
@ -43,11 +42,12 @@ export const useEditAsset = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { toggleNotification } = useNotification();
|
||||
const queryClient = useQueryClient();
|
||||
const tokenRef = useRef(axios.CancelToken.source());
|
||||
const abortController = new AbortController();
|
||||
const signal = abortController.signal;
|
||||
const { post } = useFetchClient();
|
||||
|
||||
const mutation = useMutation(
|
||||
({ asset, file }) => editAssetRequest(asset, file, tokenRef.current, setProgress, post),
|
||||
({ asset, file }) => editAssetRequest(asset, file, signal, setProgress, post),
|
||||
{
|
||||
onSuccess() {
|
||||
queryClient.refetchQueries([pluginId, 'assets'], { active: true });
|
||||
@ -69,10 +69,7 @@ export const useEditAsset = () => {
|
||||
|
||||
const editAsset = (asset, file) => mutation.mutateAsync({ asset, file });
|
||||
|
||||
const cancel = () =>
|
||||
tokenRef.current.cancel(
|
||||
formatMessage({ id: getTrad('modal.upload.cancelled'), defaultMessage: '' })
|
||||
);
|
||||
const cancel = () => abortController.abort();
|
||||
|
||||
return { ...mutation, cancel, editAsset, progress, status: mutation.status };
|
||||
};
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
import { useRef, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useFetchClient } from '@strapi/admin/strapi-admin';
|
||||
import axios from 'axios';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useMutation, useQueryClient } from 'react-query';
|
||||
|
||||
import pluginId from '../pluginId';
|
||||
import { getTrad } from '../utils';
|
||||
|
||||
const endpoint = `/${pluginId}`;
|
||||
|
||||
const uploadAsset = (asset, folderId, cancelToken, onProgress, post) => {
|
||||
const uploadAsset = (asset, folderId, signal, onProgress, post) => {
|
||||
const { rawFile, caption, name, alternativeText } = asset;
|
||||
const formData = new FormData();
|
||||
|
||||
@ -30,7 +27,7 @@ const uploadAsset = (asset, folderId, cancelToken, onProgress, post) => {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
cancelToken: cancelToken.token,
|
||||
signal,
|
||||
onUploadProgress({ total, loaded }) {
|
||||
onProgress((loaded / total) * 100);
|
||||
},
|
||||
@ -39,14 +36,14 @@ const uploadAsset = (asset, folderId, cancelToken, onProgress, post) => {
|
||||
|
||||
export const useUpload = () => {
|
||||
const [progress, setProgress] = useState(0);
|
||||
const { formatMessage } = useIntl();
|
||||
const queryClient = useQueryClient();
|
||||
const tokenRef = useRef(axios.CancelToken.source());
|
||||
const abortController = new AbortController();
|
||||
const signal = abortController.signal;
|
||||
const { post } = useFetchClient();
|
||||
|
||||
const mutation = useMutation(
|
||||
({ asset, folderId }) => {
|
||||
return uploadAsset(asset, folderId, tokenRef.current, setProgress, post);
|
||||
return uploadAsset(asset, folderId, signal, setProgress, post);
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
@ -58,10 +55,7 @@ export const useUpload = () => {
|
||||
|
||||
const upload = (asset, folderId) => mutation.mutateAsync({ asset, folderId });
|
||||
|
||||
const cancel = () =>
|
||||
tokenRef.current.cancel(
|
||||
formatMessage({ id: getTrad('modal.upload.cancelled'), defaultMessage: '' })
|
||||
);
|
||||
const cancel = () => abortController.abort();
|
||||
|
||||
return {
|
||||
upload,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AxiosError, AxiosHeaders } from 'axios';
|
||||
import { FetchError } from '@strapi/admin/strapi-admin';
|
||||
|
||||
import getAPIInnerErrors from '../getAPIInnerErrors';
|
||||
|
||||
const API_VALIDATION_ERROR_FIXTURE = new AxiosError(undefined, undefined, undefined, undefined, {
|
||||
const API_VALIDATION_ERROR_FIXTURE = new FetchError('ValidationError', {
|
||||
data: {
|
||||
error: {
|
||||
name: 'ValidationError',
|
||||
@ -25,12 +25,9 @@ const API_VALIDATION_ERROR_FIXTURE = new AxiosError(undefined, undefined, undefi
|
||||
},
|
||||
},
|
||||
status: 422,
|
||||
statusText: 'Validation',
|
||||
headers: {},
|
||||
config: { headers: new AxiosHeaders() },
|
||||
});
|
||||
|
||||
const API_APPLICATION_ERROR_FIXTURE = new AxiosError(undefined, undefined, undefined, undefined, {
|
||||
const API_APPLICATION_ERROR_FIXTURE = new FetchError('ApplicationError', {
|
||||
data: {
|
||||
error: {
|
||||
name: 'ApplicationError',
|
||||
@ -39,9 +36,6 @@ const API_APPLICATION_ERROR_FIXTURE = new AxiosError(undefined, undefined, undef
|
||||
},
|
||||
},
|
||||
status: 400,
|
||||
statusText: 'Bad Request',
|
||||
headers: {},
|
||||
config: { headers: new AxiosHeaders() },
|
||||
});
|
||||
|
||||
describe('getAPIInnerError', () => {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AxiosError, AxiosHeaders } from 'axios';
|
||||
import { FetchError } from '@strapi/admin/strapi-admin';
|
||||
|
||||
import { normalizeAPIError } from '../normalizeAPIError';
|
||||
|
||||
const API_VALIDATION_ERROR_FIXTURE = new AxiosError(undefined, undefined, undefined, undefined, {
|
||||
const API_VALIDATION_ERROR_FIXTURE = new FetchError('ValidationError', {
|
||||
data: {
|
||||
error: {
|
||||
name: 'ValidationError',
|
||||
@ -25,12 +25,9 @@ const API_VALIDATION_ERROR_FIXTURE = new AxiosError(undefined, undefined, undefi
|
||||
},
|
||||
},
|
||||
status: 422,
|
||||
statusText: 'Validation',
|
||||
headers: {},
|
||||
config: { headers: new AxiosHeaders() },
|
||||
});
|
||||
|
||||
const API_APPLICATION_ERROR_FIXTURE = new AxiosError(undefined, undefined, undefined, undefined, {
|
||||
const API_APPLICATION_ERROR_FIXTURE = new FetchError('ApplicationError', {
|
||||
data: {
|
||||
error: {
|
||||
name: 'ApplicationError',
|
||||
@ -39,9 +36,6 @@ const API_APPLICATION_ERROR_FIXTURE = new AxiosError(undefined, undefined, undef
|
||||
},
|
||||
},
|
||||
status: 400,
|
||||
statusText: 'Bad Request',
|
||||
headers: {},
|
||||
config: { headers: new AxiosHeaders() },
|
||||
});
|
||||
|
||||
describe('normalizeAPIError', () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user