antd#Upload TypeScript Examples

The following examples show how to use antd#Upload. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: DataImporter.tsx    From condo with MIT License 6 votes vote down vote up
DataImporter: React.FC<IDataImporterProps> = (props) => {
    const uploadConfig = useUploadConfig(props.onUpload)

    return (
        <Upload
            { ...uploadConfig }
            accept={FILE_EXTENSIONS}
        >
            {props.children}
        </Upload>
    )
}
Example #2
Source File: InputWithUpload.tsx    From jitsu with MIT License 6 votes vote down vote up
InputWithUpload: React.FC<InputWithUploadProps> = ({ value, onChange }) => {
  const triggerChange = e => {
    onChange?.(e.target.value)
  }

  const beforeUpload = file => {
    const reader = new FileReader()

    reader.onload = e => {
      const content: string = e.target.result as string
      onChange?.(content)
    }
    reader.readAsText(file)

    // Prevent upload
    return false
  }

  return value === "" ? (
    <Upload showUploadList={true} beforeUpload={beforeUpload}>
      <Button icon={<UploadOutlined />}>Click to Upload</Button>
    </Upload>
  ) : (
    <Input.TextArea autoSize={{ minRows: 1, maxRows: 5 }} value={value} autoComplete="off" onChange={triggerChange} />
  )
}
Example #3
Source File: index.tsx    From imove with MIT License 6 votes vote down vote up
ImportDSL: React.FC<IProps> = (props) => {
  const { flowChart } = props;
  const [disabled, setDisabled] = useState(false);
  const beforeUpload = (file: any) => {
    setDisabled(true);
    const reader = new FileReader();
    reader.onload = (evt) => {
      setDisabled(false);
      if (!evt.target) {
        message.error('加载文件失败!');
      } else {
        const dsl = evt.target.result as string;
        try {
          flowChart.fromJSON(JSON.parse(dsl));
        } catch (err) {
          message.error('DSL解析失败!');
        }
      }
    };
    reader.readAsText(file);
    return false;
  };

  return (
    <Upload
      className={styles.container}
      accept={'.json'}
      disabled={disabled}
      showUploadList={false}
      beforeUpload={beforeUpload}
    >
      <Button type={'primary'} size={'small'}>
        导入DSL
      </Button>
    </Upload>
  );
}
Example #4
Source File: index.tsx    From scorpio-h5-design with MIT License 6 votes vote down vote up
export default function() {
  useEffect(()=>{
    //
  }, []);
  const props = {
    name: 'file',
    async onChange(info: any) {
      if (info.file.status === 'done') {
        message.success(`${info.file.name} file uploaded successfully`);
        const uploadResult = await ossClient.put(`design/${info.file.name}`, info.file.originFileObj);
      } else if (info.file.status === 'error') {
        message.error(`${info.file.name} file upload failed.`);
      }
    },
  };
  return (
    <Upload {...props} className="aliyun-upload">
      <Button icon={<UploadOutlined />}>上传</Button>
    </Upload>
  );
}
Example #5
Source File: index.tsx    From whiteboard-demo with MIT License 6 votes vote down vote up
private renderUploadImage(): React.ReactNode {
        return (
            <Upload
                key="upload-image"
                accept={"image/*"}
                showUploadList={false}
                customRequest={this.uploadImage}>
                <div className="oss-upload-section">
                    <div className="oss-upload-section-inner">
                        <div className="oss-upload-title-section">
                            <div className="oss-upload-title">{this.translate(this.props.i18nLanguage, 'uploadImage')}</div>
                            <div className="oss-upload-icon">
                                <img src={image} alt={"image"} />
                            </div>
                        </div>
                        <div className="oss-upload-section-script">
                            <div className="oss-upload-section-text">
                                {this.translate(this.props.i18nLanguage, 'uploadImageInner')}
                            </div>
                        </div>
                    </div>
                </div>
            </Upload>
        )
    }
Example #6
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
UploadComp = ({ form, onChangeFile, fileNameKey, fileAccept }: IUploadProps) => {
  const acceptProp = { accept: fileAccept };
  const uploadProps = getUploadProps({
    ...acceptProp,
    data: {
      fileFrom: 'certificate manager',
    },
    onChange: ({ file }: any) => {
      if (file.response) {
        const { success, err, data } = file.response;
        if (!success) {
          message.error(err.msg);
        } else {
          onChangeFile({ uuid: data.uuid, fileName: data.name });
        }
      }
      return file;
    },
  });
  const deleteFile = () => {
    onChangeFile({ uuid: undefined, fileName: undefined });
  };
  const fileName = form.getFieldValue(fileNameKey);
  return (
    <div className="upload-container">
      <Upload {...uploadProps}>
        <Button className="flex items-center">
          <ErdaIcon type="upload" size="16" className="mr-1" /> {i18n.t('Upload')}
        </Button>
      </Upload>
      {fileName && (
        <div className="flex justify-between items-center upload-file-item nowrap">
          <span>{fileName}</span>
          <CustomIcon type="thin-del" className="hover-active" onClick={deleteFile} />
        </div>
      )}
    </div>
  );
}
Example #7
Source File: index.tsx    From whiteboard-demo with MIT License 6 votes vote down vote up
private renderUploadAudio(): React.ReactNode {
        return (
            <Upload
                key="upload-audio"
                accept={".mp3,audio/mp3"}
                showUploadList={false}
                customRequest={this.uploadAudio}>
                <div className="oss-upload-section">
                    <div className="oss-upload-section-inner">
                        <div className="oss-upload-title-section">
                            <div className="oss-upload-title">{this.translate(this.props.i18nLanguage, 'uploadAudio')}</div>
                            <div className="oss-upload-icon">
                                <img src={Audio} alt={"Audio"} />
                            </div>
                        </div>
                        <div className="oss-upload-section-script">
                            <div className="oss-upload-section-text">{this.translate(this.props.i18nLanguage, 'uploadAudioInner')}</div>
                        </div>
                    </div>
                </div>
            </Upload>
        );
    }
Example #8
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
renderPureUploadItem(uploadText: string, queryData: any) {
    return (
      <div className="image-upload mr-2 mb-2" key="upload">
        <Input type="hidden" />
        <Upload className="pure-upload" accept=".jpg, .jpeg, .png, .gif" {...this.getUploadProps(queryData)}>
          <div className="mt-5">
            <ErdaIcon fill="black-8" size="30" key="icon" type="cir-add" />
            <div key="text">{uploadText}</div>
          </div>
        </Upload>
      </div>
    );
  }
