This is an automated email from the ASF dual-hosted git repository. suddjian pushed a commit to branch dynamic-plugin-import in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
commit 9b0dfc4f54159b23054a6d57a95c6fc9b3af2e65 Author: David Aaron Suddjian <[email protected]> AuthorDate: Wed Jun 10 14:30:03 2020 -0700 first attempts at dynamic plugin loading --- superset-frontend/src/addSlice/App.tsx | 5 +- .../DynamicPlugins/DynamicPluginProvider.tsx | 40 +++++++++++++ .../src/components/DynamicPlugins/PluginContext.ts | 25 +++++++++ superset-frontend/src/welcome/App.tsx | 65 +++++++++++----------- 4 files changed, 103 insertions(+), 32 deletions(-) diff --git a/superset-frontend/src/addSlice/App.tsx b/superset-frontend/src/addSlice/App.tsx index 4443fb5..f94b4da 100644 --- a/superset-frontend/src/addSlice/App.tsx +++ b/superset-frontend/src/addSlice/App.tsx @@ -21,6 +21,7 @@ import { hot } from 'react-hot-loader/root'; import { supersetTheme, ThemeProvider } from '@superset-ui/style'; import setupApp from '../setup/setupApp'; import setupPlugins from '../setup/setupPlugins'; +import DynamicPluginProvider from '../components/DynamicPlugins/DynamicPluginProvider'; import AddSliceContainer from './AddSliceContainer'; setupApp(); @@ -33,7 +34,9 @@ const bootstrapData = JSON.parse( const App = () => ( <ThemeProvider theme={supersetTheme}> - <AddSliceContainer datasources={bootstrapData.datasources} /> + <DynamicPluginProvider> + <AddSliceContainer datasources={bootstrapData.datasources} /> + </DynamicPluginProvider> </ThemeProvider> ); diff --git a/superset-frontend/src/components/DynamicPlugins/DynamicPluginProvider.tsx b/superset-frontend/src/components/DynamicPlugins/DynamicPluginProvider.tsx new file mode 100644 index 0000000..ca45e66 --- /dev/null +++ b/superset-frontend/src/components/DynamicPlugins/DynamicPluginProvider.tsx @@ -0,0 +1,40 @@ +import React, { useEffect, useState } from 'react'; +// use scriptjs for browser-side dynamic importing +// import $script from 'scriptjs'; +// import { Preset } from '@superset-ui/core'; +import PluginContext, { initialPluginContext } from './PluginContext'; + +console.log('from superset:', React); + +// In future this should be provided by an api call +const pluginUrls = ['http://localhost:8080/main.js']; + +export type Props = React.PropsWithChildren<{}>; + +export default function DynamicPluginProvider({ children }: Props) { + const [pluginState] = useState(initialPluginContext); + useEffect(() => { + console.log('importing test'); + // $script(pluginUrls, () => { + // console.log('done'); + // }); + Promise.all( + pluginUrls.map(async url => { + const { default: d } = await import(/* webpackIgnore: true */ url); + return d; + }), + ).then(pluginModules => { + console.log(pluginModules); + // return new Preset({ + // name: 'Dynamic Charts', + // presets: [], + // plugins: [pluginModules], + // }); + }); + }, [pluginUrls]); + return ( + <PluginContext.Provider value={pluginState}> + {children} + </PluginContext.Provider> + ); +} diff --git a/superset-frontend/src/components/DynamicPlugins/PluginContext.ts b/superset-frontend/src/components/DynamicPlugins/PluginContext.ts new file mode 100644 index 0000000..100e813 --- /dev/null +++ b/superset-frontend/src/components/DynamicPlugins/PluginContext.ts @@ -0,0 +1,25 @@ +import React from 'react'; + +export enum LoadingStatus { + LOADING = 'loading', + COMPLETE = 'complete', + ERROR = 'error', +} + +export type PluginContextType = { + status: LoadingStatus; + error: null | { + message: string; + }; + pluginKeys: string[]; +}; + +export const initialPluginContext: PluginContextType = { + status: LoadingStatus.LOADING, + error: null, + pluginKeys: [], +}; + +const PluginContext = React.createContext(initialPluginContext); + +export default PluginContext; diff --git a/superset-frontend/src/welcome/App.tsx b/superset-frontend/src/welcome/App.tsx index 5bc624d..c72a131 100644 --- a/superset-frontend/src/welcome/App.tsx +++ b/superset-frontend/src/welcome/App.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { hot } from 'react-hot-loader/root'; import thunk from 'redux-thunk'; import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; -import { Provider } from 'react-redux'; +import { Provider as ReduxProvider } from 'react-redux'; import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; import { QueryParamProvider } from 'use-query-params'; import { initFeatureFlags } from 'src/featureFlags'; @@ -38,6 +38,7 @@ import setupApp from '../setup/setupApp'; import setupPlugins from '../setup/setupPlugins'; import Welcome from './Welcome'; import ToastPresenter from '../messageToasts/containers/ToastPresenter'; +import DynamicPluginProvider from 'src/components/DynamicPlugins/DynamicPluginProvider'; setupApp(); setupPlugins(); @@ -58,40 +59,42 @@ const store = createStore( ); const App = () => ( - <Provider store={store}> + <ReduxProvider store={store}> <ThemeProvider theme={supersetTheme}> <FlashProvider common={common}> - <Router> - <QueryParamProvider ReactRouterRoute={Route}> - <Menu data={menu} /> - <Switch> - <Route path="/superset/welcome/"> - <ErrorBoundary> - <Welcome user={user} /> - </ErrorBoundary> - </Route> - <Route path="/dashboard/list/"> - <ErrorBoundary> - <DashboardList user={user} /> - </ErrorBoundary> - </Route> - <Route path="/chart/list/"> - <ErrorBoundary> - <ChartList user={user} /> - </ErrorBoundary> - </Route> - <Route path="/tablemodelview/list/"> - <ErrorBoundary> - <DatasetList user={user} /> - </ErrorBoundary> - </Route> - </Switch> - <ToastPresenter /> - </QueryParamProvider> - </Router> + <DynamicPluginProvider> + <Router> + <QueryParamProvider ReactRouterRoute={Route}> + <Menu data={menu} /> + <Switch> + <Route path="/superset/welcome/"> + <ErrorBoundary> + <Welcome user={user} /> + </ErrorBoundary> + </Route> + <Route path="/dashboard/list/"> + <ErrorBoundary> + <DashboardList user={user} /> + </ErrorBoundary> + </Route> + <Route path="/chart/list/"> + <ErrorBoundary> + <ChartList user={user} /> + </ErrorBoundary> + </Route> + <Route path="/tablemodelview/list/"> + <ErrorBoundary> + <DatasetList user={user} /> + </ErrorBoundary> + </Route> + </Switch> + <ToastPresenter /> + </QueryParamProvider> + </Router> + </DynamicPluginProvider> </FlashProvider> </ThemeProvider> - </Provider> + </ReduxProvider> ); export default hot(App);
