client side routing

This commit is contained in:
Vladimir Polyakov 2015-05-17 16:48:16 +03:00
parent 40338bb654
commit f310239279
23 changed files with 197 additions and 67 deletions

View File

@ -7,7 +7,7 @@ var Steppy = require('twostep').Steppy,
module.exports = function(app) { module.exports = function(app) {
var resource = app.dataio.resource('builds'); var resource = app.dataio.resource('builds');
resource.use('read', function(req, res) { resource.use('readAll', function(req, res) {
Steppy( Steppy(
function() { function() {
var findParams = _(req.data).pick('offset', 'limit'); var findParams = _(req.data).pick('offset', 'limit');
@ -25,5 +25,21 @@ module.exports = function(app) {
); );
}); });
resource.use('read', function(req, res) {
Steppy(
function() {
var findParams = {};
findParams.start = _(req.data).pick('id');
db.builds.find(findParams, this.slot());
},
function(err, build) {
res.send(build[0]);
},
function(err) {
console.log(err.stack || err)
}
);
});
return resource; return resource;
}; };

View File

@ -116,7 +116,7 @@ module.exports = function(app) {
app.dataio.resource('build' + build.id).clientEmitSync('data', data); app.dataio.resource('build' + build.id).clientEmitSync('data', data);
}); });
resource.use('read', function(req, res) { resource.use('readAll', function(req, res) {
res.send(_(projects).pluck('config')); res.send(_(projects).pluck('config'));
}); });

View File

@ -2,6 +2,6 @@ body {
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
} }
.main-row { .page-wrapper {
margin-top: @navbar-height + 15px; margin-top: @navbar-height + 15px;
} }

View File

@ -1,6 +1,6 @@
.terminal { .terminal {
&_code { &_code {
max-height: 100px; /*max-height: 100px;*/
overflow-y: scroll; /*overflow-y: scroll;*/
} }
} }

View File

@ -3,7 +3,8 @@
define(['reflux'], function(Reflux) { define(['reflux'], function(Reflux) {
var Actions = Reflux.createActions([ var Actions = Reflux.createActions([
'readTerminalOutput', 'readTerminalOutput',
'readAll' 'readAll',
'read'
]); ]);
return Actions; return Actions;

View File

@ -3,29 +3,32 @@
define([ define([
'react', 'react',
'react-router', 'react-router',
'templates/app/index', 'app/components/index', 'templates/app/index',
'app/components/index',
'app/actions/project', 'app/actions/build' 'app/actions/project', 'app/actions/build'
], function( ], function(
React, React,
Router, Router,
template, Components, template,
Components,
ProjectActions, BuildActions ProjectActions, BuildActions
) { ) {
var Route = React.createFactory(Router.Route), var Route = React.createFactory(Router.Route),
DefaultRoute = React.createFactory(Router.DefaultRoute); DefaultRoute = React.createFactory(Router.DefaultRoute);
var routes = ( var routes = (
Route({name: 'dashboard', path: '/', handler: Components.App}, Route({name: 'index', path: '/'},
Route({name: 'projects', path: '/projects', handler: Components.ProjectsComponents.List}) Route({name: 'dashboard', path: '/', handler: Components.App}),
Route({name: 'projects', path: 'projects', handler: Components.Project.List}),
Route({name: 'build', path: 'builds/:id', handler: Components.Build.View})
) )
); );
Router.run(routes, Router.HistoryLocation, function(Handler) { Router.run(routes, Router.HistoryLocation, function(Handler) {
React.render(template({ React.render(
Component: Handler template({Component: Handler, Header: Components.Header}),
}), document.getElementById('content')); document.getElementById('content')
);
}); });
ProjectActions.readAll();
BuildActions.readAll();
}); });

View File

@ -1,20 +0,0 @@
'use strict';
define([
'react',
'app/components/projects/index',
'app/components/builds/index',
'app/components/terminal/index',
'templates/app/components/app'
], function(React, Projects, Builds, Console, template) {
var Component = React.createClass({
render: function() {
return template({
ProjectsList: Projects.List,
BuildsList: Builds.List
});
}
});
return Component;
});

View File

@ -0,0 +1,25 @@
'use strict';
define([
'react',
'app/actions/project',
'app/actions/build',
'app/components/projects/index',
'app/components/builds/index',
'templates/app/components/app/template'
], function(React, ProjectActions, BuildActions, Projects, Builds, template) {
template = template.locals({
ProjectsList: Projects.List,
BuildsList: Builds.List
});
var Component = React.createClass({
componentWillMount: function() {
ProjectActions.readAll();
BuildActions.readAll();
},
render: template
});
return Component;
});

View File

@ -2,10 +2,12 @@
define([ define([
'app/components/builds/item', 'app/components/builds/item',
'app/components/builds/list' 'app/components/builds/list',
], function(Item, List) { 'app/components/builds/view'
], function(Item, List, View) {
return { return {
Item: Item, Item: Item,
List: List List: List,
View: View
}; };
}); });

View File

@ -13,12 +13,15 @@ mixin statusText(build)
.build(class="build__#{build.status}") .build(class="build__#{build.status}")
.build_controls.pull-right .build_controls.pull-right
a(href="javascript:void(0);", onClick=this.onBuildSelect(build.id)) a(href="javascript:void(0);", onClick=this.onBuildSelect(build.id))
i.fa.fa-2x.fa-repeat(title="Rebuild", style={marginRight: '15px'}, onClick=this.onRebuildProject(build.project.name)) i.fa.fa-2x.fa-repeat(title="Rebuild", onClick=this.onRebuildProject(build.project.name))
a(href="javascript:void(0);", onClick=this.onShowTerminal)
i.fa.fa-2x.fa-terminal(title="Rebuild")
.build_header .build_header
a(href="javascript:void(0)")= build.project.name if build.status !== 'queued'
Link(to="build", params={id: build.id})
span= build.project.name
else
span= build.project.name
if build.number if build.number
span span
span # span #
@ -53,4 +56,4 @@ mixin statusText(build)
if this.state.showTerminal if this.state.showTerminal
.build_terminal .build_terminal
Terminal(build=build) Terminal(build=build.id)

View File

@ -1,17 +1,18 @@
'use strict'; 'use strict';
define([ define([
'react', 'app/actions/project', 'react', 'react-router', 'app/actions/project',
'app/actions/build', 'templates/app/components/builds/item', 'app/actions/build', 'templates/app/components/builds/item',
'app/components/terminal/terminal', 'app/components/terminal/terminal',
'app/components/common/index' 'app/components/common/index'
], function( ], function(
React, ProjectActions, BuildActions, template, React, Router, ProjectActions, BuildActions, template,
TerminalComponent, CommonComponents TerminalComponent, CommonComponents
) { ) {
template = template.locals({ template = template.locals({
DateTime: CommonComponents.DateTime, DateTime: CommonComponents.DateTime,
Terminal: TerminalComponent Terminal: TerminalComponent,
Link: Router.Link
}); });
var Component = React.createClass({ var Component = React.createClass({

View File

@ -0,0 +1,5 @@
if this.state.build
h2
span Build #
span= this.state.build.number
Terminal(build=this.state.build.id)

View File

@ -0,0 +1,39 @@
'use strict';
define([
'react',
'reflux',
'app/actions/build',
'app/stores/build',
'app/components/terminal/terminal',
'templates/app/components/builds/view'
], function(
React, Reflux, BuildActions, buildStore, TerminalComponent, template
) {
template = template.locals({
Terminal: TerminalComponent
});
var Component = React.createClass({
mixins: [Reflux.ListenerMixin],
componentDidMount: function() {
BuildActions.read(Number(this.props.params.id));
this.listenTo(buildStore, this.updateBuild);
},
updateBuild: function(build) {
if (!this.state.build && build) {
BuildActions.readTerminalOutput(build);
}
this.setState({build: build});
},
render: template,
getInitialState: function() {
return {
build: null
};
}
});
return Component;
});

View File

@ -0,0 +1,17 @@
'use strict';
define([
'react',
'react-router',
'templates/app/components/header/template'
], function(React, Router, template) {
template = template.locals({
Link: Router.Link
});
var Component = React.createClass({
render: template
});
return Component;
});

View File

@ -0,0 +1,8 @@
.navbar.navbar-default.navbar-fixed-top
.container-fluid
.navbar-header
a.navbar-brand(href="/")
span Company Brand Name CI
form.navbar-left.navbar-form
.form-group
input.form-control(placeholder="Start typing project name...", style={width: '220px'})

View File

@ -3,11 +3,13 @@
define([ define([
'app/components/projects/index', 'app/components/projects/index',
'app/components/builds/index', 'app/components/builds/index',
'app/components/app', 'app/components/app/component',
], function(ProjectsComponents, BuildsComponents, App) { 'app/components/header/component'
], function(ProjectsComponents, BuildsComponents, App, Header) {
return { return {
App: App, App: App,
ProjectsComponents: ProjectsComponents, Header: Header,
BuildsComponents: BuildsComponents Project: ProjectsComponents,
Build: BuildsComponents
}; };
}); });

View File

@ -1,2 +1,2 @@
.terminal .terminal
pre.terminal_code= data pre.terminal_code= this.state.data

View File

@ -13,16 +13,13 @@ define([
}, },
updateItems: function(data) { updateItems: function(data) {
// listen just our console update // listen just our console update
if (data.buildId === this.props.build.id) { if (data.buildId === this.props.build) {
this.setState({data: data}); this.setState({data: data});
} }
}, },
render: function() { render: template,
return template(this.state.data);
},
getInitialState: function() { getInitialState: function() {
return { return {
name: '',
data: '' data: ''
}; };
} }

View File

@ -1,9 +1,5 @@
.navbar.navbar-default.navbar-fixed-top Header()
.container-fluid
.navbar-header
a.navbar-brand(href="javascript:void(0);") Company Brand Name CI
form.navbar-left.navbar-form
.form-group
input.form-control(placeholder="Start typing project name...", style={width: '220px'})
.container-fluid .container-fluid
Component() .page-wrapper
Component()

View File

@ -0,0 +1,35 @@
'use strict';
define([
'underscore',
'reflux', 'app/actions/build', 'app/resources'
], function(_, Reflux, BuildActions, resources) {
var resource = resources.builds;
var Store = Reflux.createStore({
listenables: BuildActions,
build: null,
onChange: function(data, action) {
if (this.build && (data.buildId === this.build.id)) {
_(this.build).extend(data.changes);
this.trigger(this.build);
}
},
init: function() {
resource.subscribe('change', this.onChange);
},
onRead: function(id) {
var self = this;
resource.sync('read', {id: id}, function(err, build) {
if (err) throw err;
self.build = build;
self.trigger(self.build);
});
}
});
return Store;
});

View File

@ -29,12 +29,12 @@ define([
onReadAll: function() { onReadAll: function() {
var self = this; var self = this;
resource.sync('read', function(err, builds) { resource.sync('readAll', function(err, builds) {
if (err) throw err; if (err) throw err;
self.builds = builds; self.builds = builds;
self.trigger(self.builds); self.trigger(self.builds);
}); });
} },
}); });
return Store; return Store;

View File

@ -14,7 +14,7 @@ define([
}, },
onReadAll: function() { onReadAll: function() {
var self = this; var self = this;
resource.sync('read', function(err, projects) { resource.sync('readAll', function(err, projects) {
if (err) throw err; if (err) throw err;
self.trigger(projects); self.trigger(projects);
}); });