Skip to content

Commit 92e7943

Browse files
authored
refactor: rm transformFile (#299)
* reafactor: rm transformFile * clean up * add runtime for jest * test: Delay test * fix lint * fix compile
1 parent 653a094 commit 92e7943

File tree

12 files changed

+208
-213
lines changed

12 files changed

+208
-213
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ React.render(<Upload />, container);
7676
|customRequest | function | null | provide an override for the default xhr behavior for additional customization|
7777
|withCredentials | boolean | false | ajax upload with cookie send |
7878
|openFileDialogOnClick | boolean | true | useful for drag only upload as it does not trigger on enter key or click event |
79-
|transformFile | function(file): Promise&lt;blob&gt; | | transform file before request |
8079

8180
#### onError arguments
8281

docs/demo/transformFile.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

docs/examples/transformFile.tsx

Lines changed: 0 additions & 59 deletions
This file was deleted.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"now-build": "npm run docs:build"
3838
},
3939
"devDependencies": {
40-
"@types/jest": "^26.0.0",
40+
"@types/enzyme": "^3.10.8",
41+
"@types/jest": "^26.0.20",
4142
"@types/react": "^16.9.2",
4243
"@types/react-dom": "^16.9.0",
4344
"@umijs/fabric": "^2.0.0",
@@ -58,6 +59,7 @@
5859
"rc-tools": "8.x",
5960
"react": "^16.0.0",
6061
"react-dom": "^16.0.0",
62+
"regenerator-runtime": "^0.13.7",
6163
"sinon": "^9.0.2",
6264
"typescript": "^4.0.2",
6365
"vinyl-fs": "^3.0.3"

src/AjaxUploader.tsx

Lines changed: 95 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
/* eslint react/no-is-mounted:0,react/sort-comp:0,react/prop-types:0 */
2-
import React, { Component, ReactElement } from 'react';
2+
import type { ReactElement } from 'react';
3+
import React, { Component } from 'react';
34
import classNames from 'classnames';
45
import pickAttrs from 'rc-util/lib/pickAttrs';
56
import defaultRequest from './request';
67
import getUid from './uid';
78
import attrAccept from './attr-accept';
89
import traverseFileTree from './traverseFileTree';
9-
import { UploadProps, UploadProgressEvent, UploadRequestError, RcFile, Action } from './interface';
10+
import type { UploadProps, UploadProgressEvent, UploadRequestError, RcFile } from './interface';
11+
12+
interface ParsedFileInfo {
13+
origin: RcFile;
14+
action: string;
15+
data: object;
16+
parsedFile: File | Blob | null;
17+
}
1018

1119
class AjaxUploader extends Component<UploadProps> {
1220
state = { uid: getUid() };
@@ -84,106 +92,105 @@ class AjaxUploader extends Component<UploadProps> {
8492
}
8593

8694
uploadFiles = (files: FileList) => {
87-
const postFiles: Array<RcFile> = Array.prototype.slice.call(files);
88-
postFiles
89-
.map((file: RcFile & { uid?: string }) => {
90-
// eslint-disable-next-line no-param-reassign
91-
file.uid = getUid();
92-
return file;
93-
})
94-
.forEach(file => {
95-
this.upload(file, postFiles);
96-
});
97-
};
95+
const originFiles = [...files] as RcFile[];
96+
const postFiles = originFiles.map((file: RcFile & { uid?: string }) => {
97+
// eslint-disable-next-line no-param-reassign
98+
file.uid = getUid();
99+
return this.processFile(file, originFiles);
100+
});
98101

99-
upload(file: RcFile, fileList: Array<RcFile>) {
100-
const { props } = this;
101-
if (!props.beforeUpload) {
102-
// always async in case use react state to keep fileList
103-
Promise.resolve().then(() => {
102+
// Batch upload files
103+
Promise.all(postFiles).then(fileList => {
104+
const { onBatchStart } = this.props;
105+
const enabledFiles = fileList.filter(file => file);
106+
107+
onBatchStart?.(enabledFiles.map(file => file.origin));
108+
109+
enabledFiles.forEach(file => {
104110
this.post(file);
105111
});
106-
return;
112+
});
113+
};
114+
115+
/**
116+
* Process file before upload. When all the file is ready, we start upload.
117+
*/
118+
processFile = async (file: RcFile, fileList: RcFile[]): Promise<ParsedFileInfo> => {
119+
const { beforeUpload, action, data } = this.props;
120+
121+
let transformedFile: boolean | File | Blob | void = file;
122+
if (beforeUpload) {
123+
transformedFile = await beforeUpload(file, fileList);
124+
if (transformedFile === false) {
125+
return null;
126+
}
107127
}
108128

109-
const before = props.beforeUpload(file, fileList);
110-
if (before && typeof before !== 'boolean' && before.then) {
111-
before
112-
.then(processedFile => {
113-
const processedFileType = Object.prototype.toString.call(processedFile);
114-
if (processedFileType === '[object File]' || processedFileType === '[object Blob]') {
115-
this.post(processedFile as RcFile);
116-
return;
117-
}
118-
this.post(file);
119-
})
120-
.catch(e => {
121-
// eslint-disable-next-line no-console
122-
console.log(e);
123-
});
124-
} else if (before !== false) {
125-
Promise.resolve().then(() => {
126-
this.post(file);
127-
});
129+
let mergedAction: string;
130+
if (typeof action === 'function') {
131+
mergedAction = await action(file);
132+
} else {
133+
mergedAction = action;
128134
}
129-
}
130135

131-
post(file: RcFile) {
136+
let mergedData: object;
137+
if (typeof data === 'function') {
138+
mergedData = await data(file);
139+
} else {
140+
mergedData = data;
141+
}
142+
143+
const parsedFile =
144+
typeof transformedFile === 'object' && transformedFile ? transformedFile : file;
145+
146+
// Used for `request.ts` get form data name
147+
if (!(parsedFile as any).name) {
148+
(parsedFile as any).name = file.name;
149+
}
150+
151+
return {
152+
origin: file,
153+
data: mergedData,
154+
parsedFile,
155+
action: mergedAction,
156+
};
157+
};
158+
159+
post({ data, origin, action, parsedFile }: ParsedFileInfo) {
132160
if (!this._isMounted) {
133161
return;
134162
}
135163
const { props } = this;
136-
const { onStart, onProgress, transformFile = originFile => originFile } = props;
164+
const { onStart, onProgress } = props;
137165

138-
new Promise(resolve => {
139-
let actionRet: Action | PromiseLike<string> = props.action;
140-
if (typeof actionRet === 'function') {
141-
actionRet = actionRet(file);
142-
}
143-
return resolve(actionRet);
144-
}).then((action: string) => {
145-
const { uid } = file;
146-
const request = props.customRequest || defaultRequest;
147-
const transform = Promise.resolve(transformFile(file))
148-
.then(transformedFile => {
149-
let { data } = props;
150-
if (typeof data === 'function') {
151-
data = data(transformedFile);
166+
const { uid } = origin;
167+
const request = props.customRequest || defaultRequest;
168+
169+
const requestOption = {
170+
action,
171+
filename: props.name,
172+
data,
173+
file: parsedFile,
174+
headers: props.headers,
175+
withCredentials: props.withCredentials,
176+
method: props.method || 'post',
177+
onProgress: onProgress
178+
? (e: UploadProgressEvent) => {
179+
onProgress(e, origin);
152180
}
153-
return Promise.all([transformedFile, data]);
154-
})
155-
.catch(e => {
156-
console.error(e); // eslint-disable-line no-console
157-
});
158-
159-
transform.then(([transformedFile, data]: [RcFile, object]) => {
160-
const requestOption = {
161-
action,
162-
filename: props.name,
163-
data,
164-
file: transformedFile,
165-
headers: props.headers,
166-
withCredentials: props.withCredentials,
167-
method: props.method || 'post',
168-
onProgress: onProgress
169-
? (e: UploadProgressEvent) => {
170-
onProgress(e, file);
171-
}
172-
: null,
173-
onSuccess: (ret: any, xhr: XMLHttpRequest) => {
174-
delete this.reqs[uid];
175-
props.onSuccess(ret, file, xhr);
176-
},
177-
onError: (err: UploadRequestError, ret: any) => {
178-
delete this.reqs[uid];
179-
props.onError(err, ret, file);
180-
},
181-
};
181+
: null,
182+
onSuccess: (ret: any, xhr: XMLHttpRequest) => {
183+
delete this.reqs[uid];
184+
props.onSuccess(ret, origin, xhr);
185+
},
186+
onError: (err: UploadRequestError, ret: any) => {
187+
delete this.reqs[uid];
188+
props.onError(err, ret, origin);
189+
},
190+
};
182191

183-
onStart(file);
184-
this.reqs[uid] = request(requestOption);
185-
});
186-
});
192+
onStart(origin);
193+
this.reqs[uid] = request(requestOption);
187194
}
188195

189196
reset() {

src/Upload.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint react/prop-types:0 */
22
import React, { Component } from 'react';
33
import AjaxUpload from './AjaxUploader';
4-
import { UploadProps, RcFile } from './interface';
4+
import type { UploadProps, RcFile } from './interface';
55

66
function empty() {}
77

src/attr-accept.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { RcFile } from './interface';
1+
import type { RcFile } from './interface';
22

33
function endsWith(str: string, suffix: string) {
44
return str.indexOf(suffix, str.length - suffix.length) !== -1;
55
}
66

7-
export default (file: RcFile, acceptedFiles: string | Array<string>) => {
7+
export default (file: RcFile, acceptedFiles: string | string[]) => {
88
if (file && acceptedFiles) {
99
const acceptedFilesArray = Array.isArray(acceptedFiles)
1010
? acceptedFiles

src/interface.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as React from 'react';
1+
import type * as React from 'react';
22

33
export type Action = string | ((file: RcFile) => string | PromiseLike<string>);
44

@@ -16,6 +16,7 @@ export interface UploadProps
1616
headers?: UploadRequestHeader;
1717
accept?: string;
1818
multiple?: boolean;
19+
onBatchStart?: (fileList: RcFile[]) => void;
1920
onStart?: (file: RcFile) => void;
2021
onError?: (error: Error, ret: object, file: RcFile) => void;
2122
onSuccess?: (response: object, file: RcFile, xhr: object) => void;
@@ -24,7 +25,6 @@ export interface UploadProps
2425
customRequest?: (option: UploadRequestOption) => void;
2526
withCredentials?: boolean;
2627
openFileDialogOnClick?: boolean;
27-
transformFile?: (file: RcFile) => string | Blob | RcFile | PromiseLike<string | Blob | RcFile>;
2828
prefixCls?: string;
2929
id?: string;
3030
onMouseEnter?: (e: React.MouseEvent<HTMLDivElement>) => void;
@@ -38,9 +38,7 @@ export interface UploadProgressEvent extends ProgressEvent {
3838

3939
export type UploadRequestMethod = 'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch';
4040

41-
export interface UploadRequestHeader {
42-
[key: string]: string;
43-
}
41+
export type UploadRequestHeader = Record<string, string>;
4442

4543
export interface UploadRequestError extends Error {
4644
status?: number;
@@ -54,7 +52,7 @@ export interface UploadRequestOption<T = any> {
5452
onSuccess?: (body: T, xhr: XMLHttpRequest) => void;
5553
data?: object;
5654
filename?: string;
57-
file: RcFile;
55+
file: RcFile | Blob;
5856
withCredentials?: boolean;
5957
action: string;
6058
headers?: UploadRequestHeader;

src/request.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { UploadRequestOption, UploadRequestError, UploadProgressEvent } from './interface';
1+
import type { UploadRequestOption, UploadRequestError, UploadProgressEvent } from './interface';
22

33
function getError(option: UploadRequestOption, xhr: XMLHttpRequest) {
44
const msg = `cannot ${option.method} ${option.action} ${xhr.status}'`;
@@ -57,7 +57,7 @@ export default function upload(option: UploadRequestOption) {
5757

5858
// eslint-disable-next-line no-undef
5959
if (option.file instanceof Blob) {
60-
formData.append(option.filename, option.file, option.file.name);
60+
formData.append(option.filename, option.file, (option.file as any).name);
6161
} else {
6262
formData.append(option.filename, option.file);
6363
}

0 commit comments

Comments
 (0)