SIP-32: Moving frontend code to the base of the repo (#9098)

* move assets out, get webpack dev working

* update docs to reference superset-frontend

* draw the rest of the owl

* fix docs

* fix webpack script

* rats

* correct docs

* fix tox dox
This commit is contained in:
David Aaron Suddjian
2020-02-09 17:53:56 -08:00
committed by GitHub
parent 0cf354cc88
commit 2913063924
930 changed files with 681 additions and 314 deletions

View File

@@ -0,0 +1,94 @@
/**
* 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.
*/
import React from 'react';
import { Modal } from 'react-bootstrap';
import configureStore from 'redux-mock-store';
import { shallow } from 'enzyme';
import fetchMock from 'fetch-mock';
import thunk from 'redux-thunk';
import sinon from 'sinon';
import ChangeDatasourceModal from '../../../src/datasource/ChangeDatasourceModal';
import mockDatasource from '../../fixtures/mockDatasource';
const props = {
addDangerToast: () => {},
onDatasourceSave: sinon.spy(),
onChange: () => {},
onHide: () => {},
show: true,
};
const datasource = mockDatasource['7__table'];
const datasourceData = {
id: datasource.name,
type: datasource.type,
uid: datasource.id,
};
const DATASOURCES_ENDPOINT = 'glob:*/superset/datasources/';
const DATASOURCE_ENDPOINT = `glob:*/datasource/get/${datasourceData.type}/${datasourceData.id}`;
const DATASOURCES_PAYLOAD = { json: 'data' };
const DATASOURCE_PAYLOAD = { new: 'data' };
describe('ChangeDatasourceModal', () => {
const mockStore = configureStore([thunk]);
const store = mockStore({});
fetchMock.get(DATASOURCES_ENDPOINT, DATASOURCES_PAYLOAD);
let wrapper;
let el;
let inst;
beforeEach(() => {
el = <ChangeDatasourceModal {...props} />;
wrapper = shallow(el, { context: { store } }).dive();
inst = wrapper.instance();
});
it('is valid', () => {
expect(React.isValidElement(el)).toBe(true);
});
it('renders a Modal', () => {
expect(wrapper.find(Modal)).toHaveLength(1);
});
it('fetches datasources', done => {
inst.onEnterModal();
setTimeout(() => {
expect(fetchMock.calls(DATASOURCES_ENDPOINT)).toHaveLength(1);
fetchMock.reset();
done();
}, 0);
});
it('changes the datasource', done => {
fetchMock.get(DATASOURCE_ENDPOINT, DATASOURCE_PAYLOAD);
inst.selectDatasource(datasourceData);
setTimeout(() => {
expect(fetchMock.calls(DATASOURCE_ENDPOINT)).toHaveLength(1);
expect(props.onDatasourceSave.getCall(0).args[0]).toEqual(
DATASOURCE_PAYLOAD,
);
fetchMock.reset();
done();
}, 0);
});
});

View File

@@ -0,0 +1,103 @@
/**
* 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.
*/
import React from 'react';
import { Tabs } from 'react-bootstrap';
import { shallow } from 'enzyme';
import configureStore from 'redux-mock-store';
import fetchMock from 'fetch-mock';
import thunk from 'redux-thunk';
import DatasourceEditor from '../../../src/datasource/DatasourceEditor';
import Field from '../../../src/CRUD/Field';
import mockDatasource from '../../fixtures/mockDatasource';
const props = {
datasource: mockDatasource['7__table'],
addSuccessToast: () => {},
addDangerToast: () => {},
onChange: () => {},
};
const extraColumn = {
column_name: 'new_column',
type: 'VARCHAR(10)',
description: null,
filterable: true,
verbose_name: null,
is_dttm: false,
expression: '',
groupby: true,
};
const DATASOURCE_ENDPOINT = 'glob:*/datasource/external_metadata/*';
describe('DatasourceEditor', () => {
const mockStore = configureStore([thunk]);
const store = mockStore({});
fetchMock.get(DATASOURCE_ENDPOINT, []);
let wrapper;
let el;
let inst;
beforeEach(() => {
el = <DatasourceEditor {...props} />;
wrapper = shallow(el, { context: { store } }).dive();
inst = wrapper.instance();
});
it('is valid', () => {
expect(React.isValidElement(el)).toBe(true);
});
it('renders Tabs', () => {
expect(wrapper.find(Tabs)).toHaveLength(1);
});
it('makes an async request', done => {
wrapper.setState({ activeTabKey: 2 });
const syncButton = wrapper.find('.sync-from-source');
expect(syncButton).toHaveLength(1);
syncButton.simulate('click');
setTimeout(() => {
expect(fetchMock.calls(DATASOURCE_ENDPOINT)).toHaveLength(1);
fetchMock.reset();
done();
}, 0);
});
it('merges columns', () => {
const numCols = props.datasource.columns.length;
expect(inst.state.databaseColumns).toHaveLength(numCols);
inst.mergeColumns([extraColumn]);
expect(inst.state.databaseColumns).toHaveLength(numCols + 1);
});
it('renders isSqla fields', () => {
wrapper.setState({ activeTabKey: 4 });
expect(wrapper.state('isSqla')).toBe(true);
expect(
wrapper
.find(Field)
.find({ fieldKey: 'fetch_values_predicate' })
.exists(),
).toBe(true);
});
});

View File

@@ -0,0 +1,80 @@
/**
* 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.
*/
import React from 'react';
import { Modal } from 'react-bootstrap';
import configureStore from 'redux-mock-store';
import { shallow } from 'enzyme';
import fetchMock from 'fetch-mock';
import thunk from 'redux-thunk';
import sinon from 'sinon';
import DatasourceModal from '../../../src/datasource/DatasourceModal';
import DatasourceEditor from '../../../src/datasource/DatasourceEditor';
import mockDatasource from '../../fixtures/mockDatasource';
const props = {
datasource: mockDatasource['7__table'],
addSuccessToast: () => {},
addDangerToast: () => {},
onChange: () => {},
show: true,
onHide: () => {},
onDatasourceSave: sinon.spy(),
};
const SAVE_ENDPOINT = 'glob:*/datasource/save/';
const SAVE_PAYLOAD = { new: 'data' };
describe('DatasourceModal', () => {
const mockStore = configureStore([thunk]);
const store = mockStore({});
fetchMock.post(SAVE_ENDPOINT, SAVE_PAYLOAD);
let wrapper;
let el;
let inst;
beforeEach(() => {
el = <DatasourceModal {...props} />;
wrapper = shallow(el, { context: { store } }).dive();
inst = wrapper.instance();
});
it('is valid', () => {
expect(React.isValidElement(el)).toBe(true);
});
it('renders a Modal', () => {
expect(wrapper.find(Modal)).toHaveLength(1);
});
it('renders a DatasourceEditor', () => {
expect(wrapper.find(DatasourceEditor)).toHaveLength(1);
});
it('saves on confirm', done => {
inst.onConfirmSave();
setTimeout(() => {
expect(fetchMock.calls(SAVE_ENDPOINT)).toHaveLength(1);
expect(props.onDatasourceSave.getCall(0).args[0]).toEqual(SAVE_PAYLOAD);
fetchMock.reset();
done();
}, 0);
});
});