Handle task interaction like story interaction
When moving or adding tasks, instead of waiting for the user to reselect the task reload the task each time.
This commit is contained in:
parent
bdd07b68ca
commit
84ae7a5fd4
3 changed files with 54 additions and 15 deletions
|
@ -46,11 +46,13 @@
|
|||
(defmethod datastore-get-story ((datastore pg-datastore) id)
|
||||
(with-connection (connection-spec datastore)
|
||||
(append (query (:select :* :from 'story :where (:= 'id id)) :alist)
|
||||
`((tasks . ,(query (:order-by
|
||||
(:select :* :from 'task
|
||||
:where (:= 'story-id id))
|
||||
`((tasks . ,(datastore-get-tasks-for-story datastore id))))))
|
||||
|
||||
(defmethod datastore-get-tasks-for-story ((datastore pg-datastore) id)
|
||||
(with-connection (connection-spec datastore)
|
||||
(query (:order-by (:select :* :from 'task :where (:= 'story-id id))
|
||||
'priority)
|
||||
:alists))))))
|
||||
:alists)))
|
||||
|
||||
(defmethod datastore-post-story
|
||||
((datastore pg-datastore) role necessity title content reporter)
|
||||
|
|
16
scrumli.lisp
16
scrumli.lisp
|
@ -105,12 +105,13 @@
|
|||
(encode-json-to-string '((status . "ok"))))
|
||||
403))
|
||||
|
||||
(define-route tasks-new ("stories/tasks/new" :method :post)
|
||||
(define-route tasks-new ("stories/tasks/new" :method :post
|
||||
:content-type "text/json")
|
||||
(if (logged-in-p)
|
||||
(with-post-parameters ("storyId" "description")
|
||||
(post-task storyid description
|
||||
(hunchentoot:session-value :username))
|
||||
200)
|
||||
(encode-json-to-string '((status . "ok"))))
|
||||
403))
|
||||
|
||||
(define-route stories-state ("stories/state" :method :post
|
||||
|
@ -148,12 +149,13 @@
|
|||
(encode-json-to-string '((status . "ok"))))
|
||||
403))
|
||||
|
||||
(define-route task-priority ("tasks/:dir" :method :post)
|
||||
(define-route task-priority ("tasks/:dir" :method :post
|
||||
:content-type "text/json")
|
||||
(if (logged-in-p)
|
||||
(let* ((id (hunchentoot:post-parameter "id")))
|
||||
(story-change-priority
|
||||
'task id (intern (string-upcase dir) :keyword))
|
||||
200)
|
||||
(encode-json-to-string '((status . "ok"))))
|
||||
403))
|
||||
|
||||
(define-route login-page ("login")
|
||||
|
@ -217,3 +219,9 @@
|
|||
(if (logged-in-p)
|
||||
(encode-json-to-string (get-story id))
|
||||
403))
|
||||
|
||||
(define-route scrumli-story-tasks ("stories/:id/tasks"
|
||||
:content-type "json")
|
||||
(if (logged-in-p)
|
||||
(encode-json-to-string (get-tasks-for-story id))
|
||||
403))
|
||||
|
|
|
@ -20,10 +20,18 @@ var StoryTaskRow = React.createClass({
|
|||
return {state: this.props.task.state};
|
||||
},
|
||||
moveUp: React.autoBind(function(event) {
|
||||
$.post("/tasks/up", {'id': this.props.task.id});
|
||||
$.post("/tasks/up", {'id': this.props.task.id})
|
||||
.done(function (data) {
|
||||
if (data.status == "ok")
|
||||
this.props.onMoved(1);
|
||||
}.bind(this));
|
||||
}),
|
||||
moveDown: React.autoBind(function(event) {
|
||||
$.post("/tasks/down", {'id': this.props.task.id});
|
||||
$.post("/tasks/down", {'id': this.props.task.id})
|
||||
.done(function (data) {
|
||||
if (data.status == "ok")
|
||||
this.props.onMoved(-1);
|
||||
}.bind(this));
|
||||
}),
|
||||
render: function() {
|
||||
return (
|
||||
|
@ -50,7 +58,8 @@ var StoryTaskRow = React.createClass({
|
|||
var StoryTaskTable = React.createClass({
|
||||
render: function() {
|
||||
var taskNodes = this.props.tasks.map(function (task) {
|
||||
return <StoryTaskRow task={task} />;
|
||||
return <StoryTaskRow task={task}
|
||||
onMoved={this.props.onTaskMoved} />;
|
||||
}.bind(this));
|
||||
|
||||
return (
|
||||
|
@ -91,14 +100,32 @@ var StoryTaskForm = React.createClass({
|
|||
var StoryData = React.createClass({
|
||||
handleTaskSubmit: React.autoBind(function (task) {
|
||||
task.storyId = this.state.data.id;
|
||||
$.post("/stories/tasks/new", task);
|
||||
$.post("/stories/tasks/new", task)
|
||||
.done(function(data) {
|
||||
if (data.status == "ok")
|
||||
this.loadStoryFromServer();
|
||||
}.bind(this));
|
||||
}),
|
||||
loadStoryFromServer: function() {
|
||||
$.get("/stories/" + this.state.data.id)
|
||||
.done(this.setData.bind(this));
|
||||
},
|
||||
componentWillMount: function() {
|
||||
setInterval(
|
||||
this.loadStoryFromServer.bind(this),
|
||||
this.props.pollInterval
|
||||
);
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {data: null};
|
||||
},
|
||||
setData: function(data) {
|
||||
this.setState({data: null});
|
||||
this.setState({data: data});
|
||||
},
|
||||
handleTaskMoved: React.autoBind(function(direction) {
|
||||
this.loadStoryFromServer();
|
||||
}),
|
||||
render: function() {
|
||||
if (this.state.data) {
|
||||
return (<div>
|
||||
|
@ -107,7 +134,8 @@ var StoryData = React.createClass({
|
|||
<div class="well">
|
||||
{this.state.data.content}
|
||||
</div>
|
||||
<StoryTaskTable tasks={this.state.data.tasks || []} />
|
||||
<StoryTaskTable tasks={this.state.data.tasks || []}
|
||||
onTaskMoved={this.handleTaskMoved} />
|
||||
<StoryTaskForm onTaskSubmit={this.handleTaskSubmit} />
|
||||
</div>);
|
||||
}
|
||||
|
@ -283,7 +311,8 @@ var StoryPage = React.createClass({
|
|||
<StoryForm onStorySubmit={this.handleStorySubmit} />
|
||||
</div>
|
||||
<div class="span6">
|
||||
<StoryData ref="data" />
|
||||
<StoryData ref="data"
|
||||
pollInterval={this.props.pollInterval} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue