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) {
var resource = app.dataio.resource('builds');
resource.use('read', function(req, res) {
resource.use('readAll', function(req, res) {
Steppy(
function() {
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;
};

View File

@ -116,7 +116,7 @@ module.exports = function(app) {
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'));
});

View File

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

View File

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

View File

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

View File

@ -3,29 +3,32 @@
define([
'react',
'react-router',
'templates/app/index', 'app/components/index',
'templates/app/index',
'app/components/index',
'app/actions/project', 'app/actions/build'
], function(
React,
Router,
template, Components,
template,
Components,
ProjectActions, BuildActions
) {
var Route = React.createFactory(Router.Route),
DefaultRoute = React.createFactory(Router.DefaultRoute);
var routes = (
Route({name: 'dashboard', path: '/', handler: Components.App},
Route({name: 'projects', path: '/projects', handler: Components.ProjectsComponents.List})
Route({name: 'index', path: '/'},
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) {
React.render(template({
Component: Handler
}), document.getElementById('content'));
React.render(
template({Component: Handler, Header: Components.Header}),
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([
'app/components/builds/item',
'app/components/builds/list'
], function(Item, List) {
'app/components/builds/list',
'app/components/builds/view'
], function(Item, List, View) {
return {
Item: Item,
List: List
List: List,
View: View
};
});

View File

@ -13,12 +13,15 @@ mixin statusText(build)
.build(class="build__#{build.status}")
.build_controls.pull-right
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))
a(href="javascript:void(0);", onClick=this.onShowTerminal)
i.fa.fa-2x.fa-terminal(title="Rebuild")
i.fa.fa-2x.fa-repeat(title="Rebuild", onClick=this.onRebuildProject(build.project.name))
.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
span
span #
@ -53,4 +56,4 @@ mixin statusText(build)
if this.state.showTerminal
.build_terminal
Terminal(build=build)
Terminal(build=build.id)

View File

@ -1,17 +1,18 @@
'use strict';
define([
'react', 'app/actions/project',
'react', 'react-router', 'app/actions/project',
'app/actions/build', 'templates/app/components/builds/item',
'app/components/terminal/terminal',
'app/components/common/index'
], function(
React, ProjectActions, BuildActions, template,
React, Router, ProjectActions, BuildActions, template,
TerminalComponent, CommonComponents
) {
template = template.locals({
DateTime: CommonComponents.DateTime,
Terminal: TerminalComponent
Terminal: TerminalComponent,
Link: Router.Link
});
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([
'app/components/projects/index',
'app/components/builds/index',
'app/components/app',
], function(ProjectsComponents, BuildsComponents, App) {
'app/components/app/component',
'app/components/header/component'
], function(ProjectsComponents, BuildsComponents, App, Header) {
return {
App: App,
ProjectsComponents: ProjectsComponents,
BuildsComponents: BuildsComponents
Header: Header,
Project: ProjectsComponents,
Build: BuildsComponents
};
});

View File

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

View File

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

View File

@ -1,9 +1,5 @@
.navbar.navbar-default.navbar-fixed-top
.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'})
Header()
.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() {
var self = this;
resource.sync('read', function(err, builds) {
resource.sync('readAll', function(err, builds) {
if (err) throw err;
self.builds = builds;
self.trigger(self.builds);
});
}
},
});
return Store;

View File

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