Skip to content
Snippets Groups Projects
Commit f90b46f8 authored by Florian Fittkau's avatar Florian Fittkau
Browse files

tasks

parent 94d4b473
No related branches found
No related tags found
No related merge requests found
Showing
with 347 additions and 65 deletions
......@@ -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."))
productBacklog.addToUserstories(userStoryInBacklog)
userStory.save(failOnError: true)
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:showUserStoryDialog />
<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"
}
}
......@@ -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"
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment