feat: style import button (#15057)

* feat: style import button

* Update tests

* Update test
This commit is contained in:
Beto Dealmeida 2021-06-09 15:40:53 -07:00 committed by GitHub
parent 0c470feaef
commit 256e1452fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 40 deletions

View File

@ -54,6 +54,7 @@ export {
Tag,
Tabs,
Tooltip,
Upload,
Input as AntdInput,
} from 'antd';
export { Card as AntdCard } from 'antd';

View File

@ -17,10 +17,12 @@
* under the License.
*/
import React from 'react';
import { act } from 'react-dom/test-utils';
import thunk from 'redux-thunk';
import configureStore from 'redux-mock-store';
import { styledMount as mount } from 'spec/helpers/theming';
import { ReactWrapper } from 'enzyme';
import { Upload } from 'src/common/components';
import Button from 'src/components/Button';
import { ImportResourceName } from 'src/views/CRUD/types';
import ImportModelsModal from 'src/components/ImportModal';
@ -66,29 +68,37 @@ describe('ImportModelsModal', () => {
expect(wrapper.find('h4').text()).toEqual('Import database');
});
it('renders a label and a file input field', () => {
it('renders a file input field', () => {
expect(wrapper.find('input[type="file"]')).toExist();
expect(wrapper.find('label')).toExist();
});
it('should attach the label to the input field', () => {
const id = 'modelFile';
expect(wrapper.find('label').prop('htmlFor')).toBe(id);
expect(wrapper.find('input').prop('id')).toBe(id);
});
it('should render the close, import and cancel buttons', () => {
expect(wrapper.find('button')).toHaveLength(3);
it('should render the close, file, import and cancel buttons', () => {
expect(wrapper.find('button')).toHaveLength(4);
});
it('should render the import button initially disabled', () => {
expect(wrapper.find(Button).at(1).prop('disabled')).toBe(true);
expect(wrapper.find(Button).at(2).prop('disabled')).toBe(true);
});
it('should render the import button enabled when a file is selected', () => {
const file = new File([new ArrayBuffer(1)], 'model_export.zip');
wrapper.find('input').simulate('change', { target: { files: [file] } });
expect(wrapper.find(Button).at(1).prop('disabled')).toBe(false);
act(() => {
const handler = wrapper.find(Upload).prop('onChange');
if (handler) {
handler({
fileList: [],
file: {
name: 'model_export.zip',
originFileObj: file,
uid: '-1',
size: 0,
type: 'zip',
},
});
}
});
wrapper.update();
expect(wrapper.find(Button).at(2).prop('disabled')).toBe(false);
});
it('should render password fields when needed for import', () => {

View File

@ -16,11 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
import React, { FunctionComponent, useEffect, useRef, useState } from 'react';
import React, { FunctionComponent, useEffect, useState } from 'react';
import { UploadChangeParam, UploadFile } from 'antd/lib/upload/interface';
import { styled, t } from '@superset-ui/core';
import Icon from 'src//components/Icon';
import Button from 'src/components/Button';
import Icon from 'src/components/Icon';
import Modal from 'src/components/Modal';
import { Upload } from 'src/common/components';
import { useImportResource } from 'src/views/CRUD/hooks';
import { ImportResourceName } from 'src/views/CRUD/types';
@ -127,24 +130,19 @@ const ImportModelsModal: FunctionComponent<ImportModelsModalProps> = ({
setPasswordFields = () => {},
}) => {
const [isHidden, setIsHidden] = useState<boolean>(true);
const [uploadFile, setUploadFile] = useState<File | null>(null);
const [passwords, setPasswords] = useState<Record<string, string>>({});
const [needsOverwriteConfirm, setNeedsOverwriteConfirm] = useState<boolean>(
false,
);
const [confirmedOverwrite, setConfirmedOverwrite] = useState<boolean>(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const [fileList, setFileList] = useState<UploadFile[]>([]);
const clearModal = () => {
setUploadFile(null);
setFileList([]);
setPasswordFields([]);
setPasswords({});
setNeedsOverwriteConfirm(false);
setConfirmedOverwrite(false);
if (fileInputRef && fileInputRef.current) {
fileInputRef.current.value = '';
}
};
const handleErrorMsg = (msg: string) => {
@ -173,11 +171,15 @@ const ImportModelsModal: FunctionComponent<ImportModelsModalProps> = ({
};
const onUpload = () => {
if (uploadFile === null) {
if (!(fileList[0]?.originFileObj instanceof File)) {
return;
}
importResource(uploadFile, passwords, confirmedOverwrite).then(result => {
importResource(
fileList[0].originFileObj,
passwords,
confirmedOverwrite,
).then(result => {
if (result) {
addSuccessToast(t('The import was successful'));
clearModal();
@ -186,9 +188,18 @@ const ImportModelsModal: FunctionComponent<ImportModelsModalProps> = ({
});
};
const changeFile = (event: React.ChangeEvent<HTMLInputElement>) => {
const { files } = event.target as HTMLInputElement;
setUploadFile((files && files[0]) || null);
const changeFile = (info: UploadChangeParam) => {
setFileList([
{
...info.file,
status: 'done',
},
]);
};
const removeFile = (removedFile: UploadFile) => {
setFileList(fileList.filter(file => file.uid !== removedFile.uid));
return false;
};
const confirmOverwrite = (event: React.ChangeEvent<HTMLInputElement>) => {
@ -259,7 +270,7 @@ const ImportModelsModal: FunctionComponent<ImportModelsModalProps> = ({
name="model"
className="import-model-modal"
disablePrimaryButton={
uploadFile === null || (needsOverwriteConfirm && !confirmedOverwrite)
fileList.length === 0 || (needsOverwriteConfirm && !confirmedOverwrite)
}
onHandledPrimaryAction={onUpload}
onHide={hide}
@ -270,21 +281,19 @@ const ImportModelsModal: FunctionComponent<ImportModelsModalProps> = ({
title={<h4>{t('Import %s', resourceLabel)}</h4>}
>
<StyledInputContainer>
<div className="control-label">
<label htmlFor="modelFile">
{t('File')}
<span className="required">*</span>
</label>
</div>
<input
ref={fileInputRef}
data-test="model-file-input"
<Upload
name="modelFile"
id="modelFile"
type="file"
data-test="model-file-input"
accept=".yaml,.json,.yml,.zip"
fileList={fileList}
onChange={changeFile}
/>
onRemove={removeFile}
// upload is handled by hook
customRequest={() => {}}
>
<Button>Select file</Button>
</Upload>
</StyledInputContainer>
{renderPasswordFields()}
{renderOverwriteConfirmation()}

View File

@ -330,7 +330,7 @@ describe('RTL', () => {
userEvent.click(importButton);
// Grab "Choose File" input from import modal
const chooseFileInput = screen.getByLabelText(/file\*/i);
const chooseFileInput = screen.getByTestId('model-file-input');
// Upload mocked import file
userEvent.upload(chooseFileInput, mockImportFile);