implemented PluginLoader

This commit is contained in:
Sebastian Sdorra
2018-08-24 12:43:10 +02:00
parent ab8f166b1d
commit 4f775fe7ca
8 changed files with 104 additions and 9 deletions

View File

@@ -5,7 +5,7 @@
"build": "ui-bundler plugin" "build": "ui-bundler plugin"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-extensions": "^0.0.5" "@scm-manager/ui-extensions": "^0.0.6"
}, },
"devDependencies": { "devDependencies": {
"@scm-manager/ui-bundler": "^0.0.3" "@scm-manager/ui-bundler": "^0.0.3"

View File

@@ -5,7 +5,7 @@
"build": "ui-bundler plugin" "build": "ui-bundler plugin"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-extensions": "^0.0.5" "@scm-manager/ui-extensions": "^0.0.6"
}, },
"devDependencies": { "devDependencies": {
"@scm-manager/ui-bundler": "^0.0.3" "@scm-manager/ui-bundler": "^0.0.3"

View File

@@ -5,7 +5,7 @@
"build": "ui-bundler plugin" "build": "ui-bundler plugin"
}, },
"dependencies": { "dependencies": {
"@scm-manager/ui-extensions": "^0.0.5" "@scm-manager/ui-extensions": "^0.0.6"
}, },
"devDependencies": { "devDependencies": {
"@scm-manager/ui-bundler": "^0.0.3" "@scm-manager/ui-bundler": "^0.0.3"

View File

@@ -5,7 +5,7 @@
"private": true, "private": true,
"main": "src/index.js", "main": "src/index.js",
"dependencies": { "dependencies": {
"@scm-manager/ui-extensions": "^0.0.5", "@scm-manager/ui-extensions": "^0.0.6",
"bulma": "^0.7.1", "bulma": "^0.7.1",
"classnames": "^2.2.5", "classnames": "^2.2.5",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",

View File

@@ -39,8 +39,5 @@
--> -->
<script src="vendor.bundle.js"></script> <script src="vendor.bundle.js"></script>
<script src="scm-ui.bundle.js"></script> <script src="scm-ui.bundle.js"></script>
<script src="scm-git-plugin.bundle.js"></script>
<script src="scm-hg-plugin.bundle.js"></script>
<script src="scm-svn-plugin.bundle.js"></script>
</body> </body>
</html> </html>

View File

@@ -25,12 +25,13 @@ const styles = {
type Props = { type Props = {
t: string => string, t: string => string,
message?: string,
classes: any classes: any
}; };
class Loading extends React.Component<Props> { class Loading extends React.Component<Props> {
render() { render() {
const { t, classes } = this.props; const { message, t, classes } = this.props;
return ( return (
<div className={classes.wrapper}> <div className={classes.wrapper}>
<div className={classes.loading}> <div className={classes.loading}>
@@ -39,6 +40,7 @@ class Loading extends React.Component<Props> {
src="/images/loading.svg" src="/images/loading.svg"
alt={t("loading.alt")} alt={t("loading.alt")}
/> />
<p className="has-text-centered">{message}</p>
</div> </div>
</div> </div>
); );

View File

@@ -0,0 +1,93 @@
// @flow
import * as React from "react";
import Loading from "./Loading";
import { apiClient } from "../apiclient";
type Props = {
children: React.Node
};
type State = {
finished: boolean,
message: string
};
type Plugin = {
id: string,
bundles: string[]
};
class PluginLoader extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
finished: false,
message: "booting"
};
}
componentDidMount() {
this.setState({
message: "loading plugin information"
});
apiClient
.get("ui/plugins")
.then(response => response.text())
.then(JSON.parse)
.then(this.loadPlugins)
.then(() => {
this.setState({
finished: true
});
});
}
loadPlugins = (plugins: Plugin[]) => {
this.setState({
message: "loading plugins"
});
const promises = [];
for (let plugin of plugins) {
promises.push(this.loadPlugin(plugin));
}
return Promise.all(promises);
};
loadPlugin = (plugin: Plugin) => {
this.setState({
message: `loading ${plugin.name}`
});
const promises = [];
for (let bundle of plugin.bundles) {
// skip old bundles
// TODO remove old bundles
if (bundle.indexOf("/") !== 0) {
promises.push(this.loadBundle(bundle));
}
}
return Promise.all(promises);
};
loadBundle = (bundle: string) => {
return fetch(bundle)
.then(response => {
return response.text();
})
.then(script => {
// TODO is this safe???
eval(script);
});
};
render() {
const { message, finished } = this.state;
if (finished) {
return <div>{this.props.children}</div>;
}
return <Loading message={message} />;
}
}
export default PluginLoader;

View File

@@ -14,6 +14,7 @@ import type { BrowserHistory } from "history/createBrowserHistory";
import createReduxStore from "./createReduxStore"; import createReduxStore from "./createReduxStore";
import { ConnectedRouter } from "react-router-redux"; import { ConnectedRouter } from "react-router-redux";
import PluginLoader from "./components/PluginLoader";
const publicUrl: string = process.env.PUBLIC_URL || ""; const publicUrl: string = process.env.PUBLIC_URL || "";
@@ -36,7 +37,9 @@ ReactDOM.render(
<I18nextProvider i18n={i18n}> <I18nextProvider i18n={i18n}>
{/* ConnectedRouter will use the store from Provider automatically */} {/* ConnectedRouter will use the store from Provider automatically */}
<ConnectedRouter history={history}> <ConnectedRouter history={history}>
<App /> <PluginLoader>
<App />
</PluginLoader>
</ConnectedRouter> </ConnectedRouter>
</I18nextProvider> </I18nextProvider>
</Provider>, </Provider>,