Commit 6a20fcec authored by Florian Fittkau's avatar Florian Fittkau

nearly working :)

parent 6f72c09c
......@@ -121,7 +121,7 @@
<attribute name="org.grails.ide.eclipse.core.SOURCE_FOLDER" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path=".link_to_grails_plugins/hibernate-2.1.1/grails-app/i18n">
<classpathentry kind="src" path=".link_to_grails_plugins/hibernate-2.1.0/grails-app/i18n">
<attributes>
<attribute name="org.grails.ide.eclipse.core.SOURCE_FOLDER" value="true"/>
</attributes>
......
......@@ -26,7 +26,7 @@
<link>
<name>.link_to_grails_plugins</name>
<type>2</type>
<locationURI>GRAILS_ROOT/2.1.1/projects/scrumboard/plugins</locationURI>
<locationURI>GRAILS_ROOT/2.1.0/projects/scrumboard/plugins</locationURI>
</link>
</linkedResources>
</projectDescription>
......@@ -5,8 +5,8 @@ encoding//.link_to_grails_plugins/cached-resources-1.0/grails-app/i18n=UTF-8
encoding//.link_to_grails_plugins/cached-resources-1.0/grails-app/i18n/messages.properties=UTF-8
encoding//.link_to_grails_plugins/constraints-0.8.0/grails-app/i18n=UTF-8
encoding//.link_to_grails_plugins/constraints-0.8.0/grails-app/i18n/messages.properties=UTF-8
encoding//.link_to_grails_plugins/hibernate-2.1.1/grails-app/i18n=UTF-8
encoding//.link_to_grails_plugins/hibernate-2.1.1/grails-app/i18n/messages.properties=UTF-8
encoding//.link_to_grails_plugins/hibernate-2.1.0/grails-app/i18n=UTF-8
encoding//.link_to_grails_plugins/hibernate-2.1.0/grails-app/i18n/messages.properties=UTF-8
encoding//.link_to_grails_plugins/jquery-1.7.2/grails-app/i18n=UTF-8
encoding//.link_to_grails_plugins/jquery-1.7.2/grails-app/i18n/messages.properties=UTF-8
encoding//.link_to_grails_plugins/jquery-ui-1.8.15/grails-app/i18n=UTF-8
......
#Grails Metadata file
#Mon Oct 08 23:09:36 CEST 2012
app.grails.version=2.1.1
#Tue Oct 09 19:00:13 CEST 2012
app.grails.version=2.1.0
app.name=scrumboard
app.version=0.1
plugins.browser-detection=0.4.1
......
......@@ -7,7 +7,7 @@ class UrlMappings {
}
}
"/"(controller:"home")
"/"(controller:"backlog")
"500"(view:'/error')
}
}
......@@ -5,7 +5,7 @@ import org.apache.shiro.subject.Subject
import scrumboard.shiro.User
class HomeController {
class BacklogController {
def index() {
Subject currentSubject = SecurityUtils.getSubject()
......@@ -17,34 +17,12 @@ class HomeController {
def sprints = projects[0].sprints
def sprintUserStories = sprints.iterator().next().userstories
backlogUserStories = backlogUserStories.sort()
sprintUserStories = sprintUserStories.sort()
render(view: "index", model: [projects: projects,
sprints: sprints,
sprintUserStories: sprintUserStories,
backlogUserStories: backlogUserStories])
}
def showUserStory(int id) {
def userStory = UserStory.get(id)
render ( template:"showUserStory", model: [userStory : userStory])
}
def moveUserStory(int id, String to) {
def userStory = UserStory.get(id)
def projects = Project.list()
def backlog = projects[0].productBacklog
def sprint = projects[0].sprints.iterator().next()
println to
if (to == "sprintbacklog") {
backlog.removeFromUserstories(userStory)
sprint.addToUserstories(userStory)
userStory.status = UserStoryStatus.OPEN
}
if (to == "backlog") {
sprint.removeFromUserstories(userStory)
backlog.addToUserstories(userStory)
userStory.status = UserStoryStatus.IN_BACKLOG
}
}
}
package scrumboard
class SprintController {
def show(int id) {
def projects = Project.list()
def sprints = projects[0].sprints
def currentSprint = sprints.iterator().next()
def sprintUserStories = currentSprint.userstories
sprintUserStories = sprintUserStories.sort()
render(view: "show", model: [projects: projects,
currentSprint: currentSprint,
sprintUserStories: sprintUserStories])
}
}
package scrumboard
class UserStoryController {
def show(int id) {
def userStory = UserStory.get(id)
render ( template:"showUserStory", model: [userStory : userStory])
}
def move(int id, String to) {
def userStory = UserStory.get(id)
def projects = Project.list()
def backlog = projects[0].productBacklog
def sprint = projects[0].sprints.iterator().next()
if (to == "sprintbacklog") {
backlog.removeFromUserstories(userStory)
sprint.addToUserstories(userStory)
userStory.status = UserStoryStatus.OPEN
}
if (to == "backlog") {
sprint.removeFromUserstories(userStory)
backlog.addToUserstories(userStory)
userStory.status = UserStoryStatus.IN_BACKLOG
}
if (to == "opensprint") {
userStory.status = UserStoryStatus.OPEN
}
if (to == "inprogresssprint") {
userStory.status = UserStoryStatus.IN_PROGRESS
}
if (to == "donesprint") {
userStory.status = UserStoryStatus.DONE
}
render ""
}
}
......@@ -2,7 +2,9 @@ package scrumboard
import scrumboard.shiro.User
class UserStory {
class UserStory implements Comparable {
static final int maxShortDescription = 60
String title
String description
String shortId
......@@ -16,4 +18,26 @@ class UserStory {
static constraints = {
}
def String toString() {shortId + ": " + title};
int compareTo(obj) {
shortId.compareTo(obj.shortId)
}
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
}
}
package scrumboard
class MovableColumnTagLib {
def movableColumn = { 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/move?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 NoteTagLib {
def note = { attrs ->
def userStories = attrs["userStories"]
if (attrs["status"]) {
userStories = userStories.findAll {
userStory -> userStory.status.toString() == attrs["status"]
}
}
userStories.eachWithIndex { item, index ->
if (index % attrs["columnlength"].toInteger() == attrs["columnindex"].toInteger()) {
out << """<div class='ui-widget ui-corner-all'>
<div class='hidden'>${item.id}</div>
<div class='ui-widget-header ui-corner-top'>${item}</div>
<div class='ui-widget-content ui-corner-bottom' >${item.getShortDescription()}</div>
</div> """
}
}
}
}
package scrumboard
class ShowUserStoryDialogTagLib {
def showUserStoryDialog = { attrs ->
out << """\$( ".ui-widget" ).dblclick(function() {
\$.ajax({
url: "/scrumboard/userStory/show?id=" + \$(this).find(".hidden").text()
}).done(function ( data ) {
\$( "#dialog-showUserStory" ).html(data);
\$( "#dialog-showUserStory" ).dialog( "open" );
});
});
\$( '#dialog-showUserStory' ).dialog({
autoOpen: false,
height: 500,
width: 650,
modal: true,
buttons: {
'Save': function() {
var bValid = true;
if ( bValid ) {
\$( this ).dialog( 'close' );
}
},
Cancel: function() {
\$( this ).dialog( 'close' );
}
},
close: function() {
}
});"""
}
}
......@@ -9,65 +9,54 @@
</style>
</head>
<body>
<h1 class="center"><img alt="Scrumboard"
src="${resource(dir: 'images', file: 'logo.png')}"
style='text-align: left;' width='200px' /> for <g:select name="projects"
from="${projects}"/></h1>
<hr>
<h1 id="backloglabel">Backlog</h1>
<h1 id="backloglabel"><img id="AddUserStory" style="cursor: pointer;" alt="Add" src="/scrumboard/images/add.png"></img>&nbsp;&nbsp;&nbsp;Backlog</h1>
<hr id="boarddivider" width="1px" size="768px" class="centerVerticalLine"></hr>
<h1 id="sprintbackloglabel"><g:select name="sprints"
from="${sprints}" style="margin-top:-6px;"/>&nbsp;
<img id="AddSprint" alt="Add" src="/scrumboard/images/add.png"></img>
<h1 id="sprintbackloglabel"><img id="AddSprint" style="cursor: pointer;" alt="Add" src="/scrumboard/images/add.png"></img>&nbsp;&nbsp;&nbsp;<g:select name="sprints"
from="${sprints}" style="margin-top:-6px;"/>&nbsp;&nbsp;&nbsp;<a href="/scrumboard/sprint/show?id=0"><img id="ShowSprint" alt="show" src="/scrumboard/images/east-mini.png"></img></a>
</h1>
<div id="backlog">
<div id="columnbacklogone" class="column">
<g:each var="backlogUserStory" in="${backlogUserStories}">
<div class="ui-widget ui-corner-all">
<div class="hidden">${backlogUserStory.id}</div>
<div class="ui-widget-header ui-corner-top">${backlogUserStory.shortId}: ${backlogUserStory.title}</div>
<div class="ui-widget-content ui-corner-bottom" >${backlogUserStory.description}</div>
</div>
</g:each>
<g:note userStories="${backlogUserStories}" columnindex="0" columnlength="4" />
</div>
<div id="columnbacklogtwo" class="column"></div>
<div id="columnbacklogthree" class="column"></div>
<div id="columnbacklogfour" class="column"></div>
<div id="columnbacklogtwo" class="column">
<g:note userStories="${backlogUserStories}" columnindex="1" columnlength="4" />
</div>
<div id="columnsprintbacklogone" class="column">
<div id="columnbacklogthree" class="column">
<g:note userStories="${backlogUserStories}" columnindex="2" columnlength="4" />
</div>
<g:each var="sprintUserStory" in="${sprintUserStories}">
<div class="ui-widget ui-corner-all">
<div class="hidden">${sprintUserStory.id}</div>
<div class="ui-widget-header ui-corner-top">${sprintUserStory.shortId}: ${sprintUserStory.title}</div>
<div class="ui-widget-content ui-corner-bottom" >${sprintUserStory.description}</div>
</div>
</g:each>
<div id="columnbacklogfour" class="column">
<g:note userStories="${backlogUserStories}" columnindex="3" columnlength="4" />
</div>
</div>
<div id="sprintbacklog">
<div id="columnsprintbacklogtwo" class="column"></div>
<div id="columnsprintbacklogone" class="column">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="4" />
</div>
<div id="columnsprintbacklogthree" class="column"></div>
<div id="columnsprintbacklogtwo" class="column">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="4" />
</div>
<div id="columnsprintbacklogfour" class="column"></div>
<div id="columnsprintbacklogthree" class="column">
<g:note userStories="${sprintUserStories}" columnindex="2" columnlength="4" />
</div>
<div id="dialog-form" title="Create new sprint">
<div id="columnsprintbacklogfour" class="column">
<g:note userStories="${sprintUserStories}" columnindex="3" columnlength="4" />
</div>
<div id="dialog-addSprint" title="Create new sprint">
<p class="validateTips">All form fields are required.</p>
<form>
......@@ -86,22 +75,7 @@ x
<script type="text/javascript">
$(function() {
$( ".column" ).sortable({
connectWith: ".column",
cursor: 'pointer',
start: function(event, ui) {
item = ui.item;
newList = oldList = ui.item.parent().parent();
},
stop: function(event, ui) {
$.ajax({
url: "/scrumboard/home/moveUserStory?id=" + item.find(".hidden").text() + "&to=" + newList.attr('id')
});
},
change: function(event, ui) {
if(ui.sender) newList = ui.placeholder.parent().parent();
}
});
<g:movableColumn name="column"/>
$( ".ui-widget" )
.find( ".ui-widget-header" )
......@@ -112,38 +86,9 @@ $(function() {
alert("x");
});
$( ".column" ).disableSelection();
$( ".ui-widget" ).dblclick(function() {
$.ajax({
url: "/scrumboard/home/showUserStory?id=" + $(this).find(".hidden").text()
}).done(function ( data ) {
$( "#dialog-showUserStory" ).html(data);
$( "#dialog-showUserStory" ).dialog( "open" );
});
});
$( "#dialog-showUserStory" ).dialog({
autoOpen: false,
height: 500,
width: 650,
modal: true,
buttons: {
"Save": function() {
var bValid = true;
if ( bValid ) {
$( this ).dialog( "close" );
}
},
Cancel: function() {
$( this ).dialog( "close" );
}
},
close: function() {
}
});
<g:showUserStoryDialog />
$( "#dialog-form" ).dialog({
$( "#dialog-addSprint" ).dialog({
autoOpen: false,
height: 300,
width: 350,
......@@ -166,7 +111,7 @@ $(function() {
});
$( "#AddSprint" ).click(function() {
$( "#dialog-form" ).dialog( "open" );
$( "#dialog-addSprint" ).dialog( "open" );
});
});
......
......@@ -24,6 +24,12 @@
<r:layoutResources />
</head>
<body>
<h1 class="center"><img alt="Scrumboard"
src="${resource(dir: 'images', file: 'logo.png')}"
style='text-align: left;' width='200px' /> for <g:select name="projects"
from="${projects}"/></h1>
<hr style="color: #315fa0;">
<g:layoutBody/>
<div id="spinner" class="spinner" style="display:none;"></div>
<r:layoutResources />
......
<!doctype html>
<html>
<head>
<meta name="layout" content="main">
<style>
.ui-widget-header .ui-icon { float: right; }
.ui-sortable-placeholder { border: 1px dotted gray; visibility: visible !important; height: 50px !important; }
.ui-sortable-placeholder * { visibility: hidden; }
</style>
</head>
<body>
<h1 id="sprintbacklogOnSprintlabel"><a href="/scrumboard/"><img id="ShowBacklog" alt="back" src="/scrumboard/images/west-mini.png"></img></a>&nbsp;&nbsp;&nbsp;Sprintbacklog</h1>
<hr id="boarddividerleft" width="1px" size="768px"></hr>
<h1 id="opensprintlabel">Open</h1>
<hr id="boarddividercenter" width="1px" size="768px"></hr>
<h1 id="inprogresssprintlabel">In Progress</h1>
<hr id="boarddividerright" width="1px" size="768px"></hr>
<h1 id="donesprintlabel">Done</h1>
<div id="sprintbacklog">
<div id="columnsprintbacklogOnSprintone" class="column">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="2" />
</div>
<div id="columnsprintbacklogOnSprinttwo" class="column">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="2" />
</div>
</div>
<div id="opensprint">
<div id="columnopensprintone" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="2" status="OPEN" />
</div>
<div id="columnopensprinttwo" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="2" status="OPEN" />
</div>
</div>
<div id="inprogresssprint">
<div id="columninprogresssprintone" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="2" status="IN_PROGRESS" />
</div>
<div id="columninprogresssprinttwo" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="2" status="IN_PROGRESS" />
</div>
</div>
<div id="donesprint">
<div id="columndonesprintone" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="0" columnlength="2" status="DONE" />
</div>
<div id="columndonesprinttwo" class="columnStatus">
<g:note userStories="${sprintUserStories}" columnindex="1" columnlength="2" status="DONE" />
</div>
</div>
<div id="dialog-showUserStory" title="Show User Story">
x
</div>
<script type="text/javascript">
$(function() {
<g:movableColumn name="column"/>
<g:movableColumn name="columnStatus"/>
$( ".ui-widget" )
.find( ".ui-widget-header" )
.prepend( "<span class='icon'>+</span>")
.end();
$( ".ui-widget-header .ui-icon" ).click(function() {
alert("x");
});
<g:showUserStoryDialog />
$( "#AddSprint" ).click(function() {
$( "#dialog-form" ).dialog( "open" );
});
});
</script>
</body>
</html>
package scrumboard
import grails.test.mixin.*
import org.junit.*
/**
* See the API for {@link grails.test.mixin.web.GroovyPageUnitTestMixin} for usage instructions
*/
@TestFor(MovableColumnTagLib)
class MovableColumnTagLibTests {
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(NoteTagLib)
class NotetagTagLibTests {
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(ShowUserStoryDialogTagLib)
class ShowUserStoryDialogTagLibTests {
void testSomething() {
fail "Implement me"
}
}
package scrumboard
import grails.test.mixin.*
import org.junit.*
/**
* See the API for {@link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
@TestFor(SprintController)
class SprintControllerTests {
void testSomething() {
fail "Implement me"
}
}
package scrumboard
import grails.test.mixin.*
import org.junit.*
/**
* See the API for {@link grails.test.mixin.web.ControllerUnitTestMixin} for usage instructions
*/
@TestFor(UserStoryController)
class UserStoryControllerTests {
void testSomething() {
fail "Implement me"
}
}
No preview for this file type
web-app/images/add.png

386 Bytes | W: | H:

web-app/images/add.png

563 Bytes | W: | H:

web-app/images/add.png
web-app/images/add.png
web-app/images/add.png
web-app/images/add.png
  • 2-up
  • Swipe
  • Onion skin
web-app/images/logo.png

37.2 KB | W: | H:

web-app/images/logo.png

41.9 KB | W: | H:

web-app/images/logo.png
web-app/images/logo.png
web-app/images/logo.png
web-app/images/logo.png
  • 2-up
  • Swipe
  • Onion skin
#backloglabel {
position:absolute;
left:22%;
left:19%;
top:10%;
z-index:0;
}
#sprintbacklogOnSprintlabel {
position:absolute;
left:8%;
top:10%;
z-index:0;
}
#boarddivider {
position:absolute;
color: #315fa0;
left:47%;
top:10%;
z-index:0;
}
#boarddividerleft {
position:absolute;
color: #315fa0;
left:25%;
top:10%;
z-index:0;
}
#opensprintlabel {
position:absolute;
left:37%;
top:10%;
z-index:0;
}
#boarddividercenter {
position:absolute;
color: #315fa0;