Permalink
Browse files

Initial commit - with Limonade

  • Loading branch information...
haugstrup committed Apr 30, 2011
1 parent 8241a88 commit 5fac8dc6769d3f32bb9d0ba4f13b4756ebcb475a
View
21 LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2011 Andreas Haugstrup Pedersen, Kenneth Auchenberg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
@@ -0,0 +1,29 @@
+# Podio API Sample: Virtual Scrumboard
+This is a simple example of how you can build specialized visual interfaces on top of Podio. It creates a virtual scrumboard based on Podio. You control all your sprints inside Podio and use the virtual scrumboard to get an overview of the state for your current sprint.
+
+This allows all team members to stay on the same page even if they are not in the same physical location. Perfect for split teams or just for when you are working from home. The virtual scrumboard also uses the reporting widgets to calculate the sum of hours left in the current sprint and tells you if the team is on track or not.
+
+When you open the scrumboard you will see a quick overview of all the features to be implemented. A bullet graph shows the current progress and you can glance at how many cards are done. Clicking on a feature shows a traditional scrumboard for that feature. You can use drag and drop to move story cards from state to state and work progresses and any changes will of course be reflected on Podio. You can even attach responsible developers so you can see on the scrumboard who is responsible for a story card.
+
+# Creating your Podio apps
+You will need three apps to run the scrumboard: Sprints (sets the daterange for a sprint), Stories (for each feature to be implemented) and Story Items (for each task inside a feature). You can name the apps and fields anything, but they should contain the following fields as a minimum:
+
+## Sprints app
+* Date field: Use it to set a start and end time for each sprint
+* State field with two allowed values ("Active" and "Inactive"). Use it to mark the current active sprint
+
+## Stories app
+* App field: Set it to reference the sprint that the story is contained in
+* Contact field: Set it to mark who is the Product Owner for the story
+
+## Story Items app
+* App field: Set it to reference the story that each story item is a part of
+* Duration field: Use it to record the time estimate (in hours) for the story item. Used to generate bullet graphs of the current progress.
+* Duration field: Use it to record the time left (in hours) for the story item. Used to generate bullet graphs of the current progress.
+* State field: Create it with 4 allowed values ("Not started", "Dev started", "Dev done" and "PO done"). This controls which column the item is shown in on the scrumboard. You can create other states if these don't fit you. The scrumboard should adapt accordingly
+* Contact field: Set te responsible developer for each story item
+
+# Setting up the scrumboard
+* Add some content to your apps
+* Copy config.php.example to config.php and add your credentials for Podio and add the appropriate IDs from your Podio apps. Nb. You can find field IDs by inspecting the data attributes when viewing the item create/edit form.
+* Run index.php in your browser
View
@@ -0,0 +1,26 @@
+<?php
+
+define('CLIENT', '/path/to/podio-php/PodioAPI.php');
+define('API_SERVER', 'https://api.podio.com:443');
+define('CLIENT_ID', '');
+define('CLIENT_SECRET', '');
+define('USERNAME', '');
+define('PASSWORD', '');
+
+define('SPRINT_APP_ID', null);
+define('SPRINT_STATE_ID', null);
+
+define('STORY_APP_ID', null);
+define('STORY_SPRINT_ID', null);
+define('STORY_OWNER', null);
+
+define('ITEM_TITLE_ID', null);
+define('ITEM_APP_ID', null);
+define('ITEM_STORY_ID', null);
+define('ITEM_STATE_ID', null);
+define('ITEM_ESTIMATE_ID', null);
+define('ITEM_TIMELEFT_ID', null);
+define('ITEM_RESPONSIBLE_ID', null);
+
+define('STATE_DEV_DONE', 'Dev done');
+define('STATE_NOT_STARTED', 'Not started');
View
@@ -0,0 +1,25 @@
+<?php
+require_once 'vendor/limonade.php';
+require_once 'scrumio.classes.php';
+require_once 'init.php';
+
+dispatch('/', 'scrumboard');
+ function scrumboard() {
+ $sprint = new ScrumioSprint();
+ return html('index.html.php', NULL, array('sprint' => $sprint));
+ }
+
+dispatch_put('/item/:item_id', 'update_time_left');
+ function update_time_left() {
+ global $api;
+ $item_id = params('item_id');
+ $state = $_POST['state'];
+
+ $data = array(array('value' => $state));
+ $api->item->updateFieldValue($item_id, ITEM_STATE_ID, $data, 1);
+ if ($state == STATE_DEV_DONE) {
+ $api->item->updateFieldValue($item_id, ITEM_TIMELEFT_ID, array(array('value' => 0)), 1);
+ }
+ return txt('ok');
+ }
+run();
View
@@ -0,0 +1,28 @@
+<?php
+require_once('config.php');
+require_once(CLIENT);
+session_start();
+
+// Setup API client and get access token
+$oauth = PodioOAuth::instance();
+$baseAPI = PodioBaseAPI::instance(API_SERVER, CLIENT_ID, CLIENT_SECRET);
+
+// Obtain access token and init API class
+if (!isset($_SESSION['access_token'])) {
+ $oauth->getAccessToken('password', array('username' => USERNAME, 'password' => PASSWORD));
+
+ $api = new PodioAPI();
+ $_SESSION['access_token'] = $oauth->access_token;
+ $_SESSION['refresh_token'] = $oauth->refresh_token;
+
+ // Figure out which space we're on so we can build links to items
+ $_SESSION['story_app'] = $api->app->get(STORY_APP_ID);
+ $_SESSION['space'] = $api->space->get($_SESSION['story_app']['space_id']);
+}
+else {
+ $oauth->access_token = $_SESSION['access_token'];
+ $oauth->refresh_token = $_SESSION['refresh_token'];
+
+ $api = new PodioAPI();
+}
+
View
Binary file not shown.
View
Binary file not shown.
View
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,52 @@
+Function.prototype.debounce = function debounce(threshold, execAsap) {
+ /// From http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
+ var func = this, timeout;
+
+ return function debounced() {
+ var obj = this, args = arguments;
+ function delayed() {
+ if (!execAsap) func.apply(obj, args);
+ timeout = null;
+ };
+
+ if (timeout) clearTimeout(timeout);
+ else if (execAsap) func.apply(obj, args);
+
+ timeout = setTimeout(delayed, threshold || 100);
+ };
+
+};
+
+Function.prototype.curry = function curry() {
+ var fn = this, args = Array.prototype.slice.call(arguments);
+ return function curryed() {
+ return fn.apply(this, args.concat(Array.prototype.slice.call(arguments)));
+ };
+};
+
+Function.prototype.curryAfter = function curryAfter() {
+ var fn = this, args = Array.prototype.slice.call(arguments);
+ return function curryedAfter() {
+ return fn.apply(this, Array.prototype.slice.call(arguments).concat(args));
+ };
+};
+
+Function.prototype.throttle = function throttle(delay) {
+ var func = this, timeOfLastExec = 0, execWaiting = false;
+
+ return function throttled() {
+ var obj = this, args = arguments, timeSinceLastExec = new Date().getTime() - timeOfLastExec;
+ if (timeSinceLastExec > delay) {
+ func.apply(obj, args);
+ execWaiting = false;
+ timeOfLastExec = new Date().getTime();
+ }
+ else if (!execWaiting) {
+ execWaiting = setTimeout(function() {
+ func.apply(obj, args);
+ execWaiting = false;
+ timeOfLastExec = new Date().getTime();
+ }, delay - timeSinceLastExec);
+ }
+ };
+};
@@ -0,0 +1,25 @@
+(function (window, $, undefined) {
+
+ function proxy_callback(callback, shouldPreserveDefault, e){
+ var target = $(e.currentTarget);
+ if(!shouldPreserveDefault) {
+ e.preventDefault();
+ }
+ callback.apply(this, [target].concat(Array.prototype.slice.call(arguments).slice(2)));
+ }
+
+ function bind(eventType, selector, fn, shouldPreserveDefault) {
+ $('body').delegate(selector, eventType, proxy_callback.curry(fn, shouldPreserveDefault));
+ }
+
+ function unbind(eventType, selector) {
+ $('body').undelegate(selector, eventType);
+ }
+
+ /** expose external methods **/
+ Podio.Event.UI = {
+ bind: bind,
+ unbind: unbind
+ };
+
+})(window, jQuery);
View
@@ -0,0 +1,35 @@
+(function (window, $, undefined) {
+
+ var eventNamespace = '.podio';
+
+ function onDomReady() {
+ $('body').trigger(Podio.Event.Types.init + eventNamespace);
+ }
+
+ function bind(type, fn) {
+ $('body').bind(type + eventNamespace, fn);
+ }
+
+ function unbind(type, fn) {
+ $('body').unbind(type + eventNamespace, fn);
+ }
+
+ function trigger(type, data) {
+ $('body').trigger(type + eventNamespace, data);
+ }
+
+ Podio.Event = {
+ bind: bind,
+ unbind: unbind,
+ trigger: trigger,
+ Types: {
+ init: 'init'
+ }
+ };
+
+ $(onDomReady);
+
+})(window, jQuery);
+
+
+
View
@@ -0,0 +1,8 @@
+(function (window, $, undefined) {
+
+ /** expose external methods **/
+ Podio = {
+
+ };
+
+})(window, jQuery);

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
Oops, something went wrong.

0 comments on commit 5fac8dc

Please sign in to comment.