blueocean-plugin/blueocean-web/src/main/js/main.jsx

149 lines
4.3 KiB
JavaScript

import React, { Component, PropTypes } from 'react';
import { render } from 'react-dom';
import { Router, Route, Link, useRouterHistory, IndexRedirect } from 'react-router';
import { createHistory } from 'history';
import { Provider, configureStore, combineReducers} from './redux';
import { DevelopmentFooter } from './DevelopmentFooter';
import Extensions from '@jenkins-cd/js-extensions';
import rootReducer, { ACTION_TYPES } from './redux/router';
import Config from './config';
let config; // Holder for various app-wide state
/**
* Root Blue Ocean UI component
*/
class App extends Component {
getChildContext() {
return {config};
}
render() {
return (
<div className="Site">
<div id="outer">
<header className="global-header">
<Extensions.Renderer extensionPoint="jenkins.logo.top"/>
<nav>
<Link to="/pipelines">Pipelines</Link>
<a href="#">Administration</a>
</nav>
</header>
<main>
{this.props.children /* Set by react-router */ }
</main>
</div>
<DevelopmentFooter />
</div>
);
}
}
App.propTypes = {
children: PropTypes.node
};
App.childContextTypes = {
config: PropTypes.object
};
class NotFound extends Component {
// FIXME: We're going to need to polish this up at some point
render() {
return <h1>Not found</h1>;
}
}
function makeRoutes(routes) {
// Build up our list of top-level routes RR will ignore any non-route stuff put into this list.
const appRoutes = [
...routes,
// FIXME: Not sure best how to set this up without the hardcoded IndexRedirect :-/
<IndexRedirect to="/pipelines" />,
<Route path="*" component={NotFound}/>
];
const routeProps = {
path: "/",
component: App
};
return React.createElement(Route, routeProps, ...appRoutes);
}
function startApp(routes, stores) {
const rootElement = document.getElementById("root");
const headElement = document.getElementsByTagName("head")[0];
// Look up where the Blue Ocean app is hosted
let appURLBase = headElement.getAttribute("data-appurl");
if (typeof appURLBase !== "string") {
appURLBase = '';
}
// Look up some other URLs we may need
const rootURL = headElement.getAttribute("data-rooturl");
const resourceURL = headElement.getAttribute("data-resurl");
const adjunctURL = headElement.getAttribute("data-adjuncturl");
// Stash urls in our module-local var, so that App can put them on context.
config = new Config({
appURLBase,
rootURL,
resourceURL,
adjunctURL
});
// Using this non-default history because it allows us to specify the base url for the app
const history = useRouterHistory(createHistory)({
basename: appURLBase
});
// get all ExtensionPoints related to redux-stores
let store;
if (stores.length === 0) {
// if we do not have any stores we only add the location store
store = configureStore(combineReducers(rootReducer));
} else {
// some plugins provide they own store so combining with loction store
store = configureStore(combineReducers(
Object.assign({}, ...stores, rootReducer))
);
}
// on each change of the url we need to update the location object
history.listen(newLocation => {
const { dispatch, getState } = store;
const { current } = getState().location;
// no current happens on the first request
if (current) {
dispatch({
type: ACTION_TYPES.SET_LOCATION_PREVIOUS,
payload: current,
});
}
dispatch({
type: ACTION_TYPES.SET_LOCATION_CURRENT,
payload: newLocation.pathname,
});
});
// Start React
render(
<Provider store={store}>
<Router history={history}>{ makeRoutes(routes) }</Router>
</Provider>
, rootElement);
}
Extensions.store.getExtensions(['jenkins.main.routes', 'jenkins.main.stores'], (routes = [], stores = []) => {
startApp(routes, stores);
});