show a list of milestones for a project
This commit is contained in:
parent
fee4d13696
commit
eec0259fea
|
@ -92,6 +92,8 @@ export default React.createClass({
|
||||||
|
|
||||||
// Show project milestones.
|
// Show project milestones.
|
||||||
milestones(owner, name) {
|
milestones(owner, name) {
|
||||||
|
document.title = `${owner}/${name}`;
|
||||||
|
process.nextTick(() => { actions.emit('projects.load', { owner, name }); });
|
||||||
return <MilestonesPage owner={owner} name={name} />;
|
return <MilestonesPage owner={owner} name={name} />;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ import Link from './Link.jsx';
|
||||||
|
|
||||||
export default React.createClass({
|
export default React.createClass({
|
||||||
|
|
||||||
displayName: 'Projects.jsx',
|
displayName: 'Milestones.jsx',
|
||||||
|
|
||||||
mixins: [ Format ],
|
mixins: [ Format ],
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export default React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let projects = this.props.projects;
|
let { projects, project } = this.props;
|
||||||
|
|
||||||
// Show the projects with errors first.
|
// Show the projects with errors first.
|
||||||
let errors = _(projects.list).filter('errors').map((project, i) => {
|
let errors = _(projects.list).filter('errors').map((project, i) => {
|
||||||
|
@ -36,12 +36,16 @@ export default React.createClass({
|
||||||
);
|
);
|
||||||
}).value();
|
}).value();
|
||||||
|
|
||||||
// Now for the list of projects.
|
// Now for the list of milestones.
|
||||||
let list = _.map(projects.index, ([ pI, mI ]) => {
|
let list = [];
|
||||||
|
_.each(projects.index, ([ pI, mI ]) => {
|
||||||
let { owner, name, milestones } = projects.list[pI];
|
let { owner, name, milestones } = projects.list[pI];
|
||||||
let milestone = milestones[mI];
|
let milestone = milestones[mI];
|
||||||
|
|
||||||
return (
|
// Filter down?
|
||||||
|
if (!(!project || (project.owner == owner && project.name == name))) return;
|
||||||
|
|
||||||
|
list.push(
|
||||||
<tr className={cls({ 'done': milestone.stats.isDone })} key={`${pI}-${mI}`}>
|
<tr className={cls({ 'done': milestone.stats.isDone })} key={`${pI}-${mI}`}>
|
||||||
<td className="repo">
|
<td className="repo">
|
||||||
<Link route={{ 'to': 'milestones', 'params': { owner, name } }} className="project">
|
<Link route={{ 'to': 'milestones', 'params': { owner, name } }} className="project">
|
||||||
|
@ -74,21 +78,38 @@ export default React.createClass({
|
||||||
// Wait for something to show.
|
// Wait for something to show.
|
||||||
if (!errors.length && !list.length) return false;
|
if (!errors.length && !list.length) return false;
|
||||||
|
|
||||||
return (
|
if (project) {
|
||||||
<div id="projects">
|
return (
|
||||||
<div className="header">
|
<div id="projects">
|
||||||
<a className="sort" onClick={this._onSort}><Icon name="sort"/> Sorted by {projects.sortBy}</a>
|
<div className="header">
|
||||||
<h2>Projects</h2>
|
<a className="sort" onClick={this._onSort}><Icon name="sort"/> Sorted by {projects.sortBy}</a>
|
||||||
|
<h2>Milestones</h2>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{list}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div className="footer" />
|
||||||
</div>
|
</div>
|
||||||
<table>
|
);
|
||||||
<tbody>
|
} else {
|
||||||
{errors}
|
return (
|
||||||
{list}
|
<div id="projects">
|
||||||
</tbody>
|
<div className="header">
|
||||||
</table>
|
<a className="sort" onClick={this._onSort}><Icon name="sort"/> Sorted by {projects.sortBy}</a>
|
||||||
<div className="footer" />
|
<h2>Projects</h2>
|
||||||
</div>
|
</div>
|
||||||
);
|
<table>
|
||||||
|
<tbody>
|
||||||
|
{errors}
|
||||||
|
{list}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div className="footer" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
|
@ -4,6 +4,8 @@ import Page from '../mixins/Page.js';
|
||||||
|
|
||||||
import Notify from '../components/Notify.jsx';
|
import Notify from '../components/Notify.jsx';
|
||||||
import Header from '../components/Header.jsx';
|
import Header from '../components/Header.jsx';
|
||||||
|
import Milestones from '../components/Milestones.jsx';
|
||||||
|
import Hero from '../components/Hero.jsx';
|
||||||
|
|
||||||
export default React.createClass({
|
export default React.createClass({
|
||||||
|
|
||||||
|
@ -12,12 +14,25 @@ export default React.createClass({
|
||||||
mixins: [ Page ],
|
mixins: [ Page ],
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
let content;
|
||||||
|
if (!this.state.app.loading) {
|
||||||
|
let projects = this.state.projects;
|
||||||
|
content = <Milestones projects={projects} project={this.props} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Notify />
|
<Notify />
|
||||||
<Header {...this.state} />
|
<Header {...this.state} />
|
||||||
|
|
||||||
<div id="page" />
|
<div id="page">
|
||||||
|
<div id="title">
|
||||||
|
<div className="wrap">
|
||||||
|
<h2 className="title">{this.props.owner}/{this.props.name}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="content" className="wrap">{content}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<div className="wrap">
|
<div className="wrap">
|
||||||
|
|
|
@ -4,7 +4,7 @@ import Page from '../mixins/Page.js';
|
||||||
|
|
||||||
import Notify from '../components/Notify.jsx';
|
import Notify from '../components/Notify.jsx';
|
||||||
import Header from '../components/Header.jsx';
|
import Header from '../components/Header.jsx';
|
||||||
import Projects from '../components/Projects.jsx';
|
import Milestones from '../components/Milestones.jsx';
|
||||||
import Hero from '../components/Hero.jsx';
|
import Hero from '../components/Hero.jsx';
|
||||||
|
|
||||||
export default React.createClass({
|
export default React.createClass({
|
||||||
|
@ -18,8 +18,7 @@ export default React.createClass({
|
||||||
if (!this.state.app.loading) {
|
if (!this.state.app.loading) {
|
||||||
let projects = this.state.projects;
|
let projects = this.state.projects;
|
||||||
if (projects.list.length) {
|
if (projects.list.length) {
|
||||||
// Show a list of projects.
|
content = <Milestones projects={projects} />;
|
||||||
content = <Projects projects={projects} />;
|
|
||||||
} else {
|
} else {
|
||||||
content = <Hero />;
|
content = <Hero />;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,46 +59,62 @@ class ProjectsStore extends Store {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start fetching milestones and issues for projects.
|
// Fetch milestones and issues for a project(s).
|
||||||
onProjectsLoad() {
|
onProjectsLoad(project) {
|
||||||
let projects = this.get('list');
|
let projects = this.get('list');
|
||||||
|
|
||||||
// Quit if we have no projects.
|
// Quit if we have no projects.
|
||||||
if (!projects.length) return;
|
if (!projects.length) return;
|
||||||
|
|
||||||
|
// Fetch milestones and issues for a project.
|
||||||
|
let get = (user, p) => {
|
||||||
|
// Fetch their milestones.
|
||||||
|
milestones.fetchAll(user, p, this.cb((err, milestones) => { // async
|
||||||
|
// Save the error if project does not exist.
|
||||||
|
if (err) return this.saveError(p, err);
|
||||||
|
// Now add in the issues.
|
||||||
|
milestones.forEach((milestone) => {
|
||||||
|
// Do we have this milestone already? Skip fetching issues then.
|
||||||
|
if (_.find(p.milestones, ({ number }) => {
|
||||||
|
return milestone.number === number;
|
||||||
|
})) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// OK fetch all the issues for this milestone then.
|
||||||
|
issues.fetchAll(user, {
|
||||||
|
'owner': p.owner,
|
||||||
|
'name': p.name,
|
||||||
|
'milestone': milestone.number
|
||||||
|
}, this.cb((err, obj) => { // async
|
||||||
|
// Save any errors on the project.
|
||||||
|
if (err) return this.saveError(p, err);
|
||||||
|
// Add in the issues to the milestone.
|
||||||
|
_.extend(milestone, { 'issues': obj });
|
||||||
|
// Save the milestone.
|
||||||
|
this.addMilestone(p, milestone);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
// Wait for the user to get resolved.
|
// Wait for the user to get resolved.
|
||||||
this.get('user', this.cb((user) => { // async
|
this.get('user', this.cb((user) => { // async
|
||||||
// For all projects.
|
if (project) {
|
||||||
projects.forEach((project) => {
|
// For a single project.
|
||||||
// Fetch their milestones.
|
_.find(this.get('list'), (obj) => {
|
||||||
milestones.fetchAll(user, project, this.cb((err, milestones) => { // async
|
if (project.owner == obj.owner && project.name == obj.name) {
|
||||||
// Save the error if project does not exist.
|
project = obj; // expand by saved properties
|
||||||
if (err) return this.saveError(project, err);
|
return true;
|
||||||
// Now add in the issues.
|
};
|
||||||
milestones.forEach((milestone) => {
|
return false;
|
||||||
// Do we have this milestone already? Skip fetching issues then.
|
});
|
||||||
if (_.find(project.milestones, ({ number }) => {
|
// For a single project.
|
||||||
return milestone.number === number;
|
get(user, project);
|
||||||
})) {
|
} else {
|
||||||
return;
|
// For all projects.
|
||||||
}
|
projects.forEach(_.partial(get, user));
|
||||||
|
}
|
||||||
// OK fetch all the issues for this milestone then.
|
|
||||||
issues.fetchAll(user, {
|
|
||||||
'owner': project.owner,
|
|
||||||
'name': project.name,
|
|
||||||
'milestone': milestone.number
|
|
||||||
}, this.cb((err, obj) => { // async
|
|
||||||
// Save any errors on the project.
|
|
||||||
if (err) return this.saveError(project, err);
|
|
||||||
// Add in the issues to the milestone.
|
|
||||||
_.extend(milestone, { 'issues': obj });
|
|
||||||
// Save the milestone.
|
|
||||||
this.addMilestone(project, milestone);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue