From 84ae7a5fd4524cc06def467efd62019d810781f4 Mon Sep 17 00:00:00 2001 From: Tom Willemse Date: Sat, 13 Jul 2013 21:09:40 +0200 Subject: 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. --- pg-datastore.lisp | 12 +++++++----- scrumli.lisp | 16 ++++++++++++---- 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 ; + return ; }.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 (
@@ -107,7 +134,8 @@ var StoryData = React.createClass({
{this.state.data.content}
- +
); } @@ -283,7 +311,8 @@ var StoryPage = React.createClass({
- +
); -- cgit v1.2.3-54-g00ecf