Example #9
Source File: AvatarUpload.spec.tsx    From next-basics with GNU General Public License v3.0 6 votes vote down vote up
describe("AvatarUpload", () => {
  it("should work", () => {
    const wrapper = mount(<AvatarUpload {...props} />);
    // wrapper.find("Button").simulate("click")
    wrapper.find(Upload).invoke("beforeUpload")(
      {
        uid: "123",
        size: 1024 * 1024 * 1024,
      } as any,
      []
    );
  });

  it("should work", async () => {
    // mockCanvas(global)
    const wrapper = mount(<AvatarUpload {...props} imgSrc="mock" />);
    // wrapper.find("Button").simulate("click")
    const file = new File(["(⌐□_□)"], "chucknorris.png", { type: "image/png" });
    wrapper.find(Upload).invoke("beforeUpload")(file as any, []);
    await (global as any).flushPromises();
    expect(wrapper.find(Modal).prop("visible")).toBe(true);
    wrapper.find(Modal).invoke("onOk")({} as any);

    // Todo(momo): make assertions.
    // expect(mockHttp).toHaveBeenCalled();
  });
});
Example #10
Source File: UploadField.tsx    From posthog-foss with MIT License 6 votes vote down vote up
export function UploadField({
    value,
    onChange,
}: {
    value?: UploadFile | null
    onChange?: (file?: UploadFile | null) => void
}): JSX.Element {
    return (
        <Upload
            multiple={false}
            fileList={value?.size ? [value] : []}
            beforeUpload={(file) => {
                onChange?.(file)
                return false
            }}
            onRemove={() => {
                onChange?.(null)
                return false
            }}
            className="ph-ignore-input"
        >
            <Button icon={<UploadOutlined />}>Click to upload</Button>
        </Upload>
    )
}
Example #11
Source File: ImageUpload.tsx    From datart with Apache License 2.0 6 votes vote down vote up
StyleUpload = styled(Upload.Dragger)`
  .image-box {
    position: relative;
    padding: 0 ${SPACE_MD};
    margin: auto;
    overflow: hidden;
  }

  .del-button {
    position: absolute;
    top: 50%;
    left: 50%;
    display: none;
    font-size: 1.5rem;
    color: ${p => p.theme.textColorDisabled};
    transform: translate(-50%, -50%);
  }

  .image-box:hover .del-button {
    display: block;
  }

  .image {
    width: 100%;
    height: auto;
  }
`
Example #12
Source File: utils.tsx    From antdp with MIT License 6 votes vote down vote up
getItem = ({ attr, type, inputNode }: {
  attr?: Partial<ItemChildAttr<any, any>>;
  type?: ItemChildType;
  inputNode?: ((...arg: any[]) => React.ReactNode) | React.ReactNode;
}) => {
  let renderItem = undefined;
  if (type === 'Input') {
    const inputAttr = attr as InputProps;
    renderItem = <Input {...inputAttr} />;
  } else if (type === 'TextArea') {
    const inputAttr = attr as TextAreaProps;
    renderItem = <Input.TextArea {...inputAttr} />;
  } else if (type === 'InputNumber') {
    const inputAttr = attr as InputNumberProps;
    renderItem = <InputNumber {...inputAttr} />;
  } else if (type === 'AutoComplete') {
    const inputAttr = attr as AutoCompleteProps;
    renderItem = <AutoComplete {...inputAttr} />;
  } else if (type === 'Cascader') {
    const inputAttr = attr as CascaderProps;
    renderItem = <Cascader {...inputAttr} />;
  } else if (type === 'DatePicker') {
    const inputAttr = attr as DatePickerProps;
    renderItem = <DatePicker {...inputAttr} />;
  } else if (type === 'Rate') {
    const inputAttr = attr as RateProps;
    renderItem = <Rate {...inputAttr} />;
  } else if (type === 'Slider') {
    const inputAttr = attr as SliderSingleProps;
    renderItem = <Slider {...inputAttr} />;
  } else if (type === 'TreeSelect') {
    const inputAttr = attr as TreeSelectProps<any>;
    renderItem = <TreeSelect {...inputAttr} />;
  } else if (type === 'Select') {
    const inputAttr = attr as SelectProps<any>;
    renderItem = <Select {...inputAttr} />;
  } else if (type === 'Checkbox') {
    const inputAttr = attr as CheckboxGroupProps;
    renderItem = <Checkbox.Group {...inputAttr} />;
  } else if (type === 'Mentions') {
    const inputAttr = attr as MentionProps;
    renderItem = <Mentions {...inputAttr} />;
  } else if (type === 'Radio') {
    const inputAttr = attr as RadioProps;
    renderItem = <Radio.Group {...inputAttr} />;
  } else if (type === 'Switch') {
    const inputAttr = attr as SwitchProps;
    renderItem = <Switch {...inputAttr} />;
  } else if (type === 'TimePicker') {
    const inputAttr = attr as TimePickerProps;
    renderItem = <TimePicker {...inputAttr} />;
  } else if (type === 'Upload') {
    const inputAttr = attr as UploadProps;
    renderItem = <Upload {...inputAttr} />;
  } else if (type === 'RangePicker') {
    const inputAttr = attr as RangePickerProps;
    renderItem = <RangePicker {...inputAttr} />;
  } else if (type === 'Custom') {
    renderItem = inputNode;
  }
  return renderItem;
}
Example #13
Source File: MultipleFilesForm.tsx    From next-basics with GNU General Public License v3.0 6 votes vote down vote up
export function LegacyMultipleFilesForm(
  { fieldList, onFinish, onFinishFailed }: MultipleFilesFormProps,
  ref: React.Ref<FormInstance>
): React.ReactElement {
  const [form] = Form.useForm();

  useImperativeHandle(ref, () => form);

  const handleFinish = (data: UploadFormData): void => {
    const formData = processFileData(data);
    onFinish?.(formData);
  };

  return (
    <Form
      form={form}
      name="filesForm"
      data-testid="files-form"
      onFinish={handleFinish}
      onFinishFailed={onFinishFailed}
    >
      {fieldList?.map((item) => (
        <Form.Item key={item.name} name={item.name} label={item.name}>
          <Upload
            maxCount={isMultipleFiles(item.type) ? null : 1}
            beforeUpload={() => false}
          >
            <Button icon={<UploadOutlined />}>upload</Button>
          </Upload>
        </Form.Item>
      ))}
    </Form>
  );
}
Example #14
Source File: inputUtil.tsx    From yakit with GNU Affero General Public License v3.0 5 votes vote down vote up
InputFileNameItem: React.FC<InputFileNameItem> = p => {
    const [uploadLoading, setUploadLoading] = useState(false);
    return <Item>
        <Upload.Dragger
            className='targets-upload-dragger'
            accept={(p.accept || [])?.join(",")}
            multiple={false}
            maxCount={1}
            showUploadList={false}
            beforeUpload={(f: any) => {
                // 设置名字
                p.setFileName && p.setFileName(f?.path)
                if (!p.loadContent) {
                    return false
                }

                setUploadLoading(true)
                ipcRenderer.invoke("fetch-file-content", (f as any).path).then((res) => {
                    p.setContent && p.setContent(res)
                    setTimeout(() => {
                        setUploadLoading(false)
                    }, 100);
                })
                return false
            }}>
            <Spin spinning={uploadLoading}>
                {p.loadContent ? <InputItem
                    label={p.label} setValue={Targets => p.setContent && p.setContent(Targets)}
                    value={p.content} textarea={true} textareaRow={6}
                    placeholder="请输入绝对路径"
                    isBubbing={true}
                    help={p.hint ? p.hint : (<div>
                        可将文件拖入框内或<span style={{color: 'rgb(25,143,255)'}}>点击此处</span>上传
                    </div>)}
                /> : <InputItem
                    label={p.label} value={p.filename} setValue={f => p.setFileName && p.setFileName(f)}
                    placeholder="请输入绝对路径"
                    isBubbing={true} allowClear={false} help={p.hint ? p.hint : (<div>
                    可将文件拖入框内或<span style={{color: 'rgb(25,143,255)'}}>点击此处</span>上传
                </div>)}
                />
                }

            </Spin>
        </Upload.Dragger>
    </Item>
}
Example #15
Source File: index.tsx    From scorpio-h5-design with MIT License 5 votes vote down vote up
export default function ImageUpload(props: IProps) {
  const { value, onChange } = props;
  const handleDelete = function(){
    onChange('');
  };

  const uploadButton = (
    <div>
      <PlusOutlined />
      <div style={{ marginTop: 8 }}>Upload</div>
    </div>
  );

  const customRequest = async function(options:any){
    const fileName = `${uuidv4()}.png`;
    await ossClient.put(`design/${fileName}`, options.file);
    onChange(`https://scorpio-design.lxzyl.cn/design/${fileName}`);
    options.onSuccess(null, options.file);
  };

  return (
    <div className="picture-uploader">
      <Upload
        listType="picture-card"
        showUploadList={false}
        // onChange={handleChange}
        customRequest={customRequest}
      >
        {value ? (
          <div className="picture-uploader-img-container">
            <img src={value} alt="avatar" style={{ width: '100%' }} />
          </div>
        ) : uploadButton}
      </Upload>
      {
        value && <div className="delete-img" onClick={handleDelete}><CloseOutlined /></div>
      }
    </div>

  );
}
Example #16
Source File: index.tsx    From metaplex with Apache License 2.0 5 votes vote down vote up
{ Dragger } = Upload
Example #17
Source File: FormItemUtil.tsx    From yakit with GNU Affero General Public License v3.0 5 votes vote down vote up
{Dragger} = Upload
Example #18
Source File: index.tsx    From nebula-studio with Apache License 2.0 5 votes vote down vote up
{ Dragger } = Upload
Example #19
Source File: FileUpload.tsx    From datart with Apache License 2.0 5 votes vote down vote up
export function FileUpload({
  form,
  sourceId,
  loading,
  onTest,
}: FileUploadProps) {
  const [uploadFileLoading, setUploadFileLoading] = useState(false);
  const t = useI18NPrefix('source');

  const normFile = useCallback(e => {
    if (Array.isArray(e)) {
      return e;
    }
    return e && e.fileList;
  }, []);

  const uploadChange = useCallback(
    async ({ file }) => {
      if (file.status === 'done') {
        const format = file.name
          .substr(file.name.lastIndexOf('.') + 1)
          .toUpperCase();
        const response = file.response as APIResponse<string>;
        if (response.success) {
          form &&
            form.setFieldsValue({ config: { path: response.data, format } });
          onTest && onTest();
        }
        setUploadFileLoading(false);
      } else {
        setUploadFileLoading(true);
      }
    },
    [form, onTest],
  );

  return (
    <>
      <Form.Item
        label={t('form.file')}
        valuePropName="fileList"
        getValueFromEvent={normFile}
      >
        <Upload
          accept=".xlsx,.xls,.csv"
          method="post"
          action={`${BASE_API_URL}/files/datasource/?sourceId=${sourceId}`}
          headers={{ authorization: getToken()! }}
          showUploadList={false}
          onChange={uploadChange}
        >
          <Button
            icon={<UploadOutlined />}
            loading={uploadFileLoading || loading}
          >
            {t('form.selectFile')}
          </Button>
        </Upload>
      </Form.Item>
      <Form.Item
        name={['config', 'path']}
        css={`
          display: none;
        `}
      >
        <Input />
      </Form.Item>
      <Form.Item
        name={['config', 'format']}
        css={`
          display: none;
        `}
      >
        <Input />
      </Form.Item>
    </>
  );
}
Example #20
Source File: index.tsx    From dashboard with Apache License 2.0 5 votes vote down vote up
Uploader: React.FC<ImageUploaderProps> = (props) => {
  const {value, onChange, fileType, ...rest} = props;
  const [loading, setLoading] = useState<boolean>(false);
  return <>
    <Upload
      {...rest}
      key={props.currentKey}
      accept={fileMap[fileType].accept}
      name='avatar'
      listType='picture-card'
      className={fileType === 'formImage' ? styles.formImageUploader : styles.uploader}
      showUploadList={false}
      beforeUpload={(file) => {
        if (!fileMap[fileType].contentType.includes(file.type)) {
          message.error(`只能上传${fileMap[fileType].accept}格式`);
          return false;
        }
        if (file.size / 1024 / 1024 > fileMap[fileType].limitSize) {
          message.error(`图片最大${fileMap[fileType].limitSize}M`);
          return false;
        }
        if(fileType==='PDF'){
          // @ts-ignore
          const temp = [...props?.fileInfoAry]
          temp.push({fileName:file.name,fileSize:file.size,key:props.currentKey})
          props?.setFileInfoAry?.(temp || [])
        }
        return true;
      }}
      onChange={(info) => {
        if (info.file.status === 'uploading') {
          setLoading(true);
          return;
        }
        if (info.file.status === 'done') {
          setLoading(false);
        }
      }}
      {...(_.omit(props, ['value']))}
    >
      <div>
        {value && (
          <Badge
            count={
              <CloseCircleFilled
                onClick={(e) => {
                  e.preventDefault();
                  e.stopPropagation();
                  if (onChange) {
                    onChange('');
                  }
                  setLoading(false);
                  if(fileType==='PDF'){
                    // @ts-ignore
                    const temp = [...props?.fileInfoAry]
                    for (let i = 0; i < temp.length; i += 1) {
                      if (temp[i].key === props.currentKey) {
                        temp.splice(i, 1)
                      }
                    }
                    props?.setFileInfoAry?.(temp || [])
                  }
                }}
                style={{color: 'rgb(199,199,199)'}}
              />
            }
          >
            {fileMap[fileType].existValueRender(value, props?.fileInfoAry?.find((item: any) => item.key === props.currentKey) || props.initialFileInfo, fileType)}
          </Badge>
        )}
        {
          !value && fileMap[fileType].noValueRender(loading, fileType)
        }
      </div>
    </Upload>
  </>;
}
Example #21
Source File: index.tsx    From ii-admin-base with MIT License 5 votes vote down vote up
export default function IUpload(props: IUpload) {
  const {
    multiple = true,
    iconFontSize = 28,
    iconFontStyle,
    describe,
    extra,
    icon,
    uploadType = 'dragger',
    children,
    ...restProps
  } = props;

  if (!restProps.beforeUpload) {
    restProps.beforeUpload = beforeUpload;
  }

  if (uploadType === 'dragger') {
    return (
      <Dragger multiple={multiple} {...restProps}>
        {children}
        <p className="myupload-iconpart">
          {!icon && (
            <UploadOutlined
              style={{
                fontSize: `${iconFontSize}px`,
                color: '#3079FF',
                ...iconFontStyle,
              }}
            />
          )}
          {icon}
        </p>
        <p className="myupload-describe">
          {describe instanceof Array
            ? describe.map((item, index: number) => (
                <div key={`index${index}`}>{item}</div>
              ))
            : describe}
        </p>
        <p className="myupload-extra">
          {extra instanceof Array
            ? extra.map((item, index: number) => (
                <div key={`index${index}`}>{item}</div>
              ))
            : extra}
        </p>
      </Dragger>
    );
  }
  return (
    <Upload multiple={multiple} {...restProps}>
      {children}
    </Upload>
  );
}
Example #22
Source File: index.tsx    From dashboard with Apache License 2.0 5 votes vote down vote up
ImageUploader: React.FC<ImageUploaderProps> = (props) => {
  const {value, onChange} = props;
  const [loading, setLoading] = useState<boolean>(false);
  return (
    <Upload
      accept={'.jpg,.png,.jpeg'}
      name='avatar'
      listType='picture-card'
      className={styles.imageUploader}
      showUploadList={false}
      beforeUpload={(file) => {
        if (!['image/jpeg', 'image/png', 'image/jpg'].includes(file.type)) {
          message.error('只能上传jpg和png格式');
          return false;
        }
        if (file.size / 1024 / 1024 > 20) {
          message.error('图片最大20M');
          return false;
        }
        return true;
      }}
      onChange={(info) => {
        if (info.file.status === 'uploading') {
          setLoading(true);
          return;
        }
        if (info.file.status === 'done') {
          setLoading(false);
        }
      }}
      {...(_.omit(props, ['value']))}
    >
      <div>
        {value && (
          <Badge
            count={
              <CloseCircleFilled
                onClick={(e) => {
                  e.preventDefault();
                  e.stopPropagation();
                  if (onChange) {
                    onChange('');
                  }
                  setLoading(false);
                }}
                style={{color: 'rgb(199,199,199)'}}
              />
            }
          >
            <Image
              preview={false}
              className={styles.image}
              src={value}
              fallback={defaultImage}
            />
          </Badge>
        )}
        {!value && (
          <div className={styles.button}>
            {loading ? <LoadingOutlined/> : <PlusCircleFilled/>}
            <div className={styles.text}>上传图片</div>
          </div>
        )}
      </div>
    </Upload>
  );
}
Example #23
Source File: upload.tsx    From erda-ui with GNU Affero General Public License v3.0 5 votes vote down vote up
FormUpload = ({
  fixOut = noop,
  fixIn = noop,
  extensionFix,
  requiredCheck,
  trigger = 'onChange',
}: any = {}) =>
  React.memo(({ fieldConfig, form }: any = {}) => {
    const {
      key,
      handleBeforeUpload,
      value,
      label,
      visible,
      valid = [],
      disabled,
      required,
      registerRequiredCheck = noop,
      componentProps,
      wrapperProps,
      labelTip,
      fixIn: itemFixIn,
      fixOut: itemFixOut,
      requiredCheck: _requiredCheck,
    } = fieldConfig || {};

    const curFixIn = itemFixIn || fixIn;
    const curFixOut = itemFixOut || fixOut;
    const [loading, setLoading] = React.useState(false);
    const [imageUrl, setImageUrl] = React.useState('');

    React.useEffect(() => {
      setImageUrl(value);
    }, [value]);

    registerRequiredCheck(_requiredCheck || requiredCheck);
    const { uploadText, sizeLimit, supportFormat = [] } = componentProps || {};
    const _placeholder = uploadText || '上传图片';
    const accept = supportFormat.map((x) => `.${x}`).join(',');

    const uploadButton = (
      <div className="form-item-upload-button">
        <CustomIcon type="cir-add" className="text-xl" />
        <div>{_placeholder}</div>
      </div>
    );

    function handleChange(info: any) {
      if (info.file.status === 'done') {
        const { response } = info.file;
        if (!response) {
          return;
        }
        // FIXME: 为什么要将 http(s) 去掉?
        const url = (get(response, 'data.url') || '').replace(/^http(s)?:/g, '');
        setImageUrl(url);
        form.setFieldValue(key, curFixOut(url));
        componentProps?.onChange?.(url);
      }
    }

    return (
      <FormItem
        colon
        label={getLabel(label, labelTip)}
        className={visible ? '' : 'hidden'}
        validateStatus={valid[0]}
        help={valid[1]}
        required={required}
        {...wrapperProps}
      >
        <Upload listType="picture" accept={accept} onChange={handleChange} {...getUploadProps({}, sizeLimit)}>
          {imageUrl ? <img src={imageUrl} alt="avatar" className="form-item-upload-img" /> : uploadButton}
          <div className="form-item-upload-tip">
            支持格式: {supportFormat?.join(' / ')},不超过 {sizeLimit} M
          </div>
        </Upload>
      </FormItem>
    );
  })
