diff options
author | Tom Willemse | 2013-07-13 21:09:40 +0200 |
---|---|---|
committer | Tom Willemse | 2013-07-13 21:14:37 +0200 |
commit | 84ae7a5fd4524cc06def467efd62019d810781f4 (patch) | |
tree | a46c26d2b90445d0d46021d47992ba1f97c72672 | |
parent | bdd07b68ca1f70b53bfcc8e54fc7ec489e4b52e8 (diff) | |
download | scrumli-84ae7a5fd4524cc06def467efd62019d810781f4.tar.gz scrumli-84ae7a5fd4524cc06def467efd62019d810781f4.zip |
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.
-rw-r--r-- | pg-datastore.lisp | 12 | ||||
-rw-r--r-- | scrumli.lisp | 16 | ||||
-rw-r--r-- | static/js/main.js | 41 |
3 files changed, 54 insertions, 15 deletions
diff --git a/pg-datastore.lisp b/pg-datastore.lisp index 0952ab0..805e748 100644 --- a/pg-datastore.lisp +++ b/pg-datastore.lisp @@ -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)) - 'priority) - :alists)))))) + `((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))) (defmethod datastore-post-story ((datastore pg-datastore) role necessity title content reporter) diff --git a/scrumli.lisp b/scrumli.lisp index f52fff5..33a9ae9 100644 --- a/scrumli.lisp +++ b/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)) diff --git a/static/js/main.js b/static/js/main.js index 28abd54..3e5ae07 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -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> ); |