1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-06 00:07:44 +01:00

Merge pull request #96 from finn-no/feature/react-router

Move to react-router.
This commit is contained in:
Ivar Conradi Østhus 2015-03-28 10:12:24 +01:00
commit f5f3421e3f
11 changed files with 121 additions and 163 deletions

View File

@ -52,6 +52,7 @@
"nconf": "0.7.1", "nconf": "0.7.1",
"pg": "4.3.0", "pg": "4.3.0",
"react": "^0.13.1", "react": "^0.13.1",
"react-router": "^0.13.2",
"reflux": "^0.2.5", "reflux": "^0.2.5",
"reqwest": "^1.1.4", "reqwest": "^1.1.4",
"webpack": "1.7.3", "webpack": "1.7.3",

View File

@ -1,52 +1,91 @@
var React = require('react'); var React = require('react');
var TabView = require('./components/TabView'); var Router = require('react-router');
var Menu = require('./components/Menu'); var Menu = require('./components/Menu');
var UserStore = require('./stores/UserStore');
var ErrorMessages = require('./components/ErrorMessages'); var ErrorMessages = require('./components/ErrorMessages');
var initalizer = require('./stores/initalizer'); var initalizer = require('./stores/initalizer');
var LogEntriesComponent = React.createFactory(require('./components/log/LogEntriesComponent')); var FeatureToggleStore = require('./stores/FeatureToggleStore');
var FeatureTogglesComponent = React.createFactory(require('./components/feature/FeatureTogglesComponent')); var StrategyStore = require('./stores/StrategyStore');
var StrategiesComponent = React.createFactory(require('./components/strategy/StrategiesComponent')); var ArchiveStore = require('./stores/ArchivedToggleStore');
var ArchiveFeatureComponent = React.createFactory(require('./components/feature/ArchiveFeatureComponent')); var Link = Router.Link;
var RouteHandler = Router.RouteHandler;
UserStore.init();
var tabPanes = [
{
name: 'Feature Toggles',
slug: 'feature-toggles',
content: FeatureTogglesComponent
},
{
name: 'Strategies',
slug: 'strategies',
content: StrategiesComponent
},
{
name: "Log",
slug: 'log',
content: LogEntriesComponent
},
{
name: "Archive",
slug: 'archive',
content: ArchiveFeatureComponent
}
];
var UnleashApp = React.createClass({ var UnleashApp = React.createClass({
contextTypes: {
router: React.PropTypes.func
},
getInitialState: function() {
return {
features: FeatureToggleStore.getFeatureToggles(),
strategies: StrategyStore.getStrategies(),
archivedFeatures: ArchiveStore.getArchivedToggles()
};
},
onFeatureToggleChange: function() {
this.setState({
features: FeatureToggleStore.getFeatureToggles()
});
},
onStrategiesChange: function() {
this.setState({
strategies: StrategyStore.getStrategies()
});
},
onArchiveChange: function() {
this.setState({
archivedFeatures: ArchiveStore.getArchivedToggles()
});
},
componentDidMount: function() {
this.unsubscribeFS = FeatureToggleStore.listen(this.onFeatureToggleChange);
this.unsubscribeSS = StrategyStore.listen(this.onStrategiesChange);
this.unsubscribeAS = ArchiveStore.listen(this.onArchiveChange);
},
componentWillUnmount: function() {
this.unsubscribeFS();
this.unsubscribeSS();
this.unsubscribeAS();
},
componentWillMount: function() { componentWillMount: function() {
initalizer(30); initalizer(30);
}, },
renderLink: function(id, label) {
return (
<Link to={id} className="nav-element centerify" activeClassName="nav-active">
<span className="topbar-nav-svg-caption caption showbydefault no-break">{label}</span>
</Link>
);
},
render: function () { render: function () {
return ( return (
<div> <div>
<Menu /> <Menu>
{this.renderLink("features", "Toggles")}
{this.renderLink("strategies", "Strategies")}
{this.renderLink("log", "Log")}
{this.renderLink("archive", "Archive")}
</Menu>
<div className="container"> <div className="container">
<div className="page"> <div className="page">
<ErrorMessages /> <ErrorMessages />
<TabView tabPanes={tabPanes} /> <div className="mod shadow mrn pan">
<div className="inner pan">
<div className="bd">
<RouteHandler
features={this.state.features}
strategies={this.state.strategies}
archivedFeatures={this.state.archivedFeatures}
/>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -54,4 +93,5 @@ var UnleashApp = React.createClass({
} }
}); });
module.exports = UnleashApp; module.exports = UnleashApp;

View File

@ -16,13 +16,8 @@ describe("FeatureForm", function () {
{ name: "featureY" } { name: "featureY" }
]; ];
Server.getArchivedFeatures.mockImplementation(function(cb) { Component = TestUtils.renderIntoDocument(
cb(null, archivedToggles); <FeatureArchive archivedFeatures={archivedToggles} />);
});
FeatureToggleStore.initStore(archivedToggles);
Component = TestUtils.renderIntoDocument(<FeatureArchive />);
}); });
afterEach(function() { afterEach(function() {

View File

@ -1,3 +1,10 @@
var React = require('react'); var React = require('react');
var UnleashApp = require('./UnleashApp'); var Router = require('react-router');
React.render(<UnleashApp />, document.getElementById('content')); var UserStore = require('./stores/UserStore');
var routes = require('./routes');
UserStore.init();
Router.run(routes, function (Handler) {
React.render(<Handler/>, document.getElementById('content'));
});

View File

@ -10,7 +10,7 @@ var Menu = React.createClass({
<User /> <User />
</div> </div>
<div className="nav-level1 h4"> <div className="nav-level1 h4">
<a href="" className="homelink pln"> <a href="#" className="homelink pln">
<span className="topbar-nav-svg-home"> <span className="topbar-nav-svg-home">
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53M <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53M
y5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MjcuNDExIiBoZWlnaHQ9IjE2OS4z y5vcmcvMjAwMC9zdmciIHdpZHRoPSI1MjcuNDExIiBoZWlnaHQ9IjE2OS4z
@ -50,6 +50,7 @@ var Menu = React.createClass({
unleash admin unleash admin
</span> </span>
</a> </a>
{this.props.children}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,62 +0,0 @@
var React = require('react');
var TabView = React.createClass({
getDefaultProps: function() {
return {tabPanes: []};
},
getInitialState: function() {
var activeTab = this.props.tabPanes[0];
var userHash = window.location.hash;
if(userHash) {
userHash = userHash.split("#")[1];
this.props.tabPanes.forEach(function(pane) {
if(pane.slug === userHash) {
activeTab = pane;
}
}.bind(this));
}
return {activeTab: activeTab};
},
onChangeTab: function(tabPane) {
this.setState({activeTab: tabPane});
},
render: function() {
var tabNodes = this.props.tabPanes.map(function (tabPane) {
return (
<li key={tabPane.name} className=
{tabPane.name === this.state.activeTab.name ? "active": ""}>
<a href={"#" + tabPane.slug}
onClick={this.onChangeTab.bind(this, tabPane)}>
{tabPane.name}
</a>
</li>
);
}.bind(this));
return (
<div>
<ul className="tabs mbn">
{tabNodes}
</ul>
<div className="tab-content">
<div className="active">
<div className="mod shadow mrn pan">
<div className="inner pan">
<div className="bd">
{new this.state.activeTab.content()}
</div>
</div>
</div>
</div>
</div>
</div>
);
}
});
module.exports = TabView;

View File

@ -1,27 +1,7 @@
var React = require("react"); var React = require("react");
var FeatureActions = require('../../stores/FeatureToggleActions'); var FeatureActions = require('../../stores/FeatureToggleActions');
var FeatureToggleStore = require('../../stores/ArchivedToggleStore');
var ArchiveFeatureComponent = React.createClass({ var ArchiveFeatureComponent = React.createClass({
getInitialState: function() {
return {
archivedFeatures: FeatureToggleStore.getArchivedToggles()
};
},
onStoreChange: function() {
this.setState({
archivedFeatures: FeatureToggleStore.getArchivedToggles()
});
},
componentDidMount: function() {
this.unsubscribe = FeatureToggleStore.listen(this.onStoreChange);
},
componentWillUnmount: function() {
this.unsubscribe();
},
onRevive: function(item) { onRevive: function(item) {
FeatureActions.revive.triggerPromise(item); FeatureActions.revive.triggerPromise(item);
@ -30,7 +10,8 @@ var ArchiveFeatureComponent = React.createClass({
render: function () { render: function () {
return ( return (
<div> <div>
<h1>Archived feature toggles</h1> <h1>Archived Feature Toggles</h1>
<hr />
<table className="outerborder man"> <table className="outerborder man">
<thead> <thead>
<tr> <tr>
@ -39,7 +20,7 @@ var ArchiveFeatureComponent = React.createClass({
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{this.state.archivedFeatures.map(this.renderArchivedItem)} {this.props.archivedFeatures.map(this.renderArchivedItem)}
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -3,29 +3,14 @@ var FeatureList = require('./FeatureList');
var FeatureForm = require('./FeatureForm'); var FeatureForm = require('./FeatureForm');
var FeatureActions = require('../../stores/FeatureToggleActions'); var FeatureActions = require('../../stores/FeatureToggleActions');
var ErrorActions = require('../../stores/ErrorActions'); var ErrorActions = require('../../stores/ErrorActions');
var FeatureToggleStore = require('../../stores/FeatureToggleStore');
var StrategyStore = require('../../stores/StrategyStore');
var FeatureTogglesComponent = React.createClass({ var FeatureTogglesComponent = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
features: FeatureToggleStore.getFeatureToggles(),
createView: false createView: false
}; };
}, },
onFeatureToggleChange: function() {
this.setState({
features: FeatureToggleStore.getFeatureToggles()
});
},
componentDidMount: function() {
this.unsubscribe = FeatureToggleStore.listen(this.onFeatureToggleChange);
},
componentWillUnmount: function() {
this.unsubscribe();
},
updateFeature: function (feature) { updateFeature: function (feature) {
FeatureActions.update.triggerPromise(feature); FeatureActions.update.triggerPromise(feature);
}, },
@ -52,16 +37,18 @@ var FeatureTogglesComponent = React.createClass({
return ( return (
<div> <div>
<h1>Feature Toggles</h1>
{this.state.createView ? this.renderCreateView() : this.renderCreateButton()} {this.state.createView ? this.renderCreateView() : this.renderCreateButton()}
<FeatureList <FeatureList
features={this.state.features} features={this.props.features}
onFeatureChanged={this.updateFeature} onFeatureChanged={this.updateFeature}
onFeatureArchive={this.archiveFeature} onFeatureArchive={this.archiveFeature}
onFeatureSubmit={this.createFeature} onFeatureSubmit={this.createFeature}
onFeatureCancel={this.cancelNewFeature} onFeatureCancel={this.cancelNewFeature}
onNewFeature={this.newFeature} onNewFeature={this.newFeature}
strategies={StrategyStore.getStrategies()} /> strategies={this.props.strategies} />
</div> </div>
); );
}, },
@ -70,7 +57,7 @@ var FeatureTogglesComponent = React.createClass({
return <FeatureForm return <FeatureForm
onCancel={this.cancelNewFeature} onCancel={this.cancelNewFeature}
onSubmit={this.createFeature} onSubmit={this.createFeature}
strategies={StrategyStore.getStrategies()} />; strategies={this.props.strategies} />;
}, },
renderCreateButton: function() { renderCreateButton: function() {

View File

@ -24,6 +24,7 @@ var LogEntriesComponent = React.createClass({
render: function() { render: function() {
return ( return (
<div> <div>
<h1>Log</h1>
<hr /> <hr />
<LogEntryList events={this.state.events} /> <LogEntryList events={this.state.events} />
</div> </div>

View File

@ -1,29 +1,15 @@
var React = require('react'); var React = require('react');
var StrategyList = require('./StrategyList'); var StrategyList = require('./StrategyList');
var StrategyForm = require('./StrategyForm'); var StrategyForm = require('./StrategyForm');
var StrategyStore = require('../../stores/StrategyStore');
var StrategyActions = require('../../stores/StrategyActions'); var StrategyActions = require('../../stores/StrategyActions');
var StrategiesComponent = React.createClass({ var StrategiesComponent = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
createView: false, createView: false
strategies: StrategyStore.getStrategies()
}; };
}, },
onStoreChange: function() {
this.setState({
strategies: StrategyStore.getStrategies()
});
},
componentDidMount: function() {
this.unsubscribe = StrategyStore.listen(this.onStoreChange);
},
componentWillUnmount: function() {
this.unsubscribe();
},
onNewStrategy: function() { onNewStrategy: function() {
this.setState({createView: true}); this.setState({createView: true});
}, },
@ -44,11 +30,12 @@ var StrategiesComponent = React.createClass({
render: function() { render: function() {
return ( return (
<div> <div>
<h1>Activation Strategies</h1>
{this.state.createView ? {this.state.createView ?
this.renderCreateView() : this.renderCreateButton()} this.renderCreateView() : this.renderCreateButton()}
<hr /> <hr />
<StrategyList <StrategyList
strategies={this.state.strategies} strategies={this.props.strategies}
onRemove={this.onRemove} /> onRemove={this.onRemove} />
</div> </div>
); );

20
public/js/routes.jsx Normal file
View File

@ -0,0 +1,20 @@
var React = require('react');
var Router = require('react-router');
var UnleashApp = require('./UnleashApp');
var LogEntriesComponent = require('./components/log/LogEntriesComponent');
var FeatureTogglesComponent = require('./components/feature/FeatureTogglesComponent');
var StrategiesComponent = require('./components/strategy/StrategiesComponent');
var ArchiveFeatureComponent = require('./components/feature/ArchiveFeatureComponent');
var DefaultRoute = Router.DefaultRoute;
var Route = Router.Route;
var routes = (
<Route name="app" path="/" handler={UnleashApp}>
<Route name="strategies" handler={StrategiesComponent}/>
<Route name="log" handler={LogEntriesComponent}/>
<Route name="archive" handler={ArchiveFeatureComponent}/>
<DefaultRoute name="features" handler={FeatureTogglesComponent}/>
</Route>
);
module.exports = routes;