Skip to content
Browse files

Add support for an 'area' field, if present

  • Loading branch information...
1 parent 7289236 commit 2863a54675905f8437db50ccef355c2290c70eff @haugstrup committed Jun 2, 2012
Showing with 198 additions and 66 deletions.
  1. +10 −0 helpers.php
  2. +38 −2 public/dashboard.css
  3. +52 −12 public/scrumboard.js
  4. +59 −36 scrumio.classes.php
  5. +13 −6 views/_dashboard_story.html.php
  6. +5 −0 views/_filters.html.php
  7. +4 −0 views/_story.html.php
  8. +17 −10 views/index.html.php
View
10 helpers.php
@@ -4,3 +4,13 @@ function avatar_url($user_id, $size = 'tiny') {
return 'https://files.podio.com/'.$user_id.'/'.$size;
}
+function story_area_field($app) {
+ if (defined('STORY_AREA_ID')) {
+ foreach ($app['fields'] as $field) {
+ if ($field['field_id'] == STORY_AREA_ID) {
+ return $field;
+ }
+ }
+ }
+ return false;
+}
View
40 public/dashboard.css
@@ -44,7 +44,7 @@ header h1 {
width:960px;
}
-#dashboard .stories {
+#dashboard .stories-wrapper {
width:630px;
float:left;
}
@@ -111,7 +111,7 @@ header h1 {
#dashboard .stories > li .status-area {
height:50px;
float:left;
-
+
border-radius:4px;
background:#e7e7e7;
margin-right:15px;
@@ -156,6 +156,24 @@ header h1 {
background: #339933;
}
+.area {
+ border-radius:4px;
+ padding:0 4px;
+}
+.story-group .area {
+ margin-left:13px;
+}
+#dashboard .stories > li .metadata .area {
+ margin-left:5px;
+}
+#dashboard .stories > li .metadata .area:first-child {
+ margin-left:0;
+}
+
+#dashboard .stories > li .metadata .estimate {
+ margin:0 10px;
+}
+
#dashboard .stories > li .metadata .testing {
background:#006699;
color:#fff;
@@ -172,6 +190,24 @@ header h1 {
padding:0 2px;
}
+/* Filter list */
+.filter {
+}
+.filter ul {
+ display:inline-block;
+ margin-bottom:20px;
+}
+.filter ul li {
+ cursor:pointer;
+ display:inline-block;
+ border-radius:4px;
+ padding:0 4px;
+ margin:0 10px;
+}
+.filter ul li.active {
+ font-weight:bold;
+}
+
/* BULLET GRAPH */
div.box-wrap { position: relative; width: 370px; height: 21px; top: 0; left: 0; margin: 0; padding: 0; background: #bad6ec; }
View
64 public/scrumboard.js
@@ -5,7 +5,46 @@
$('.graph .target, .graph .actual').tipsy({gravity: 's'});
$('.tooltip').tipsy({gravity: 'n'});
}
-
+
+ function onFilterClick(elmTarget, e) {
+ elmTarget.toggleClass('active');
+ var enabled = elmTarget.hasClass('active');
+ if (enabled) {
+ elmTarget.css('background-color', elmTarget.data('color'));
+ }
+ else {
+ elmTarget.css('background-color', 'transparent');
+ }
+ var currentFilter = [];
+ elmTarget.parent().find('li.active').each(function(){
+ currentFilter.push('area-'+$(this).data('id'));
+ });
+ if (currentFilter.length === 0) {
+ $('ul.stories > li').show();
+ $('#stories > .items > .story-group').show();
+ }
+ else {
+ $('ul.stories > li').each(function(){
+ var is_visible = false;
+ var currentStory = $(this);
+ $.each(currentFilter, function(index, value) {
+ console.log('testing '+value);
+ if (currentStory.hasClass(value)) {
+ is_visible = true;
+ }
+ });
+ if (is_visible) {
+ $(this).show();
+ $('#story-'+$(this).data('id')).show();
+ }
+ else {
+ $(this).hide();
+ $('#story-'+$(this).data('id')).hide();
+ }
+ });
+ }
+ }
+
function onDashBoardStoryClick(elmTarget, e) {
if (!$(e.target).hasClass('external-link')) {
e.preventDefault();
@@ -20,7 +59,7 @@
initSingleStoryView();
$('html, body').scrollTop(0);
}
-
+
function initSingleStoryView() {
function resize_stories() {
// Recalculate width according to browser width
@@ -31,9 +70,9 @@
var count = $('#stories').data('count');
var wrapper_width = Math.floor(total_width/count);
$('.story, .state,.header h1').width(wrapper_width);
-
+
}
-
+
function set_story_height(current_id) {
var states = $(current_id).find('.state');
var max_height = 0;
@@ -44,7 +83,7 @@
current_height += $(this).outerHeight(true);
}
});
-
+
if (current_height > max_height) {
max_height = current_height;
}
@@ -53,7 +92,7 @@
}
resize_stories();
-
+
$(window).resize(function(){
resize_stories();
});
@@ -75,14 +114,14 @@
$(current_id+' .story-item-state').droppable({
accept: current_id+' .story-item-state > li',
activeClass: 'ui-state-highlight',
- tolerance: 'pointer',
+ tolerance: 'pointer',
drop: function(event, ui) {
var old_state = $(ui.draggable).parents('ul').data('state');
var state = $(this).data('state');
if (state != old_state) {
var item_id = $(ui.draggable).data('id');
$(this).append(ui.draggable);
-
+
set_story_height('#'+$(this).parents('.story-group').attr('id'));
// Make Ajax request to change state on Podio
@@ -103,7 +142,7 @@
}
});
});
-
+
var collapsedData = getCollapsedData().split(',');
if (typeof collapsedData === 'object') {
$.each(collapsedData, function(index, value){
@@ -113,7 +152,7 @@
});
}
}
-
+
function onScrumBoardToggleClick(elmTarget, e) {
var elmParent = elmTarget.parents('.story-group');
elmParent.find('.user-list, .state').toggle();
@@ -125,7 +164,7 @@
removeCollapsed(elmParent.attr('data-id'));
}
}
-
+
function getCollapsedData() {
var data = false;
if (typeof localStorage !== 'undefined' ) {
@@ -170,5 +209,6 @@
Podio.Event.UI.bind('click', '#dashboard ul.stories > li', onDashBoardStoryClick, true);
Podio.Event.UI.bind('click', '#switch-view', onDashBoardToggleClick);
Podio.Event.UI.bind('click', '.story-group h2', onScrumBoardToggleClick);
+ Podio.Event.UI.bind('click', '.filter li', onFilterClick);
-})(window, jQuery);
+})(window, jQuery);
View
95 scrumio.classes.php
@@ -1,22 +1,22 @@
<?php
class ScrumioItem {
-
+
public $item_id;
public $title;
public $estimate;
public $time_left;
public $responsible;
public $state;
public $story_id;
-
+
public function __construct($item) {
global $api;
// Set Item properties
$this->item_id = $item['item_id'];
$this->title = $item['title'];
$this->link = $item['link'];
-
+
foreach ($item['fields'] as $field) {
if ($field['field_id'] == ITEM_STORY_ID) {
$this->story_id = $field['values'][0]['value']['item_id'];
@@ -44,7 +44,7 @@ public function __construct($item) {
}
}
}
-
+
}
class ScrumioStory {
@@ -56,30 +56,53 @@ class ScrumioStory {
public $total_days;
public $remaining_days;
public $items;
-
+ public $areas;
+
public function __construct($item, $items, $estimate, $time_left, $states, $total_days, $remaining_days) {
global $api;
// Set Story properties
$this->item_id = $item['item_id'];
$this->title = $item['title'];
$this->link = $item['link'];
+ $this->areas = array();
foreach ($item['fields'] as $field) {
if ($field['field_id'] == STORY_OWNER) {
$this->product_owner = $field['values'][0]['value'];
break;
}
+ elseif (defined('STORY_AREA_ID') && $field['field_id'] == STORY_AREA_ID) {
+ foreach ($field['values'] as $value) {
+ $this->areas[] = $value['value'];
+ }
+ }
}
-
+
// Get all items for this story
$this->items = $items;
$this->estimate = $estimate;
$this->time_left = $time_left;
-
+
$this->states = $states;
$this->total_days = $total_days;
$this->remaining_days = $remaining_days;
}
-
+
+ public function get_areas_ids() {
+ $list = array();
+ foreach ($this->areas as $area) {
+ $list[] = $area['id'];
+ }
+ return $list;
+ }
+
+ public function get_areas_class_list() {
+ $list = array();
+ foreach ($this->areas as $area) {
+ $list[] = 'area-'.$area['id'];
+ }
+ return $list;
+ }
+
public function get_responsible() {
$list = array();
foreach ($this->items as $item) {
@@ -89,26 +112,26 @@ public function get_responsible() {
}
return $list;
}
-
+
public function get_items_by_state() {
$list = array();
foreach ($this->states as $state) {
$list[$state] = array();
}
-
+
foreach ($this->items as $item) {
$state = $item->state ? $item->state : STATE_NOT_STARTED;
$list[$state][] = $item;
}
-
+
return $list;
}
-
+
public function get_status_text() {
$states = $this->get_items_by_state();
$total = count($this->items);
$return = array();
-
+
if (count($states[STATE_DEV_DONE]) > 0 && $total == (count($states[STATE_DEV_DONE])+count($states[STATE_QA_DONE])+count($states[STATE_PO_DONE]))) {
$return = array('short' => 'testing', 'long' => 'ready for testing!');
}
@@ -118,44 +141,44 @@ public function get_status_text() {
elseif (count($states['PO done']) > 0 && $total == count($states[STATE_PO_DONE])) {
$return = array('short' => 'done', 'long' => 'all finished!');
}
-
+
return $return;
}
-
+
public function get_time_left() {
return $this->time_left;
}
-
+
public function get_estimate() {
return $this->estimate;
}
-
+
public function get_on_target_value() {
$estimate = $this->get_estimate();
$hours_per_day = $estimate/$this->total_days;
$target_value = round($estimate-($this->remaining_days*$hours_per_day));
return $target_value > $estimate ? $estimate : $target_value;
}
-
+
public function get_current_percent() {
$target = $this->get_on_target_value();
$total = $this->get_estimate();
$current = $total-$this->get_time_left();
$target_percent = $target/$total*100;
return $current/$total*100;
}
-
+
public function get_current_target_percent() {
$target = $this->get_on_target_value();
$total = $this->get_estimate();
$current = $total-$this->get_time_left();
return $target/$total*100;
}
-
+
}
class ScrumioSprint {
-
+
public $item_id;
public $title;
public $start_date;
@@ -164,7 +187,7 @@ class ScrumioSprint {
public $total_days;
public $remaining_days;
public $stories;
-
+
public function __construct($sprint) {
global $api;
// Locate available states
@@ -180,7 +203,7 @@ public function __construct($sprint) {
}
// Find active sprint
$sprint_id = $sprint['item_id'];
-
+
// Set sprint properties
$this->item_id = $sprint['item_id'];
$this->title = $sprint['title'];
@@ -200,7 +223,7 @@ public function __construct($sprint) {
'sort_desc' => $sort_desc,
STORY_SPRINT_ID => $sprint_id,
));
-
+
// Grab all story items for all stories in one go
$stories_ids = array();
$stories_items = array();
@@ -228,25 +251,25 @@ public function __construct($sprint) {
$items = $stories_items[$story['item_id']];
$estimate = $stories_estimates[$story['item_id']] ? $stories_estimates[$story['item_id']] : '0';
$time_left = $stories_time_left[$story['item_id']] ? $stories_time_left[$story['item_id']] : '0';
-
+
if (count($items) > 0) {
$this->stories[] = new ScrumioStory($story, $items, $estimate, $time_left, $this->states, $this->get_working_days(), $this->get_working_days_left());
}
}
-
+
}
-
+
public function get_working_days() {
return getWorkingDays(date_format($this->start_date, 'Y-m-d'), date_format($this->end_date, 'Y-m-d'));
}
-
+
public function get_working_days_left() {
$start_date = date_create('now', timezone_open('UTC'));
-
+
// We substract 1 here to be able to 'chase the target' rather than 'working ahead'
return getWorkingDays(date_format($start_date, 'Y-m-d'), date_format($this->end_date, 'Y-m-d'))-1;
}
-
+
public function get_time_left() {
static $list;
if (!isset($list[$this->item_id])) {
@@ -257,7 +280,7 @@ public function get_time_left() {
}
return $list[$this->item_id] ? $list[$this->item_id] : '0';
}
-
+
public function get_estimate() {
static $list;
if (!isset($list[$this->item_id])) {
@@ -268,7 +291,7 @@ public function get_estimate() {
}
return $list[$this->item_id] ? $list[$this->item_id] : '0';
}
-
+
public function get_on_target_value() {
static $list;
if (!isset($list[$this->item_id])) {
@@ -278,11 +301,11 @@ public function get_on_target_value() {
$hours_per_day = $estimate/$total_days;
$target_value = round($estimate-($remaining_days*$hours_per_day));
$list[$this->item_id] = $target_value > $estimate ? $estimate : $target_value;
-
+
}
return $list[$this->item_id];
}
-
+
public function get_planned_daily_burn() {
static $list;
if (!isset($list[$this->item_id])) {
@@ -301,7 +324,7 @@ public function get_current_percent() {
$target_percent = $target/$total*100;
return $current/$total*100;
}
-
+
public function get_current_target_percent() {
$target = $this->get_on_target_value();
$total = $this->get_estimate();
@@ -316,7 +339,7 @@ public function get_finished() {
public function get_on_target_delta() {
return $this->get_finished()-$this->get_on_target_value();
}
-
+
}
//The function returns the no. of business days between two dates and it skips the holidays
View
19 views/_dashboard_story.html.php
@@ -1,4 +1,4 @@
-<li data-id="<?= $story->item_id ?>">
+<li data-id="<?= $story->item_id ?>" class="<?= implode(' ', $story->get_areas_class_list()); ?>">
<div class="body">
<div class="status-area">
<ul class="status">
@@ -14,14 +14,21 @@
<div class="metadata">
<?php
$links = array();
- $status_text = $story->get_status_text();
- if ($status_text) {
- $links[] = '<span class="'.$status_text['short'].'">'.$status_text['long'].'</span>';
+ // $status_text = $story->get_status_text();
+ // if ($status_text) {
+ // $links[] = '<span class="'.$status_text['short'].'">'.$status_text['long'].'</span>';
+ // }
+ if ($story->areas) {
+ $areas = array();
+ foreach ($story->areas as $area) {
+ $areas[] = '<span class="area" style="background-color:#'.$area['color'].'">'.$area['text'].'</span>';
+ }
+ $links[] = implode('', $areas);
}
- $links[] = $story->get_estimate() .' hrs estimated';
+ $links[] = '<span class="estimate">' . $story->get_estimate() .' hrs estimated</span>';
$links[] = '<a href="'.$story->link.'" class="external-link" target="_blank">view in podio</a>';
?>
- <?= implode(' | ', $links); ?>
+ <?= implode('', $links); ?>
</div>
</div>
</li>
View
5 views/_filters.html.php
@@ -0,0 +1,5 @@
+<ul>
+ <?php foreach($story_area_field['config']['settings']['options'] as $option): ?>
+ <li data-id="<?= $option['id']?>" data-color="#<?= $option['color']?>"><?= $option['text']?></li>
+ <?php endforeach ?>
+</ul>
View
4 views/_story.html.php
@@ -1,6 +1,10 @@
<div class="story-group" id="story-<?= $story->item_id ?>" data-id="<?= $story->item_id ?>">
<div class="story-header">
<h2><div class="toggle"></div><?= $story->title ?></h2>
+ <?php foreach ($story->areas as $area): ?>
+ <span class="area" style="background-color:#<?= $area['color']; ?>"><?= $area['text']; ?></span>
+ <?php endforeach; ?>
+
<?php if ($story->product_owner) : ?>
<ul class="user-list">
<li>
View
27 views/index.html.php
@@ -3,18 +3,18 @@
<head>
<title>ScrumIO | draggable, droppable, trackable scrum!</title>
<!-- <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"> -->
- <link href='https://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold' rel='stylesheet' type='text/css'>
+ <link href='https://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="public/base.css" type="text/css" media="all" charset="utf-8">
<link rel="stylesheet" href="public/dashboard.css" type="text/css" media="all" charset="utf-8">
<link rel="stylesheet" href="public/board.css" type="text/css" media="all" charset="utf-8">
<link rel="stylesheet" href="public/tipsy/stylesheets/tipsy.css" type="text/css" media="all" charset="utf-8">
- <link rel="shortcut icon" href="public/i/favicon.png">
+ <link rel="shortcut icon" href="public/i/favicon.png">
</head>
<body>
<div id="navbar">
<a id="logout" href="<?= url_for('logout');?>">Log out</a>
- <a href="#" id="switch-view">Switch view</a> |
- Sprints:
+ <a href="#" id="switch-view">Switch view</a> |
+ Sprints:
<ul class="sprints">
<?php foreach ($sprints as $item) : ?>
<li class="<?= $sprint->item_id == $item['item_id'] ? 'selected' : '' ?>"><a href="<?= url_for('/show/'.$item['item_id']);?>"><?= $item['title']; ?></a></li>
@@ -37,11 +37,18 @@
</div>
</div>
- <ul class="stories">
- <?php foreach ($sprint->stories as $story) : ?>
- <?= render('_dashboard_story.html.php', NULL, array('story' => $story)); ?>
- <?php endforeach; ?>
- </ul>
+ <div class="stories-wrapper">
+ <?php if ($story_area_field = story_area_field($_SESSION['story_app'])) : ?>
+ <div class="filter">
+ Show only: <?= render('_filters.html.php', NULL, array('story_area_field' => $story_area_field)); ?>
+ </div>
+ <?php endif; ?>
+ <ul class="stories">
+ <?php foreach ($sprint->stories as $story) : ?>
+ <?= render('_dashboard_story.html.php', NULL, array('story' => $story)); ?>
+ <?php endforeach; ?>
+ </ul>
+ </div>
</div>
@@ -62,7 +69,7 @@
<script type="text/javascript" charset="utf-8">
var update_url_base = "<?= url_for('/item'); ?>";
</script>
- <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.js"></script>
<script src="public/tipsy/javascripts/jquery.tipsy.js" type="text/javascript" charset="utf-8"></script>
<script src="public/lib/jquery.ui.touch.js" type="text/javascript" charset="utf-8"></script>

0 comments on commit 2863a54

Please sign in to comment.
Something went wrong with that request. Please try again.