mirror of
https://github.com/apache/superset.git
synced 2024-09-17 11:09:47 -04:00
chore: remove supersetTheme with withTheme (#17069)
* remove supersettheme * migrate Datasourceeditor to rtl * lint fix * remove file * fix import * fix test * fix lint * spread tests and remove unused code * fix lint
This commit is contained in:
parent
65f1644208
commit
93f59e055e
@ -25,7 +25,7 @@ import Card from 'src/components/Card';
|
|||||||
import Alert from 'src/components/Alert';
|
import Alert from 'src/components/Alert';
|
||||||
import Badge from 'src/components/Badge';
|
import Badge from 'src/components/Badge';
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
import { styled, SupersetClient, t, supersetTheme } from '@superset-ui/core';
|
import { styled, SupersetClient, t, withTheme } from '@superset-ui/core';
|
||||||
import { Select } from 'src/components';
|
import { Select } from 'src/components';
|
||||||
import { FormLabel } from 'src/components/Form';
|
import { FormLabel } from 'src/components/Form';
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
@ -97,7 +97,7 @@ const StyledBadge = styled(Badge)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const EditLockContainer = styled.div`
|
const EditLockContainer = styled.div`
|
||||||
font-size: ${supersetTheme.typography.sizes.s}px;
|
font-size: ${({ theme }) => theme.typography.sizes.s}px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
a {
|
a {
|
||||||
@ -828,7 +828,7 @@ class DatasourceEditor extends React.PureComponent {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSourceFieldset() {
|
renderSourceFieldset(theme) {
|
||||||
const { datasource } = this.state;
|
const { datasource } = this.state;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -989,13 +989,9 @@ class DatasourceEditor extends React.PureComponent {
|
|||||||
<EditLockContainer>
|
<EditLockContainer>
|
||||||
<span role="button" tabIndex={0} onClick={this.onChangeEditMode}>
|
<span role="button" tabIndex={0} onClick={this.onChangeEditMode}>
|
||||||
{this.state.isEditMode ? (
|
{this.state.isEditMode ? (
|
||||||
<Icons.LockUnlocked
|
<Icons.LockUnlocked iconColor={theme.colors.grayscale.base} />
|
||||||
iconColor={supersetTheme.colors.grayscale.base}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<Icons.LockLocked
|
<Icons.LockLocked iconColor={theme.colors.grayscale.base} />
|
||||||
iconColor={supersetTheme.colors.grayscale.base}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
{!this.state.isEditMode && (
|
{!this.state.isEditMode && (
|
||||||
@ -1166,6 +1162,8 @@ class DatasourceEditor extends React.PureComponent {
|
|||||||
const { datasource, activeTabKey } = this.state;
|
const { datasource, activeTabKey } = this.state;
|
||||||
const { metrics } = datasource;
|
const { metrics } = datasource;
|
||||||
const sortedMetrics = metrics?.length ? this.sortMetrics(metrics) : [];
|
const sortedMetrics = metrics?.length ? this.sortMetrics(metrics) : [];
|
||||||
|
const { theme } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DatasourceContainer>
|
<DatasourceContainer>
|
||||||
{this.renderErrors()}
|
{this.renderErrors()}
|
||||||
@ -1190,7 +1188,7 @@ class DatasourceEditor extends React.PureComponent {
|
|||||||
defaultActiveKey={activeTabKey}
|
defaultActiveKey={activeTabKey}
|
||||||
>
|
>
|
||||||
<Tabs.TabPane key={0} tab={t('Source')}>
|
<Tabs.TabPane key={0} tab={t('Source')}>
|
||||||
{this.renderSourceFieldset()}
|
{this.renderSourceFieldset(theme)}
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
<Tabs.TabPane
|
<Tabs.TabPane
|
||||||
tab={
|
tab={
|
||||||
@ -1283,4 +1281,6 @@ class DatasourceEditor extends React.PureComponent {
|
|||||||
DatasourceEditor.defaultProps = defaultProps;
|
DatasourceEditor.defaultProps = defaultProps;
|
||||||
DatasourceEditor.propTypes = propTypes;
|
DatasourceEditor.propTypes = propTypes;
|
||||||
|
|
||||||
export default withToasts(DatasourceEditor);
|
const DataSourceComponent = withTheme(DatasourceEditor);
|
||||||
|
|
||||||
|
export default withToasts(DataSourceComponent);
|
||||||
|
@ -17,22 +17,12 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
|
||||||
import configureStore from 'redux-mock-store';
|
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import thunk from 'redux-thunk';
|
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { render, screen } from 'spec/helpers/testing-library';
|
import { render, screen } from 'spec/helpers/testing-library';
|
||||||
|
|
||||||
import { Radio } from 'src/components/Radio';
|
|
||||||
|
|
||||||
import Icons from 'src/components/Icons';
|
|
||||||
import Tabs from 'src/components/Tabs';
|
|
||||||
import DatasourceEditor from 'src/components/Datasource/DatasourceEditor';
|
import DatasourceEditor from 'src/components/Datasource/DatasourceEditor';
|
||||||
import Field from 'src/CRUD/Field';
|
|
||||||
import mockDatasource from 'spec/fixtures/mockDatasource';
|
import mockDatasource from 'spec/fixtures/mockDatasource';
|
||||||
import * as featureFlags from 'src/featureFlags';
|
import * as featureFlags from 'src/featureFlags';
|
||||||
import TableSelector from 'src/components/TableSelector';
|
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
datasource: mockDatasource['7__table'],
|
datasource: mockDatasource['7__table'],
|
||||||
@ -43,23 +33,14 @@ const props = {
|
|||||||
const DATASOURCE_ENDPOINT = 'glob:*/datasource/external_metadata_by_name/*';
|
const DATASOURCE_ENDPOINT = 'glob:*/datasource/external_metadata_by_name/*';
|
||||||
|
|
||||||
describe('DatasourceEditor', () => {
|
describe('DatasourceEditor', () => {
|
||||||
const mockStore = configureStore([thunk]);
|
|
||||||
const store = mockStore({});
|
|
||||||
fetchMock.get(DATASOURCE_ENDPOINT, []);
|
fetchMock.get(DATASOURCE_ENDPOINT, []);
|
||||||
|
|
||||||
let wrapper;
|
|
||||||
let el;
|
let el;
|
||||||
let inst;
|
|
||||||
let isFeatureEnabledMock;
|
let isFeatureEnabledMock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
el = <DatasourceEditor {...props} store={store} />;
|
el = <DatasourceEditor {...props} />;
|
||||||
wrapper = shallow(el).dive();
|
render(el, { useRedux: true });
|
||||||
inst = wrapper.instance();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
wrapper.unmount();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is valid', () => {
|
it('is valid', () => {
|
||||||
@ -67,15 +48,18 @@ describe('DatasourceEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('renders Tabs', () => {
|
it('renders Tabs', () => {
|
||||||
expect(wrapper.find('#table-tabs')).toExist();
|
expect(screen.getByTestId('edit-dataset-tabs')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('makes an async request', () =>
|
it('makes an async request', () =>
|
||||||
new Promise(done => {
|
new Promise(done => {
|
||||||
wrapper.setState({ activeTabKey: 2 });
|
const columnsTab = screen.getByTestId('collection-tab-Columns');
|
||||||
const syncButton = wrapper.find('.sync-from-source');
|
|
||||||
expect(syncButton).toHaveLength(1);
|
userEvent.click(columnsTab);
|
||||||
syncButton.simulate('click');
|
const syncButton = screen.getByText(/sync columns from source/i);
|
||||||
|
expect(syncButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(syncButton);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(fetchMock.calls(DATASOURCE_ENDPOINT)).toHaveLength(1);
|
expect(fetchMock.calls(DATASOURCE_ENDPOINT)).toHaveLength(1);
|
||||||
@ -84,76 +68,77 @@ describe('DatasourceEditor', () => {
|
|||||||
}, 0);
|
}, 0);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('to add, remove and modify columns accordingly', () => {
|
// to add, remove and modify columns accordingly
|
||||||
const columns = [
|
it('can modify columns', async () => {
|
||||||
{
|
const columnsTab = screen.getByTestId('collection-tab-Columns');
|
||||||
name: 'ds',
|
userEvent.click(columnsTab);
|
||||||
type: 'DATETIME',
|
|
||||||
nullable: true,
|
|
||||||
default: '',
|
|
||||||
primary_key: false,
|
|
||||||
is_dttm: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'gender',
|
|
||||||
type: 'VARCHAR(32)',
|
|
||||||
nullable: true,
|
|
||||||
default: '',
|
|
||||||
primary_key: false,
|
|
||||||
is_dttm: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'new_column',
|
|
||||||
type: 'VARCHAR(10)',
|
|
||||||
nullable: true,
|
|
||||||
default: '',
|
|
||||||
primary_key: false,
|
|
||||||
is_dttm: false,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const numCols = props.datasource.columns.length;
|
const getToggles = screen.getAllByRole('button', {
|
||||||
expect(inst.state.databaseColumns).toHaveLength(numCols);
|
name: /toggle expand/i,
|
||||||
inst.updateColumns(columns);
|
});
|
||||||
expect(inst.state.databaseColumns).toEqual(
|
userEvent.click(getToggles[0]);
|
||||||
expect.arrayContaining([
|
const getTextboxes = screen.getAllByRole('textbox');
|
||||||
{
|
expect(getTextboxes.length).toEqual(5);
|
||||||
type: 'DATETIME',
|
|
||||||
description: null,
|
const inputLabel = screen.getByPlaceholderText('Label');
|
||||||
filterable: false,
|
const inputDescription = screen.getByPlaceholderText('Description');
|
||||||
verbose_name: null,
|
const inputDtmFormat = screen.getByPlaceholderText('%Y/%m/%d');
|
||||||
is_dttm: true,
|
const inputCertifiedBy = screen.getByPlaceholderText('Certified by');
|
||||||
expression: '',
|
const inputCertDetails = screen.getByPlaceholderText(
|
||||||
groupby: false,
|
'Certification details',
|
||||||
column_name: 'ds',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'VARCHAR(32)',
|
|
||||||
description: null,
|
|
||||||
filterable: true,
|
|
||||||
verbose_name: null,
|
|
||||||
is_dttm: false,
|
|
||||||
expression: '',
|
|
||||||
groupby: true,
|
|
||||||
column_name: 'gender',
|
|
||||||
},
|
|
||||||
expect.objectContaining({
|
|
||||||
column_name: 'new_column',
|
|
||||||
type: 'VARCHAR(10)',
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
expect(inst.state.databaseColumns).not.toEqual(
|
|
||||||
expect.arrayContaining([expect.objectContaining({ name: 'name' })]),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
userEvent.type(await inputLabel, 'test_lable');
|
||||||
|
userEvent.type(await inputDescription, 'test');
|
||||||
|
userEvent.type(await inputDtmFormat, 'test');
|
||||||
|
userEvent.type(await inputCertifiedBy, 'test');
|
||||||
|
userEvent.type(await inputCertDetails, 'test');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can delete columns', async () => {
|
||||||
|
const columnsTab = screen.getByTestId('collection-tab-Columns');
|
||||||
|
userEvent.click(columnsTab);
|
||||||
|
|
||||||
|
const getToggles = screen.getAllByRole('button', {
|
||||||
|
name: /toggle expand/i,
|
||||||
|
});
|
||||||
|
|
||||||
|
userEvent.click(getToggles[0]);
|
||||||
|
screen.logTestingPlaygroundURL();
|
||||||
|
const deleteButtons = screen.getAllByRole('button', {
|
||||||
|
name: /delete item/i,
|
||||||
|
});
|
||||||
|
expect(deleteButtons.length).toEqual(7);
|
||||||
|
userEvent.click(deleteButtons[0]);
|
||||||
|
const countRows = screen.getAllByRole('button', { name: /delete item/i });
|
||||||
|
expect(countRows.length).toEqual(6);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can add new columns', async () => {
|
||||||
|
const calcColsTab = screen.getByTestId('collection-tab-Calculated columns');
|
||||||
|
userEvent.click(calcColsTab);
|
||||||
|
const addBtn = screen.getByRole('button', {
|
||||||
|
name: /add item/i,
|
||||||
|
});
|
||||||
|
expect(addBtn).toBeInTheDocument();
|
||||||
|
userEvent.click(addBtn);
|
||||||
|
const newColumn = screen.getByRole('button', {
|
||||||
|
name: /<new column>/i,
|
||||||
|
});
|
||||||
|
expect(newColumn).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders isSqla fields', () => {
|
it('renders isSqla fields', () => {
|
||||||
wrapper.setState({ activeTabKey: 4 });
|
const columnsTab = screen.getByRole('tab', {
|
||||||
expect(wrapper.state('isSqla')).toBe(true);
|
name: /settings/i,
|
||||||
|
});
|
||||||
|
userEvent.click(columnsTab);
|
||||||
|
const extraField = screen.getAllByText(/extra/i);
|
||||||
|
expect(extraField.length).toEqual(2);
|
||||||
expect(
|
expect(
|
||||||
wrapper.find(Field).find({ fieldKey: 'fetch_values_predicate' }).exists(),
|
screen.getByText(/autocomplete query predicate/i),
|
||||||
).toBe(true);
|
).toBeInTheDocument();
|
||||||
|
expect(screen.getByText(/template parameters/i)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('enable edit Source tab', () => {
|
describe('enable edit Source tab', () => {
|
||||||
@ -161,7 +146,6 @@ describe('DatasourceEditor', () => {
|
|||||||
isFeatureEnabledMock = jest
|
isFeatureEnabledMock = jest
|
||||||
.spyOn(featureFlags, 'isFeatureEnabled')
|
.spyOn(featureFlags, 'isFeatureEnabled')
|
||||||
.mockImplementation(() => false);
|
.mockImplementation(() => false);
|
||||||
wrapper = shallow(el, { context: { store } }).dive();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
@ -169,51 +153,50 @@ describe('DatasourceEditor', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Source Tab: edit mode', () => {
|
it('Source Tab: edit mode', () => {
|
||||||
wrapper.setState({ activeTabKey: 0, isEditMode: true });
|
const getLockBtn = screen.getByRole('img', { name: /lock-locked/i });
|
||||||
const sourceTab = wrapper.find(Tabs.TabPane).first();
|
userEvent.click(getLockBtn);
|
||||||
expect(sourceTab.find(Radio).first().prop('disabled')).toBe(false);
|
const physicalRadioBtn = screen.getByRole('radio', {
|
||||||
|
name: /physical \(table or view\)/i,
|
||||||
const icon = wrapper.find(Icons.LockUnlocked);
|
});
|
||||||
expect(icon).toExist();
|
const vituralRadioBtn = screen.getByRole('radio', {
|
||||||
|
name: /virtual \(sql\)/i,
|
||||||
const tableSelector = sourceTab.find(Field).shallow().find(TableSelector);
|
});
|
||||||
expect(tableSelector.length).toBe(1);
|
expect(physicalRadioBtn).toBeEnabled();
|
||||||
expect(tableSelector.prop('readOnly')).toBe(false);
|
expect(vituralRadioBtn).toBeEnabled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Source Tab: readOnly mode', () => {
|
it('Source Tab: readOnly mode', () => {
|
||||||
const sourceTab = wrapper.find(Tabs.TabPane).first();
|
const getLockBtn = screen.getByRole('img', { name: /lock-locked/i });
|
||||||
expect(sourceTab.find(Radio).length).toBe(2);
|
expect(getLockBtn).toBeInTheDocument();
|
||||||
expect(sourceTab.find(Radio).first().prop('disabled')).toBe(true);
|
const physicalRadioBtn = screen.getByRole('radio', {
|
||||||
|
name: /physical \(table or view\)/i,
|
||||||
const icon = wrapper.find(Icons.LockLocked);
|
});
|
||||||
expect(icon).toExist();
|
const vituralRadioBtn = screen.getByRole('radio', {
|
||||||
icon.parent().simulate('click');
|
name: /virtual \(sql\)/i,
|
||||||
expect(wrapper.state('isEditMode')).toBe(true);
|
});
|
||||||
|
expect(physicalRadioBtn).toBeDisabled();
|
||||||
const tableSelector = sourceTab.find(Field).shallow().find(TableSelector);
|
expect(vituralRadioBtn).toBeDisabled();
|
||||||
expect(tableSelector.length).toBe(1);
|
|
||||||
expect(tableSelector.prop('readOnly')).toBe(true);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('disable edit Source tab', () => {
|
describe('render editor with feature flag false', () => {
|
||||||
// when edit is disabled, show readOnly controls and no padlock
|
beforeAll(() => {
|
||||||
isFeatureEnabledMock = jest
|
isFeatureEnabledMock = jest
|
||||||
.spyOn(featureFlags, 'isFeatureEnabled')
|
.spyOn(featureFlags, 'isFeatureEnabled')
|
||||||
.mockImplementation(() => true);
|
.mockImplementation(() => true);
|
||||||
wrapper = shallow(el, { context: { store } }).dive();
|
});
|
||||||
wrapper.setState({ activeTabKey: 0 });
|
|
||||||
|
|
||||||
const sourceTab = wrapper.find(Tabs.TabPane).first();
|
beforeEach(() => {
|
||||||
expect(sourceTab.find(Radio).length).toBe(2);
|
render(el, { useRedux: true });
|
||||||
expect(sourceTab.find(Radio).first().prop('disabled')).toBe(true);
|
});
|
||||||
|
|
||||||
const icon = sourceTab.find(Icons.LockLocked);
|
|
||||||
expect(icon).toHaveLength(0);
|
|
||||||
|
|
||||||
|
it('disable edit Source tab', () => {
|
||||||
|
expect(
|
||||||
|
screen.queryByRole('img', { name: /lock-locked/i }),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
isFeatureEnabledMock.mockRestore();
|
isFeatureEnabledMock.mockRestore();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('DatasourceEditor RTL', () => {
|
describe('DatasourceEditor RTL', () => {
|
||||||
@ -227,9 +210,7 @@ describe('DatasourceEditor RTL', () => {
|
|||||||
/certification details/i,
|
/certification details/i,
|
||||||
);
|
);
|
||||||
expect(certificationDetails.value).toEqual('foo');
|
expect(certificationDetails.value).toEqual('foo');
|
||||||
const warningMarkdown = await await screen.findByPlaceholderText(
|
const warningMarkdown = await screen.findByPlaceholderText(/certified by/i);
|
||||||
/certified by/i,
|
|
||||||
);
|
|
||||||
expect(warningMarkdown.value).toEqual('someone');
|
expect(warningMarkdown.value).toEqual('someone');
|
||||||
});
|
});
|
||||||
it('properly updates the metric information', async () => {
|
it('properly updates the metric information', async () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user