Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Commit

Permalink
Enable hot module replacement for React via react-hot-loader (apache#…
Browse files Browse the repository at this point in the history
…5841)

* Install react-hot-loader

* enable react-hot-reload for Explore, Dashboard, Profile and Sqllab

* enable hmr for welcome page

* enable hmr for welcome page

* enable react hot module replacement for addSlice

* fix lint

* fix Welcome test

* remove eslint comment
  • Loading branch information
kristw authored and williaster committed Sep 10, 2018
1 parent 517fea3 commit 6d57372
Show file tree
Hide file tree
Showing 18 changed files with 345 additions and 282 deletions.
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

0 comments on commit 6d57372

Please sign in to comment.