Example #24
Source File: index.tsx    From ii-admin-base with MIT License 5 votes vote down vote up
{ Dragger } = Upload
Example #25
Source File: upload-plugin.tsx    From erda-ui with GNU Affero General Public License v3.0 5 votes vote down vote up
UploadPlugin = (props: any) => {
  let hideLoading: any;
  const getUploadProps = (isImage?: boolean) => ({
    action: '/api/files',
    showUploadList: false,
    headers: {
      'OPENAPI-CSRF-TOKEN': getCookies('OPENAPI-CSRF-TOKEN'),
      org: getOrgFromPath(),
    },
    beforeUpload: (file: any) => {
      const UPLOAD_SIZE_LIMIT = 20; // M
      const isLtSize = file.size / 1024 / 1024 < UPLOAD_SIZE_LIMIT;
      if (!isLtSize) {
        message.warning(i18n.t('common:the uploaded file must not exceed {size}M', { size: UPLOAD_SIZE_LIMIT }));
      }
      return isLtSize;
    },
    onChange: ({ file }: any) => {
      const { status, response } = file;
      if (status === 'uploading' && !hideLoading) {
        hideLoading = message.loading(`${i18n.t('uploading')}...`, 0);
      }
      if (!response) {
        return;
      }
      hideLoading && hideLoading();
      hideLoading = undefined;
      const { success, err, data } = response;
      if (!success) {
        message.error(err.msg);
      } else {
        const { name, size, url } = data;
        props.editor.insertText(`\n${isImage ? '!' : ''}[${name}${size})](${url})\n`);
      }
    },
  });

  return (
    <Popover
      key="yf"
      title={i18n.t('common:Add Attachment')}
      content={
        <div className="upload-plugin-menu">
          <Upload accept=".jpg, .jpeg, .png, .gif" {...getUploadProps(true)}>
            <div className="upload-item hover-active-bg">{i18n.t('common:Upload Image')}</div>
          </Upload>
          <Upload {...getUploadProps()}>
            <div className="upload-item hover-active-bg">{i18n.t('common:Upload File')}</div>
          </Upload>
        </div>
      }
    >
      <span className="button button-type-annex" title="annex">
        <CustomIcon type="fujian" style={{ lineHeight: 'unset', marginRight: 0 }} />
      </span>
    </Popover>
  );
}
Example #26
Source File: UploadFilesV2.spec.tsx    From next-basics with GNU General Public License v3.0 4 votes vote down vote up
describe("UploadFilesV2", () => {
  it("should work", async () => {
    const onChange = jest.fn();
    const wrapper = mount(
      <UploadFilesV2 url={url} value={fileList} onChange={onChange} />
    );
    await Promise.resolve();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
    wrapper.find(Upload).invoke("onChange")({
      file: {
        uid: "123",
        size: 1234,
        type: "image/png",
        name: "image.png",
        status: "done",
        response: {
          data: {
            objectName: "image.png",
          },
        },
      },
      fileList: [...fileList],
    });
    expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
    wrapper.find(Upload).invoke("onChange")({
      file: {
        uid: "123",
        size: 1234,
        type: "image/png",
        name: "image.png",
        status: "removed",
        response: {
          data: {
            objectName: "image.png",
          },
        },
      },
      fileList: [],
    });
    await jest.runAllTimers();
    wrapper.update();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(0);
    wrapper.find(Upload).invoke("onChange")({
      file: {
        uid: "-img1",
        size: 1024,
        type: "image/png",
        name: "image.png",
        status: "uploading",
        response: {
          data: {
            objectName: "image.png",
          },
        },
      },
      fileList: [
        ...fileList,
        {
          uid: "-img1",
          size: 1024,
          type: "image/png",
          name: "image.png",
          status: "uploading",
          response: {
            data: {
              objectName: "image.png",
            },
          },
        },
      ],
    });
    expect(wrapper.find(Upload).prop("disabled")).toBe(true);

    expect(wrapper.find("Button").text()).toBe("Upload");
    expect(wrapper.find("GeneralIcon").at(0).prop("icon")).toEqual({
      lib: "antd",
      icon: "upload",
      theme: "outlined",
    });
    wrapper.setProps({
      uploadButtonProps: {
        buttonName: "Upload Now",
        buttonIcon: {
          lib: "antd",
          icon: "cloud-upload",
          theme: "outlined",
        },
        buttonType: "link",
      },
    });
    wrapper.update();
    expect(wrapper.find("Button").text()).toBe("Upload Now");
    expect(wrapper.find("Button").prop("type")).toBe("link");
    expect(wrapper.find("GeneralIcon").at(0).prop("icon")).toEqual({
      lib: "antd",
      icon: "cloud-upload",
      theme: "outlined",
    });
  });

  it("test remove", async () => {
    const onChange = jest.fn();
    const onRemove = jest.fn();
    const wrapper = mount(
      <UploadFilesV2 url={url} onChange={onChange} onRemove={onRemove} />
    );
    wrapper.find(Upload).invoke("onChange")({
      file: {
        uid: "-img1",
        size: 1024,
        type: "image/png",
        name: "image.png",
        status: "done",
        response: {
          data: {
            objectName: "image.png",
          },
        },
      },
      fileList: [
        ...fileList,
        {
          uid: "-img1",
          size: 1024,
          type: "image/png",
          name: "image.png",
          status: "done",
          response: {
            data: {
              objectName: "image.png",
            },
          },
        },
      ],
    });
    wrapper.update();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(2);
    wrapper.find(Upload).invoke("onRemove")({
      uid: "-img1",
      size: 1024,
      type: "image/png",
      name: "image.png",
      response: {
        data: {
          objectName: "image.png",
        },
      },
    });
    wrapper.update();
    expect(onRemove).toHaveBeenCalled();
  });

  it("test error", async () => {
    const onChange = jest.fn();
    const onError = jest.fn();
    const wrapper = mount(
      <UploadFilesV2 url={url} onChange={onChange} onError={onError} />
    );
    wrapper.find(Upload).invoke("onChange")({
      file: {
        uid: "-img1",
        size: 1024,
        type: "image/png",
        name: "image.png",
        status: "uploading",
      },
      fileList: [
        {
          uid: "-img1",
          size: 1024,
          type: "image/png",
          name: "image.png",
          status: "uploading",
        },
      ],
    });
    wrapper.update();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
    wrapper.find(Upload).invoke("onChange")({
      file: {
        uid: "-img1",
        size: 1024,
        type: "image/png",
        name: "image.png",
        status: "error",
      },
      fileList: [],
    });
    await act(async () => {
      await jest.runAllTimers();
    });
    wrapper.update();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(0);
    expect(onError).toHaveBeenCalled();
  });

  it("test set value by outside", async () => {
    const onChange = jest.fn();
    const wrapper = mount(
      <UploadFilesV2 url={url} method="put" onChange={onChange} />
    );
    wrapper.find(Upload).invoke("onChange")({
      file: {
        uid: "-img1",
        size: 1024,
        type: "image/png",
        name: "image.png",
        status: "done",
      },
      fileList: [
        {
          uid: "-img1",
          size: 1024,
          type: "image/png",
          name: "image.png",
          status: "done",
        },
      ],
    });
    wrapper.update();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
    wrapper.setProps({
      value: [
        {
          url: "image2.png",
        },
        {
          url: "image2.png",
        },
      ],
    });
    await act(async () => {
      await jest.runAllTimers();
    });
    wrapper.update();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(2);
  });

  it("test maxNumber", async () => {
    const onChange = jest.fn();
    const wrapper = mount(
      <UploadFilesV2 url={url} method="put" onChange={onChange} />
    );
    await act(async () => {
      wrapper.find(Upload).invoke("onChange")({
        file: {
          uid: "-img1",
          size: 1024,
          type: "image/png",
          name: "image.png",
          status: "done",
          response: {
            data: {
              objectName: "image.png",
            },
          },
          originFileObj: new File([], "image.png", { type: "image/png" }),
        },
        fileList: [
          {
            uid: "-img1",
            size: 1024,
            type: "image/png",
            name: "image.png",
            status: "done",
            response: {
              data: {
                objectName: "image.png",
              },
            },
            originFileObj: new File([], "image.png", { type: "image/png" }),
          },
        ],
      });
      await (global as any).flushPromises();
    });
    wrapper.update();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
    wrapper.setProps({
      maxNumber: 2,
      value: [
        {
          url: "image2.png",
        },
        {
          url: "image2.png",
        },
      ],
    });
    await act(async () => {
      await jest.runAllTimers();
    });
    wrapper.update();
    expect(wrapper.find(".ant-upload-list-item").length).toBe(2);
    expect(
      wrapper.find(".ant-upload-select-text button").prop("disabled")
    ).toBe(true);
    wrapper.setProps({
      maxNumber: 3,
    });
    wrapper.update();
    expect(
      wrapper.find(".ant-upload-select-text button").prop("disabled")
    ).toBe(undefined);
  });

  describe("test limitSize", () => {
    const wrapper = mount(<UploadFilesV2 url={url} method="put" autoUpload />);
    it("while autoUpload is true", async () => {
      wrapper.setProps({
        limitSize: 1,
      });

      const notAllowResult = wrapper.find(Upload).invoke("beforeUpload")(
        {
          size: 1024 * 1024 * 10,
        },
        [
          {
            size: 1024 * 1024 * 10,
          },
        ]
      );
      await expect(notAllowResult).rejects.toStrictEqual(
        new Error(i18n.t(`${NS_FORMS}:${K.VOLUME_TOO_BIG}`))
      );

      wrapper.setProps({
        limitSize: 2,
      });

      const allowResult = wrapper.find(Upload).invoke("beforeUpload")(
        {
          size: 1024 * 1024,
        },
        [
          {
            size: 1024 * 1024,
          },
        ]
      );
      await expect(allowResult).resolves.toMatchObject({
        size: 1024 * 1024,
      });
    });

    it("while autoUpload is false", () => {
      wrapper.setProps({
        autoUpload: false,
      });
      wrapper.update();
      const autoUploadResult = wrapper.find(Upload).invoke("beforeUpload")(
        {
          size: 1024 * 1024,
        },
        [
          {
            size: 1024 * 1024,
          },
        ]
      );
      expect(autoUploadResult).toBeFalsy();
    });
  });

  it("test draggable", async () => {
    const onChange = jest.fn();
    const wrapper = mount(
      <UploadFilesV2
        url={url}
        method="put"
        onChange={onChange}
        hideDragBtnWhenAchieveMax
        uploadDraggable
        maxNumber={1}
      />
    );
    await act(async () => {
      wrapper.find(Upload).invoke("onChange")({
        file: {
          uid: "-img1",
          size: 1024,
          type: "image/png",
          name: "image.png",
          status: "done",
          response: {
            data: {
              objectName: "image.png",
            },
          },
          originFileObj: new File([], "image.png", { type: "image/png" }),
        },
        fileList: [
          {
            uid: "-img1",
            size: 1024,
            type: "image/png",
            name: "image.png",
            status: "done",
            response: {
              data: {
                objectName: "image.png",
              },
            },
            originFileObj: new File([], "image.png", { type: "image/png" }),
          },
        ],
      });
      await (global as any).flushPromises();
    });
    wrapper.update();
    expect(
      wrapper.find(".ant-upload-drag").hasClass("uploadContainerDisplayNone")
    ).toBeTruthy();
    wrapper.setProps({
      hideDragBtnWhenAchieveMax: false,
      value: [
        {
          url: "image2.png",
        },
      ],
    });
    await act(async () => {
      wrapper.find(Upload).invoke("onChange")({
        file: {
          uid: "-img1",
          size: 1024,
          type: "image/png",
          name: "image.png",
          status: "done",
          response: {
            data: {
              objectName: "image.png",
            },
          },
          originFileObj: new File([], "image.png", { type: "image/png" }),
        },
        fileList: [
          {
            uid: "-img1",
            size: 1024,
            type: "image/png",
            name: "image.png",
            status: "done",
            response: {
              data: {
                objectName: "image.png",
              },
            },
            originFileObj: new File([], "image.png", { type: "image/png" }),
          },
        ],
      });
      await (global as any).flushPromises();
    });
    wrapper.update();
    expect(
      wrapper.find(".ant-upload-drag").hasClass("uploadContainerDisplayNone")
    ).toBeFalsy();
  });

  it("should show dark icon", () => {
    const spyOnUseCurrentTheme = jest
      .spyOn(brickKit, "useCurrentTheme")
      .mockReturnValue("dark-v2");
    const wrapper = mount(
      <UploadFilesV2 url={url} value={fileList} uploadDraggable />
    );

    expect(wrapper.find(GeneralIcon).at(0).prop("icon")).toEqual({
      category: "colored-common",
      icon: "upload-dark",
      lib: "easyops",
    });
    spyOnUseCurrentTheme.mockRestore();
  });
});
Example #27
Source File: asset-modal.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
AssetModal = ({ scope, visible, onCancel, afterSubmit, mode, formData }: IProps) => {
  const { createAsset, addNewVersion, editAsset } = apiMarketStore.effects;
  const [suffix, setSuffix] = React.useState(allSuffix);
  const formRef = React.useRef({}) as MutableRefObject<FormInstance>;
  const [uploadFile, setUploadFile] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  React.useEffect(() => {
    if (!visible) {
      setUploadFile('');
    }
  }, [visible]);
  const handleSelectProtocol = (v: API_MARKET.SpecProtocol) => {
    setSuffix(protocolMap[v].suffix);
    // 文件后缀和资源协议不一致
    if (uploadFile && !protocolMap[v].pattern.test(uploadFile)) {
      setUploadFile('');
      formRef.current && formRef.current.setFieldsValue({ specDiceFileUUID: undefined });
    }
  };
  const nameToId = (e: React.FocusEvent<HTMLInputElement>) => {
    const name = e.target.value;
    const assetID = formRef.current.getFieldValue('assetID');
    if (!assetID && idReg.test(name) && name.length <= 20) {
      formRef.current.setFieldsValue({ assetID: name });
    }
  };
  const showVersionField = scope === 'version' || (scope === 'asset' && mode === 'add');
  const showAssetField = scope === 'asset';
  const fieldsList: IFormItem[] = [
    ...insertWhen(showAssetField, [
      {
        label: i18n.t('API name'),
        name: 'assetName',
        type: 'input',
        required: true,
        itemProps: {
          placeholder: i18n.t('default:please enter'),
          autoComplete: 'off',
          maxLength: 50,
          onBlur: nameToId,
        },
      },
      {
        label: 'API ID',
        type: 'input',
        name: 'assetID',
        required: true,
        itemProps: {
          placeholder: i18n.t('default:please enter'),
          autoComplete: 'off',
          maxLength: 20,
          disabled: mode === 'edit',
        },
        rules: [
          {
            pattern: idReg,
            message: i18n.t(
              'default:start with number or letter, can contain numbers, letters, dots, hyphens and underscores',
            ),
          },
        ],
      },
      {
        label: i18n.t('API description'),
        type: 'textArea',
        name: 'desc',
        required: false,
        itemProps: {
          placeholder: i18n.t('default:please enter'),
          autoComplete: 'off',
          maxLength: 1024,
        },
      },
    ]),
    ...insertWhen(showVersionField, [
      {
        label: i18n.t('default:Resource version'),
        type: 'input',
        name: 'version',
        required: false,
        itemProps: {
          placeholder: i18n.t('Please enter version number, such as x.y.z.'),
          autoComplete: 'off',
        },
        rules: [
          {
            pattern: /^(?:[1-9]\d*|0)\.(?:[1-9]\d*|0)\.(?:[1-9]\d*|0)$/,
            message: i18n.t('Please enter a valid version number, such as x.y.z.'),
          },
        ],
      },
      {
        label: i18n.t('API description document protocol'),
        type: 'select',
        name: 'specProtocol',
        options: map(protocolMap, ({ fullName }, key) => ({ name: fullName, value: key })),
        itemProps: {
          placeholder: i18n.t('Please Select'),
          onSelect: handleSelectProtocol,
        },
      },
    ]),
    ...insertWhen(showVersionField, [
      {
        label: i18n.t('default:API description document'),
        name: 'specDiceFileUUID',
        required: true,
        getComp: ({ form }: { form: FormInstance }) => {
          const uploadProps = getUploadProps({
            onChange: ({ file }: any) => {
              setLoading(true);
              if (file.response) {
                setLoading(false);
                const { success, err, data } = file.response;
                if (!success) {
                  message.error(err.msg);
                } else {
                  form.setFieldsValue({
                    specDiceFileUUID: data.uuid,
                  });
                  setUploadFile(data.name);
                }
              }
              return file;
            },
          });
          return (
            <div className="upload-container">
              <Upload accept={suffix} {...uploadProps}>
                <Button className="flex items-center">
                  <ErdaIcon type="upload" className="mr-1" size="14" /> {i18n.t('Upload')}
                </Button>
              </Upload>
              <span className="text-desc ml-2">
                {uploadFile ? i18n.t('selected {name}', { name: uploadFile }) : null}
              </span>
            </div>
          );
        },
      },
    ]),
    ...insertWhen(showAssetField, [
      {
        label: i18n.t('API logo'),
        name: 'logo',
        required: false,
        getComp: ({ form }: { form: FormInstance }) => <ImageUpload id="logo" form={form} showHint />,
      },
    ]),
  ];
  const handleOk = () => {
    formRef.current.validateFields().then(async (data: any) => {
      const payload = formatPayload(scope, mode, data, formData);
      let request: any = createAsset;
      if (scope === 'version') {
        request = addNewVersion;
      } else if (scope === 'asset' && mode === 'edit') {
        request = editAsset;
      } else if (scope === 'asset' && mode === 'add') {
        request = createAsset;
      }
      const res = await request(payload);
      onCancel();
      afterSubmit && afterSubmit(res);
    });
  };
  const footer = (
    <>
      <Button key="back" onClick={onCancel}>
        {i18n.t('Cancel')}
      </Button>
      <Button key="submit" type="primary" disabled={loading} onClick={handleOk}>
        {i18n.t('OK')}
      </Button>
    </>
  );
  return (
    <FormModal
      title={titleMap[scope][mode]}
      visible={visible}
      fieldsList={fieldsList}
      ref={formRef}
      onCancel={onCancel}
      formData={formData || {}}
      loading={loading}
      modalProps={{
        destroyOnClose: true,
        footer,
      }}
    />
  );
}
Example #28
Source File: TemplateInfoModal.tsx    From yugong with MIT License 4 votes vote down vote up
TemplateInfoModal: React.FC<Props> = ({ visible, onOk, onCancel }) => {
    const [tags, setTags] = useState<queryTagParams[]>([]);
    const pageData = useSelector((state: RootState) => state.pageData);
    const [defaultValue, setDefaultValue] = useState<AnyObject>();

    const [csrfToken] = useCookie('csrfToken')

    const getTags = useCallback(async () => {
        const tagsResult = await queryTag();
        setTags(tagsResult);
    }, []);

    useEffect(() => {
        const { template = {}, pageTitle } = pageData;
        const { title, cove, tag, describe, terminal, isPublic } = template;
        const defaultParams: TemplateInfo = {
            title: title || pageTitle,
            cove: !!cove ? [{thumbUrl: cove}] : [],
            tag: !!tag ? tag.split(',') : [],
            isPublic: (isPublic === 1),
            describe,
            terminal,
        };
        setDefaultValue(defaultParams);
        
    }, [pageData, pageData.template, visible]);

    useEffect(() => {
        getTags();
    }, [getTags]);

    const handleSubmit = useCallback(
        (data: AnyObject) => {
            if (!isType(data, 'Object')) return;
            data.describe = data.describe || '';
            if (onOk instanceof Function) onOk(data);
        },
        [onOk]
    );

    return (
        <Modal
            key={`${visible}`}
            title="模版信息"
            visible={visible}
            onCancel={onCancel}
            okText={'确定'}
            cancelText={'取消'}
            footer={null}
        >
            <Form
                name="templateInfo"
                labelCol={{ span: 5 }}
                wrapperCol={{ span: 19 }}
                initialValues={defaultValue}
                onFinish={handleSubmit}
            >
                <Form.Item
                    label="模板标题"
                    name="title"
                    rules={[{ required: true, message: '请填写模板标题' }]}
                >
                    <Input />
                </Form.Item>
                <Form.Item
                    label="终端"
                    name="terminal"
                    rules={[{ required: true, message: '请选择终端' }]}
                >
                    <Select placeholder="请选择">
                        <Select.Option value="mobile">移动端</Select.Option>
                        <Select.Option value="pc">PC端</Select.Option>
                    </Select>
                </Form.Item>
                <Form.Item
                    name="cove"
                    label="封面图片"
                    valuePropName="fileList"
                    getValueFromEvent={normFile}
                    extra="模版封面图片"
                    rules={[{ required: true, message: '请上传封面图片' }]}
                >
                    <Upload
                        action="/api/upload"
                        listType="picture"
                        maxCount={1}
                        headers={{
                          'x-csrf-token': csrfToken || ''
                        }}
                    >
                        <Button icon={<UploadOutlined />}>上传图片</Button>
                    </Upload>

                </Form.Item>
                <Form.Item label="描述" name="describe">
                    <Input.TextArea rows={3} />
                </Form.Item>
                <Form.Item
                    label="标签"
                    name="tag"
                    rules={[{ required: true, message: '请选择标签' }]}
                >
                    <Select mode="multiple" allowClear placeholder="标签">
                        {tags.map((item) => (
                            <Select.Option key={item.id} value={`${item.id}`}>
                                {item.name}
                            </Select.Option>
                        ))}
                    </Select>
                </Form.Item>

                <Form.Item
                    name="isPublic"
                    valuePropName="checked"
                    wrapperCol={{ offset: 9, span: 17 }}
                >
                    <Checkbox>发布为公共模板</Checkbox>
                </Form.Item>

                <Form.Item wrapperCol={{ offset: 10, span: 14 }}>
                    <Button type="primary" htmlType="submit">
                        确定
                    </Button>
                </Form.Item>
            </Form>
        </Modal>
    );
}
Example #29
Source File: MultipleFileUpload.tsx    From condo with MIT License 4 votes vote down vote up
MultipleFileUpload: React.FC<IMultipleFileUploadProps> = (props) => {
    const intl = useIntl()
    const AddFileLabel = intl.formatMessage({ id: 'component.uploadlist.AddFileLabel' })
    const FileTooBigErrorMessage = intl.formatMessage({ id: 'component.uploadlist.error.FileTooBig' },
        { maxSizeInMb: MAX_UPLOAD_FILE_SIZE / (1024 * 1024) })
    const UploadFailedErrorMessage = intl.formatMessage({ id: 'component.uploadlist.error.UploadFailedErrorMessage' })
    const {
        setFilesCount,
        fileList,
        initialCreateValues,
        Model,
        onFilesChange,
        UploadButton,
        uploadProps = {},
    } = props

    const [listFiles, setListFiles] = useState<UploadListFile[]>([])

    useEffect(() => {
        const convertedFiles = convertFilesToUploadFormat(fileList)
        setListFiles(convertedFiles)
    }, [fileList])

    const createAction = Model.useCreate(initialCreateValues, (file: DBFile) => Promise.resolve(file))

    useEffect(() => {
        if (listFiles.length === 0) {
            setFilesCount(0)
        }
    }, [listFiles.length, setFilesCount])

    const options = {
        fileList: listFiles,
        multiple: true,
        onChange: (info) => {
            let fileList = [...info.fileList]
            fileList = fileList.map(file => {
                if (file.response) {
                    file.url = file.response.url
                }
                return file
            })
            setListFiles(fileList)
        },
        showUploadList: {
            showRemoveIcon: true,
            removeIcon: (file) => {
                const removeIcon = (
                    <DeleteFilled onClick={() => {
                        const { id, uid } = file
                        const fileError = get(file, 'error')
                        if (!fileError) {
                            setFilesCount(filesCount => filesCount - 1)
                        }

                        if (!id) {
                            // remove file that failed to upload from list
                            setListFiles([...listFiles].filter(file => file.uid !== uid))
                            onFilesChange({ type: 'delete', payload: file })
                            return
                        }
                        setListFiles([...listFiles].filter(file => file.id !== id))
                        onFilesChange({ type: 'delete', payload: file })
                    }} />
                )
                return removeIcon
            },
        },
        customRequest: (options: UploadRequestOption) => {
            const { onSuccess, onError } = options
            const file = options.file as UploadFile
            if (file.size > MAX_UPLOAD_FILE_SIZE) {
                const error = new Error(FileTooBigErrorMessage)
                onError(error)
                return
            }
            return createAction({ ...initialCreateValues, file }).then( dbFile  => {
                const [uploadFile] = convertFilesToUploadFormat([dbFile])
                onSuccess(uploadFile, null)
                onFilesChange({ type: 'add', payload: dbFile })
                setFilesCount(filesCount => filesCount + 1)
            }).catch(err => {
                const error = new Error(UploadFailedErrorMessage)
                console.error('Upload failed', err)
                onError(error)
            })
        },
        ...uploadProps,
    }

    return (
        <div className={'upload-control-wrapper'}>
            <Upload { ...options }>
                {
                    UploadButton || (
                        <Button
                            type={'sberDefaultGradient'}
                            secondary
                            icon={<EditFilled />}
                        >
                            {AddFileLabel}
                        </Button>
                    )
                }
            </Upload>
        </div>
    )
}