Commit f90b46f8 authored by Florian Fittkau's avatar Florian Fittkau

tasks

parent 94d4b473
......@@ -3,6 +3,7 @@ import scrumboard.Color
import scrumboard.ProductBacklog
import scrumboard.Project
import scrumboard.Sprint
import scrumboard.Task
import scrumboard.UserStory
import scrumboard.UserStoryStatus;
import scrumboard.shiro.User
......@@ -46,16 +47,18 @@ class BootStrap {
private createBacklog(User ffi) {
def productBacklog = new ProductBacklog()
def userStoryInBacklog = new UserStory("V-1", "Energiekataster Layer")
userStoryInBacklog.description = "Energiekataster Layer im GIS um über jeder VE die Energieausweise direkt zu sehen."
userStoryInBacklog.author = ffi
userStoryInBacklog.editor = ffi
userStoryInBacklog.points = 3
userStoryInBacklog.color = new Color(250,60,0)
def userStory = new UserStory("V-1", "Energiekataster Layer")
userStory.description = "Energiekataster Layer im GIS um über jeder VE die Energieausweise direkt zu sehen."
userStory.author = ffi
userStory.editor = ffi
userStory.points = 3
userStory.color = new Color(250,60,0)
userStoryInBacklog.save(failOnError: true)
userStory.addToTasks(new Task("Definiere X in GIS", "Definiere X und lege Y an."))
userStory.save(failOnError: true)
productBacklog.addToUserstories(userStoryInBacklog)
productBacklog.addToUserstories(userStory)
productBacklog
}
......@@ -65,17 +68,20 @@ class BootStrap {
sprintOne.due_date = new Date()
def userStoryInSprint = new UserStory("V-2", "Volltextsuche im GIS")
userStoryInSprint.description = "Volltextsuche im GIS ermglichen"
userStoryInSprint.author = ffi
userStoryInSprint.editor = ffi
userStoryInSprint.points = 2
userStoryInSprint.status = UserStoryStatus.OPEN
userStoryInSprint.color = new Color(250,180,0)
def userStory = new UserStory("V-2", "Volltextsuche im GIS")
userStory.description = "Volltextsuche im GIS ermglichen"
userStory.author = ffi
userStory.editor = ffi
userStory.points = 2
userStory.status = UserStoryStatus.OPEN
userStory.color = new Color(250,180,0)
userStory.addToTasks(new Task("Menue links bei GIS", "Definiere Menue links vom GIS."))
userStory.addToTasks(new Task("Passe Suche an", "Suchergebnisse sollen in dem Menue erscheinen."))
userStoryInSprint.save(failOnError: true)
userStory.save(failOnError: true)
sprintOne.addToUserstories(userStoryInSprint)
sprintOne.addToUserstories(userStory)
sprintOne
}
......
......@@ -10,9 +10,18 @@ class SprintController {
def sprintUserStories = currentSprint.userstories
sprintUserStories = sprintUserStories.sort()
def sprintTasks = []
sprintUserStories.each {
sprintTasks.addAll(it.tasks)
}
sprintTasks = sprintTasks.sort()
render(view: "show", model: [projects: projects,
currentSprint: currentSprint,
sprintUserStories: sprintUserStories])
sprintUserStories: sprintUserStories,
sprintTasks: sprintTasks])
}
def create(String name) {
......
......@@ -3,7 +3,7 @@ package scrumboard
class UserStoryController {
def show(int id) {
def userStory = UserStory.get(id)
def userStory = UserStory.read(id)
render ( template:"showUserStory", model: [userStory : userStory])
}
......@@ -24,20 +24,58 @@ class UserStoryController {
userStory.status = UserStoryStatus.IN_BACKLOG
}
userStory.save()
render ""
}
def moveTask(int id, String to) {
def task = Task.get(id)
if (to == "opensprint") {
userStory.status = UserStoryStatus.OPEN
task.status = UserStoryStatus.OPEN
}
if (to == "inprogresssprint") {
userStory.status = UserStoryStatus.IN_PROGRESS
task.status = UserStoryStatus.IN_PROGRESS
}
if (to == "donesprint") {
userStory.status = UserStoryStatus.DONE
task.status = UserStoryStatus.DONE
}
userStory.save()
task.save()
render ""
}
def showTask(int taskId) {
def task = Task.read(taskId)
render (template:"showTask", model: [task : task])
}
def updateTask(int taskId, String title, String description) {
def task = Task.get(taskId)
task.title = title
task.description = description
task.save()
render ""
}
def deleteTask(int taskId) {
Task.get(taskId).delete()
}
def createTask(int userStoryId) {
def task = new Task("", "")
def parent = UserStory.get(userStoryId)
parent.addToTasks(task)
parent.save()
println "Test: " + task.id
render (template:"showTask", model: [task : task])
}
}
package scrumboard
class Task {
static final int maxShortDescription = 60
String title
String description
UserStoryStatus status = UserStoryStatus.OPEN
static belongsTo = [parent: UserStory]
static constraints = {
}
Task(title, description) {
this.title = title
this.description = description
}
def String toString() {title};
int compareTo(obj) {
// if (obj.parent.compareTo(obj.parent) == 0)
// title.compareTo(obj.title)
// else
// obj.parent.compareTo(obj.parent)
title.compareTo(obj.title)
}
def String getShortDescription() {
def result = description
if (description.size() > maxShortDescription) {
def indexOfSpace = description.indexOf(" ", maxShortDescription)
if (indexOfSpace != -1 && indexOfSpace < maxShortDescription + 40) {
result = description.substring(0, indexOfSpace)
} else {
result = description[0..maxShortDescription]
}
result += " [...]"
}
result
}
}
......@@ -18,6 +18,8 @@ class UserStory implements Comparable {
User author
User editor
static hasMany = [ tasks: Task ]
static constraints = {
}
......
package scrumboard
class MovableColumnTaskTagLib {
def movableColumnTask = { attrs ->
def name = attrs["name"]
out << """ \$( ".${name}" ).sortable({
connectWith: ".${name}",
cursor: 'pointer',
start: function(event, ui) {
item${name} = ui.item;
newList${name} = ui.item.parent().parent();
},
stop: function(event, ui) {
\$.ajax({
url: "/scrumboard/userStory/moveTask?id=" + item${name}.find(".hidden").text() + "&to=" + newList${name}.attr('id')
});
},
change: function(event, ui) {
if(ui.sender) newList${name} = ui.placeholder.parent().parent();
}
});
\$( ".${name}" ).disableSelection();"""
}
}
package scrumboard
class MovableColumnTagLib {
def movableColumn = { attrs ->
class MovableColumnUserStoryTagLib {
def movableColumnUserStory = { attrs ->
def name = attrs["name"]
out << """ \$( ".${name}" ).sortable({
......
package scrumboard
class NoteTaskTagLib {
def noteTask = { attrs ->
def tasks = attrs["tasks"]
if (attrs["status"]) {
tasks = tasks.findAll {
task -> task.status.toString() == attrs["status"]
}
}
tasks.eachWithIndex { item, index ->
if (index % attrs["columnlength"].toInteger() == attrs["columnindex"].toInteger()) {
out << """<div class='ui-widget ui-corner-all task'>
<div class='hidden'>${item.id}</div>
<div class='ui-widget-header ui-corner-top' style='background: ${item.parent.color.toHex()} !important;'>${item}</div>
<div class='ui-widget-content ui-corner-bottom' >${item.getShortDescription()}</div>
</div> """
}
}
}
}
package scrumboard
class NoteTagLib {
def note = { attrs ->
class NoteUserStoryTagLib {
def noteUserStory = { attrs ->
def userStories = attrs["userStories"]
if (attrs["status"]) {
......@@ -12,9 +12,9 @@ class NoteTagLib {
userStories.eachWithIndex { item, index ->
if (index % attrs["columnlength"].toInteger() == attrs["columnindex"].toInteger()) {
out << """<div class='ui-widget ui-corner-all'>
out << """<div class='ui-widget ui-corner-all userStory'>
<div class='hidden'>${item.id}</div>
<div class='ui-widget-header ui-corner-top' style='background: ${item.color.toHex()} !important;'>${item}</div>
<div class='ui-widget-header ui-corner-top userStoryHeader' style='background: ${item.color.toHex()} !important;'>${item}</div>
<div class='ui-widget-content ui-corner-bottom' >${item.getShortDescription()}</div>
</div> """
}
......
package scrumboard
class ShowTaskDialogTagLib {
def showTaskDialog = { attrs ->
out << """\$( ".task" ).dblclick(function() {
\$.ajax({
url: "/scrumboard/userStory/showTask?taskId=" + \$(this).find(".hidden").text()
}).done(function ( data ) {
\$( "#dialog-showTask" ).html(data);
\$( "#dialog-showTask" ).dialog( "open" );
});
});
\$( '#dialog-showTask' ).dialog({
autoOpen: false,
height: 500,
width: 650,
modal: true,
buttons: {
'Save': function() {
var bValid = true;
if ( bValid ) {
\$.ajax({
url: "/scrumboard/userStory/updateTask?" + \$('#showTaskForm').serialize()
}).done(function ( data ) {
\$( '#dialog-showTask' ).dialog( 'close' );
location.reload();
});
}
},
Cancel: function() {
\$( this ).dialog( 'close' );
}
},
close: function() {
}
});"""
}
}
......@@ -2,7 +2,7 @@ package scrumboard
class ShowUserStoryDialogTagLib {
def showUserStoryDialog = { attrs ->
out << """\$( ".ui-widget" ).dblclick(function() {
out << """\$( ".userStory" ).dblclick(function() {
\$.ajax({
url: "/scrumboard/userStory/show?id=" + \$(this).find(".hidden").text()
}).done(function ( data ) {
......
......@@ -20,37 +20,37 @@
<div id="backlog">
<div id="columnbacklogone" class="column">
<g:note userStories="${backlogUserStories}" columnindex="0" columnlength="4" />
<g:noteUserStory userStories="${backlogUserStories}" columnindex="0" columnlength="4" />
</div>
<div id="columnbacklogtwo" class="column">
<g:note userStories="${backlogUserStories}" columnindex="1" columnlength="4" />
<g:noteUserStory userStories="${backlogUserStories}" columnindex="1" columnlength="4" />
</div>
<div id="columnbacklogthree" class="column">
<g:note userStories="${backlogUserStories}" columnindex="2" columnlength="4" />
<g:noteUserStory userStories="${backlogUserStories}" columnindex="2" columnlength="4" />
</div>
<div id="columnbacklogfour" class="column">
<g:note userStories="${backlogUserStories}" columnindex="3" columnlength="4" />
<g:noteUserStory userStories="${backlogUserStories}" columnindex="3" columnlength="4" />
</div>
</div>
<div id="sprintbacklog">
<div id="columnsprintbacklogone" class="column">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="4" />
<g:noteUserStory userStories="${sprintUserStories}" columnindex="0" columnlength="4" />
</div>
<div id="columnsprintbacklogtwo" class="column">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="4" />
<g:noteUserStory userStories="${sprintUserStories}" columnindex="1" columnlength="4" />
</div>
<div id="columnsprintbacklogthree" class="column">
<g:note userStories="${sprintUserStories}" columnindex="2" columnlength="4" />
<g:noteUserStory userStories="${sprintUserStories}" columnindex="2" columnlength="4" />
</div>
<div id="columnsprintbacklogfour" class="column">
<g:note userStories="${sprintUserStories}" columnindex="3" columnlength="4" />
<g:noteUserStory userStories="${sprintUserStories}" columnindex="3" columnlength="4" />
</div>
<div id="dialog-addSprint" title="Create new sprint">
......@@ -68,7 +68,7 @@
<script type="text/javascript">
$(function() {
<g:movableColumn name="column"/>
<g:movableColumnUserStory name="column"/>
$( ".ui-widget" )
.find( ".ui-widget-header" )
......
......@@ -26,11 +26,11 @@
<div id="sprintbacklog">
<div id="columnsprintbacklogOnSprintone" class="column">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="2" />
<g:noteUserStory userStories="${sprintUserStories}" columnindex="0" columnlength="2" />
</div>
<div id="columnsprintbacklogOnSprinttwo" class="column">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="2" />
<g:noteUserStory userStories="${sprintUserStories}" columnindex="1" columnlength="2" />
</div>
</div>
......@@ -38,11 +38,11 @@
<div id="opensprint">
<div id="columnopensprintone" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="2" status="OPEN" />
<g:noteTask tasks="${sprintTasks}" columnindex="0" columnlength="2" status="OPEN" />
</div>
<div id="columnopensprinttwo" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="2" status="OPEN" />
<g:noteTask tasks="${sprintTasks}" columnindex="1" columnlength="2" status="OPEN" />
</div>
</div>
......@@ -50,11 +50,11 @@
<div id="inprogresssprint">
<div id="columninprogresssprintone" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="2" status="IN_PROGRESS" />
<g:noteTask tasks="${sprintTasks}" columnindex="0" columnlength="2" status="IN_PROGRESS" />
</div>
<div id="columninprogresssprinttwo" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="2" status="IN_PROGRESS" />
<g:noteTask tasks="${sprintTasks}" columnindex="1" columnlength="2" status="IN_PROGRESS" />
</div>
</div>
......@@ -62,40 +62,43 @@
<div id="donesprint">
<div id="columndonesprintone" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="2" status="DONE" />
<g:noteTask tasks="${sprintTasks}" columnindex="0" columnlength="2" status="DONE" />
</div>
<div id="columndonesprinttwo" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="2" status="DONE" />
<g:noteTask tasks="${sprintTasks}" columnindex="1" columnlength="2" status="DONE" />
</div>
</div>
<div id="dialog-showUserStory" title="Show User Story">
x
</div>
<div id="dialog-showTask" title="Show Task">
</div>
<script type="text/javascript">
$(function() {
<g:movableColumn name="column"/>
<g:movableColumnUserStory name="column"/>
<g:movableColumn name="columnStatus"/>
<g:movableColumnTask name="columnStatus"/>
$( ".ui-widget" )
.find( ".ui-widget-header" )
.prepend( "<span class='icon'>+</span>")
$( ".userStory" )
.find( ".userStoryHeader" )
.prepend( "<span class='icon addTask'>+</span>")
.end();
$( ".ui-widget-header .ui-icon" ).click(function() {
alert("x");
$( ".userStoryHeader .addTask" ).click(function() {
$.ajax({
url: "/scrumboard/userStory/createTask?userStoryId=" + $(this).parent().parent().find(".hidden").text()
}).done(function ( data ) {
$( "#dialog-showTask" ).html(data);
$( "#dialog-showTask" ).dialog( "open" );
});
});
<g:showUserStoryDialog />
$( "#AddSprint" ).click(function() {
$( "#dialog-form" ).dialog( "open" );
});
<g:showTaskDialog />
});
</script>
......
<g:form action="none" name="showTaskForm">
<input type="hidden" name="taskId" value="${task.id}" />
<table>
<tbody>
<tr>
<td>Title:</td>
<td><input size='60%' id='task_title' type="text" name="title" value="${task.title}" /></td>
</tr>
<tr>
<td>Description:</td>
<td><textarea style="width: 50%" id='task_description' name="description">${task.description}</textarea></td>
</tr>
<tr>
<td>Status:</td>
<td><input size='60%' disabled id='task_status' type="text" name="status" value="${task.status}" /></td>
</tr>
<tbody>
</table>
</g:form>
\ No newline at end of file
package scrumboard
import grails.test.mixin.*
import org.junit.*
/**
* See the API for {@link grails.test.mixin.web.GroovyPageUnitTestMixin} for usage instructions
*/
@TestFor(MovableColumnTaskTagLib)
class MovableColumnTaskTagLibTests {
void testSomething() {
fail "Implement me"
}
}
package scrumboard
import grails.test.mixin.*
import org.junit.*
/**
* See the API for {@link grails.test.mixin.web.GroovyPageUnitTestMixin} for usage instructions
*/
@TestFor(MovableColumnUserStoryTagLib)
class MovableColumnUserStoryTagLibTests {
void testSomething() {
fail "Implement me"
}
}
package scrumboard
package scrumboard
import grails.test.mixin.*
......@@ -8,8 +8,8 @@ import org.junit.*
/**
* See the API for {@link grails.test.mixin.web.GroovyPageUnitTestMixin} for usage instructions
*/
@TestFor(MovableColumnTagLib)
class MovableColumnTagLibTests {
@TestFor(NoteTaskTagLib)
class NoteTaskTagLibTests {
void testSomething() {
fail "Implement me"
......
......@@ -8,7 +8,7 @@ import org.junit.*
/**
* See the API for {@link grails.test.mixin.web.GroovyPageUnitTestMixin} for usage instructions
*/
@TestFor(NoteTagLib)
@TestFor(NoteUserStoryTagLib)
class NotetagTagLibTests {
void testSomething() {
......
package scrumboard
import grails.test.mixin.*
import org.junit.*
/**
* See the API for {@link grails.test.mixin.web.GroovyPageUnitTestMixin} for usage instructions
*/
@TestFor(ShowTaskDialogTagLib)
class ShowTaskDialogTagLibTests {
void testSomething() {
fail "Implement me"
}
}
package scrumboard
import grails.test.mixin.*
import org.junit.*
/**
* See the API for {@link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
*/
@TestFor(Task)
class TaskTests {
void testSomething() {
fail "Implement me"
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment