refactor: Use Antd Modals instead of react-bootstrap Modals (#11366)

* Make Modal responsive

* ErrorAlert

* OmniContainer

* dashboard/PropertiesModal

* Fix e2e tests

* Lint fix

* E2E test fix

* Fix test

* Use grid units

* Change padding to padding-left/right
This commit is contained in:
Kamil Gabryjelski 2020-10-27 21:08:04 +01:00 committed by GitHub
parent a99d795eaf
commit 155b5edec1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 212 additions and 198 deletions

View File

@ -87,19 +87,19 @@ describe('Dashboard edit action', () => {
const dashboardTitle = `Test dashboard [${shortid.generate()}]`;
// update title
cy.get('.modal-body')
cy.get('.ant-modal-body')
.should('be.visible')
.contains('Title')
.siblings('input')
.type(`{selectall}{backspace}${dashboardTitle}`);
// save edit changes
cy.get('.modal-footer')
cy.get('.ant-modal-footer')
.contains('Save')
.click()
.then(() => {
// assert that modal edit window has closed
cy.get('.modal-body').should('not.exist');
cy.get('.ant-modal-body').should('not.exist');
// assert title has been updated
cy.get('.editable-title input').should('have.value', dashboardTitle);

View File

@ -90,7 +90,7 @@ describe('Dashboard save action', () => {
openDashboardEditProperties();
// open color scheme dropdown
cy.get('.modal-body')
cy.get('.ant-modal-body')
.contains('Color Scheme')
.parents('.ControlHeader')
.next('.Select')
@ -105,7 +105,7 @@ describe('Dashboard save action', () => {
});
// remove json metadata
cy.get('.modal-body')
cy.get('.ant-modal-body')
.contains('Advanced')
.click()
.then(() => {
@ -113,18 +113,18 @@ describe('Dashboard save action', () => {
});
// update title
cy.get('.modal-body')
cy.get('.ant-modal-body')
.contains('Title')
.siblings('input')
.type(`{selectall}{backspace}${dashboardTitle}`);
// save edit changes
cy.get('.modal-footer')
cy.get('.ant-modal-footer')
.contains('Save')
.click()
.then(() => {
// assert that modal edit window has closed
cy.get('.modal-body').should('not.exist');
cy.get('.ant-modal-body').should('not.exist');
// save dashboard changes
cy.get('.dashboard-header').contains('Save').click();

View File

@ -101,11 +101,9 @@ describe('Dashboard card view', () => {
cy.get('.ant-dropdown-trigger').last().trigger('mouseover');
cy.get('.ant-dropdown-menu-item').contains('Edit').should('exist');
cy.get('.ant-dropdown-menu-item').contains('Edit').click();
cy.get('.modal-dialog').should('be.visible');
cy.get('.modal-dialog input[name="dashboard_title"]').should(
'not.have.value',
);
cy.get('.modal-dialog input[name="slug"]').should('not.have.value');
cy.get('.modal-dialog .btn-default').contains('Cancel').click();
cy.get('.ant-modal').should('be.visible');
cy.get('.ant-modal input[name="dashboard_title"]').should('not.have.value');
cy.get('.ant-modal input[name="slug"]').should('not.have.value');
cy.get('.ant-modal .btn-default').contains('Cancel').click();
});
});

View File

@ -47,10 +47,12 @@ interface StyledModalProps extends SupersetThemeProps {
}
const StyledModal = styled(BaseModal)<StyledModalProps>`
${({ responsive, maxWidth }) =>
${({ theme, responsive, maxWidth }) =>
responsive &&
css`
max-width: ${maxWidth ?? '900px'};
padding-left: ${theme.gridUnit * 3}px;
padding-right: ${theme.gridUnit * 3}px;
`}
.ant-modal-header {
@ -137,7 +139,7 @@ export default function Modal({
]
: footer;
const modalWidth = width || responsive ? 'calc(100vw - 24px)' : '600px';
const modalWidth = width || (responsive ? '100vw' : '600px');
return (
<StyledModal
centered={!!centered}
@ -154,6 +156,7 @@ export default function Modal({
</span>
}
footer={!hideFooter ? modalFooter : null}
data-test={`${title}-modal`}
{...rest}
>
{children}

View File

@ -0,0 +1,20 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export * from './Modal';
export { default } from './Modal';

View File

@ -17,9 +17,9 @@
* under the License.
*/
import React, { useState, ReactNode } from 'react';
import { Modal } from 'react-bootstrap';
import { styled, supersetTheme, t } from '@superset-ui/core';
import { noOp } from 'src/utils/common';
import Modal from 'src/common/components/Modal';
import Button from 'src/components/Button';
import Icon from '../Icon';
@ -64,17 +64,10 @@ const ErrorModal = styled(Modal)<{ level: ErrorLevel }>`
}
.header {
display: flex;
align-items: center;
background-color: ${({ level, theme }) => theme.colors[level].light2};
display: flex;
justify-content: space-between;
font-size: ${({ theme }) => theme.typography.sizes.l}px;
// Remove clearfix hack as Superset is only used on modern browsers
::before,
::after {
content: unset;
}
}
`;
@ -157,30 +150,18 @@ export default function ErrorAlert({
level={level}
show={isModalOpen}
onHide={() => setIsModalOpen(false)}
>
<Modal.Header className="header">
<LeftSideContent>
title={
<div className="header">
<Icon
className="icon"
name={level === 'error' ? 'error-solid' : 'warning-solid'}
color={supersetTheme.colors[level].base}
/>
<div className="title">{title}</div>
</LeftSideContent>
<span
role="button"
tabIndex={0}
onClick={() => setIsModalOpen(false)}
>
<Icon name="close" />
</span>
</Modal.Header>
<Modal.Body>
<p>{subtitle}</p>
<br />
{body}
</Modal.Body>
<Modal.Footer>
</div>
}
footer={
<>
{copyText && (
<CopyToClipboard
text={copyText}
@ -196,7 +177,14 @@ export default function ErrorAlert({
>
{t('Close')}
</Button>
</Modal.Footer>
</>
}
>
<>
<p>{subtitle}</p>
<br />
{body}
</>
</ErrorModal>
)}
</ErrorAlertDiv>

View File

@ -17,11 +17,11 @@
* under the License.
*/
import React from 'react';
import { Modal } from 'react-bootstrap';
import PropTypes from 'prop-types';
import { t, SupersetClient } from '@superset-ui/core';
import { styled, t, SupersetClient } from '@superset-ui/core';
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
import Omnibar from 'omnibar';
import Modal from 'src/common/components/Modal';
import { LOG_ACTIONS_OMNIBAR_TRIGGERED } from '../logger/LogUtils';
const propTypes = {
@ -44,6 +44,14 @@ const getDashboards = query =>
title: t('An error occurred while fethching Dashboards'),
}));
const OmniModal = styled(Modal)`
margin-top: 20%;
.ant-modal-body {
padding: 0;
}
`;
class OmniContainer extends React.Component {
constructor(props) {
super(props);
@ -79,13 +87,13 @@ class OmniContainer extends React.Component {
render() {
return (
<Modal show={this.state.showOmni} style={{ marginTop: '25%' }}>
<OmniModal show={this.state.showOmni} hideFooter closable={false}>
<Omnibar
className="Omnibar"
placeholder="Search all dashboards"
extensions={[getDashboards]}
/>
</Modal>
</OmniModal>
);
}
}

View File

@ -18,7 +18,7 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { Row, Col, Modal, FormControl } from 'react-bootstrap';
import { Row, Col, FormControl } from 'react-bootstrap';
import Button from 'src/components/Button';
import Dialog from 'react-bootstrap-dialog';
import { AsyncSelect } from 'src/components/Select';
@ -30,6 +30,7 @@ import {
getCategoricalSchemeRegistry,
} from '@superset-ui/core';
import Modal from 'src/common/components/Modal';
import FormLabel from 'src/components/FormLabel';
import { JsonEditor } from 'src/components/AsyncAceEditor';
@ -292,16 +293,41 @@ class PropertiesModal extends React.PureComponent {
const saveLabel = onlyApply ? t('Apply') : t('Save');
return (
<Modal show={this.props.show} onHide={this.props.onHide} bsSize="lg">
<Modal
show={this.props.show}
onHide={this.props.onHide}
title={t('Dashboard Properties')}
footer={
<>
<Button
type="button"
buttonSize="sm"
onClick={onHide}
data-test="properties-modal-cancel-button"
cta
>
{t('Cancel')}
</Button>
<Button
onClick={this.submit}
buttonSize="sm"
buttonStyle="primary"
className="m-r-5"
disabled={errors.length > 0}
cta
>
{saveLabel}
</Button>
<Dialog
ref={ref => {
this.dialog = ref;
}}
/>
</>
}
responsive
>
<form onSubmit={this.submit}>
<Modal.Header closeButton data-test="dashboard-properties-modal">
<Modal.Title>
<div>
<span className="float-left">{t('Dashboard Properties')}</span>
</div>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Row>
<Col md={12}>
<h3>{t('Basic Information')}</h3>
@ -402,35 +428,6 @@ class PropertiesModal extends React.PureComponent {
)}
</Col>
</Row>
</Modal.Body>
<Modal.Footer>
<span className="float-right">
<Button
type="button"
buttonSize="sm"
onClick={onHide}
data-test="properties-modal-cancel-button"
cta
>
{t('Cancel')}
</Button>
<Button
type="submit"
buttonSize="sm"
buttonStyle="primary"
className="m-r-5"
disabled={errors.length > 0}
cta
>
{saveLabel}
</Button>
<Dialog
ref={ref => {
this.dialog = ref;
}}
/>
</span>
</Modal.Footer>
</form>
</Modal>
);