Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable hot module replacement for React via react-hot-loader #5841

Merged
merged 8 commits into from
Sep 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion superset/assets/.babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"presets" : ["airbnb", "react", "env"],
"plugins": ["syntax-dynamic-import"],
"plugins": ["syntax-dynamic-import", "react-hot-loader/babel"]
}
1 change: 1 addition & 0 deletions superset/assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"react-dnd-html5-backend": "^2.5.4",
"react-dom": "^15.6.2",
"react-gravatar": "^2.6.1",
"react-hot-loader": "^4.3.6",
"react-map-gl": "^3.0.4",
"react-markdown": "^3.3.0",
"react-redux": "^5.0.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import { shallow } from 'enzyme';
import { describe, it } from 'mocha';
import { expect } from 'chai';

import App from '../../../src/welcome/App';
import Welcome from '../../../src/welcome/Welcome';

describe('App', () => {
describe('Welcome', () => {
const mockedProps = {};
it('is valid', () => {
expect(
React.isValidElement(<App {...mockedProps} />),
React.isValidElement(<Welcome {...mockedProps} />),
).to.equal(true);
});
it('renders 4 Tab, Panel, and Row components', () => {
const wrapper = shallow(<App {...mockedProps} />);
const wrapper = shallow(<Welcome {...mockedProps} />);
expect(wrapper.find(Tab)).to.have.length(3);
expect(wrapper.find(Panel)).to.have.length(3);
expect(wrapper.find(Row)).to.have.length(3);
Expand Down
45 changes: 45 additions & 0 deletions superset/assets/src/SqlLab/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { createStore, compose, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunkMiddleware from 'redux-thunk';
import { hot } from 'react-hot-loader';

import getInitialState from './getInitialState';
import rootReducer from './reducers';
import { initEnhancer } from '../reduxUtils';
import { initJQueryAjax } from '../modules/utils';
import App from './components/App';
import { appSetup } from '../common';

import './main.less';
import '../../stylesheets/reactable-pagination.css';
import '../components/FilterableTable/FilterableTableStyles.css';

appSetup();
initJQueryAjax();

const appContainer = document.getElementById('app');
const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
const state = getInitialState(bootstrapData);

const store = createStore(
rootReducer,
state,
compose(
applyMiddleware(thunkMiddleware),
initEnhancer(),
),
);

// jquery hack to highlight the navbar menu
$('a:contains("SQL Lab")')
.parent()
.addClass('active');

const Application = () => (
<Provider store={store}>
<App />
</Provider>
);

export default hot(module)(Application);
46 changes: 5 additions & 41 deletions superset/assets/src/SqlLab/index.jsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,8 @@
import React from 'react';
import { render } from 'react-dom';
import { createStore, compose, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunkMiddleware from 'redux-thunk';
import ReactDOM from 'react-dom';
import App from './App';

import getInitialState from './getInitialState';
import rootReducer from './reducers';
import { initEnhancer } from '../reduxUtils';
import { initJQueryAjax } from '../modules/utils';
import App from './components/App';
import { appSetup } from '../common';

import './main.less';
import '../../stylesheets/reactable-pagination.css';
import '../components/FilterableTable/FilterableTableStyles.css';

appSetup();
initJQueryAjax();

const appContainer = document.getElementById('app');
const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
const state = getInitialState(bootstrapData);

const store = createStore(
rootReducer,
state,
compose(
applyMiddleware(thunkMiddleware),
initEnhancer(),
),
);

// jquery hack to highlight the navbar menu
$('a:contains("SQL Lab")')
.parent()
.addClass('active');

render(
<Provider store={store}>
<App />
</Provider>,
appContainer,
ReactDOM.render(
<App />,
document.getElementById('app'),
);
15 changes: 15 additions & 0 deletions superset/assets/src/addSlice/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { hot } from 'react-hot-loader';
import { appSetup } from '../common';
import AddSliceContainer from './AddSliceContainer';

appSetup();

const addSliceContainer = document.getElementById('js-add-slice-container');
const bootstrapData = JSON.parse(addSliceContainer.getAttribute('data-bootstrap'));

const App = () => (
<AddSliceContainer datasources={bootstrapData.datasources} />
);

export default hot(module)(App);
12 changes: 3 additions & 9 deletions superset/assets/src/addSlice/index.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { appSetup } from '../common';
import AddSliceContainer from './AddSliceContainer';

appSetup();

const addSliceContainer = document.getElementById('js-add-slice-container');
const bootstrapData = JSON.parse(addSliceContainer.getAttribute('data-bootstrap'));
import App from './App';

ReactDOM.render(
<AddSliceContainer datasources={bootstrapData.datasources} />,
addSliceContainer,
<App />,
document.getElementById('js-add-slice-container'),
);
36 changes: 36 additions & 0 deletions superset/assets/src/dashboard/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import thunk from 'redux-thunk';
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import { hot } from 'react-hot-loader';

import { initEnhancer } from '../reduxUtils';
import { appSetup } from '../common';
import { initJQueryAjax } from '../modules/utils';
import DashboardContainer from './containers/Dashboard';
import getInitialState from './reducers/getInitialState';
import rootReducer from './reducers/index';

appSetup();
initJQueryAjax();

const appContainer = document.getElementById('app');
const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
const initState = getInitialState(bootstrapData);

const store = createStore(
rootReducer,
initState,
compose(
applyMiddleware(thunk),
initEnhancer(false),
),
);

const App = () => (
<Provider store={store}>
<DashboardContainer />
</Provider>
);

export default hot(module)(App);
34 changes: 2 additions & 32 deletions superset/assets/src/dashboard/index.jsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import App from './App';

import { initEnhancer } from '../reduxUtils';
import { appSetup } from '../common';
import { initJQueryAjax } from '../modules/utils';
import DashboardContainer from './containers/Dashboard';
import getInitialState from './reducers/getInitialState';
import rootReducer from './reducers/index';

appSetup();
initJQueryAjax();

const appContainer = document.getElementById('app');
const bootstrapData = JSON.parse(appContainer.getAttribute('data-bootstrap'));
const initState = getInitialState(bootstrapData);

const store = createStore(
rootReducer,
initState,
compose(
applyMiddleware(thunk),
initEnhancer(false),
),
);

ReactDOM.render(
<Provider store={store}>
<DashboardContainer />
</Provider>,
appContainer,
);
ReactDOM.render(<App />, document.getElementById('app'));
92 changes: 92 additions & 0 deletions superset/assets/src/explore/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/* eslint no-undef: 2 */
import React from 'react';
import { hot } from 'react-hot-loader';
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';

import shortid from 'shortid';
import { now } from '../modules/dates';
import { initEnhancer } from '../reduxUtils';
import { getChartKey } from './exploreUtils';
import ToastPresenter from '../messageToasts/containers/ToastPresenter';
import { getControlsState, getFormDataFromControls } from './store';
import { initJQueryAjax } from '../modules/utils';
import ExploreViewContainer from './components/ExploreViewContainer';
import rootReducer from './reducers/index';
import getToastsFromPyFlashMessages from '../messageToasts/utils/getToastsFromPyFlashMessages';

import { appSetup } from '../common';
import './main.css';
import '../../stylesheets/reactable-pagination.css';

appSetup();
initJQueryAjax();

const exploreViewContainer = document.getElementById('app');
const bootstrapData = JSON.parse(exploreViewContainer.getAttribute('data-bootstrap'));
const controls = getControlsState(bootstrapData, bootstrapData.form_data);
const rawFormData = { ...bootstrapData.form_data };

delete bootstrapData.form_data;
delete bootstrapData.common.locale;
delete bootstrapData.common.language_pack;

// Initial state
const bootstrappedState = {
...bootstrapData,
rawFormData,
controls,
filterColumnOpts: [],
isDatasourceMetaLoading: false,
isStarred: false,
};
const slice = bootstrappedState.slice;
const sliceFormData = slice
? getFormDataFromControls(getControlsState(bootstrapData, slice.form_data))
: null;
const chartKey = getChartKey(bootstrappedState);
const initState = {
charts: {
[chartKey]: {
id: chartKey,
chartAlert: null,
chartStatus: 'loading',
chartUpdateEndTime: null,
chartUpdateStartTime: now(),
latestQueryFormData: getFormDataFromControls(controls),
sliceFormData,
queryRequest: null,
queryResponse: null,
triggerQuery: true,
lastRendered: 0,
},
},
saveModal: {
dashboards: [],
saveModalAlert: null,
},
explore: bootstrappedState,
impressionId: shortid.generate(),
messageToasts: getToastsFromPyFlashMessages((bootstrapData.common || {}).flash_messages || []),
};

const store = createStore(
rootReducer,
initState,
compose(
applyMiddleware(thunk),
initEnhancer(false),
),
);

const App = () => (
<Provider store={store}>
<div>
<ExploreViewContainer />
<ToastPresenter />
</div>
</Provider>
);

export default hot(module)(App);
Loading