Index: uts.pages.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uts/uts.pages.inc,v
retrieving revision 1.33
diff -u -r1.33 uts.pages.inc
--- uts.pages.inc	13 Oct 2008 01:27:35 -0000	1.33
+++ uts.pages.inc	27 Dec 2008 07:13:11 -0000
@@ -304,7 +304,7 @@
 
 /**
  * Dashboard displayed on admin/uts as the main landing page. If no studies
- * displays instructional video(s) otherwise summary view.
+ * displays instructional video(s), otherwise summary view.
  *
  * @return string HTML output.
  */
@@ -312,23 +312,149 @@
   drupal_add_css(drupal_get_path('module', 'uts') . '/uts.css', 'module');
   $studies = uts_studies_load();
 
-  $output = '';
-  if (empty($studies)) {
-    $output .= t('<p>Running a usability test will give you valuable data to improve your application.
+  $out = '';
+  if (!$studies) {
+    $out .= t('<p>Running a usability test will give you valuable data to improve your application.
                   Getting feedback from real people using your module is the best feedback you can get.
                   The usability testing suite allows you to easily collect exactly that data!</p>');
-    $output .= '<div class="uts-dashboard">';
-    $output .= l(t('Create study'), 'admin/uts/studies/add', array('attributes' => array('id' => 'uts-create-study')));
-    $output .= '<h3 id="uts-learn">' . t('Learn about UTS, watch a video.') . '</h3>';
-    $output .= '<embed src="http://blip.tv/play/AaXwG4mSHQ" type="application/x-shockwave-flash" width="640" height="510" allowscriptaccess="always" allowfullscreen="true"></embed>';
-    $output .= '</div>';
+    $out .= '<div class="uts-dashboard">';
+    $out .= l(t('Create study'), 'admin/uts/studies/add', array('attributes' => array('id' => 'uts-create-study')));
+    $out .= '<h3 id="uts-learn">' . t('Learn about UTS, watch a video.') . '</h3>';
+    $out .= '<embed src="http://blip.tv/play/AaXwG4mSHQ" type="application/x-shockwave-flash" width="640" height="510" allowscriptaccess="always" allowfullscreen="true"></embed>';
+    $out .= '</div>';
   }
   else {
-    // TODO #307518.
-    $output .= 'TODO: http://drupal.org/node/307518';
+    $out .= '<div id="uts-dashboard-summary">' . uts_dashboard_studies($studies) . '</div>';
   }
 
-  return $output;
+  return $out;
+}
+
+function uts_dashboard_studies($studies) {
+  $header = array(t('Name'), t('Participants'), t('Task progress'));
+  $rows = array();
+
+  // Cycle through studies to generate summary table.
+  foreach ($studies as $study) {
+    $progress = uts_dashboard_studies_progress($study);
+    $tasks = uts_tasks_load($study->nid);
+
+    $row = array();
+    $row[] = array(
+      'data' => l($study->title, 'node/' . $study->nid),
+      'id' => $study->nid
+    );
+    $row[] = t('@count / @required', array('@count' => $progress['overal']['participated'], '@required' => $study->participant_count));
+    $row[] = theme('uts_progress', $progress['overal']['completed'], count($tasks) * $study->participant_count);
+
+    $rows[] = $row;
+
+    // Generate individual task rows.
+    foreach ($tasks as $task) {
+      $row = array();
+      $row[]['data'] = l($task->title, 'node/' . $task->nid);
+      $row[] = t('@count / @required', array('@count' => $progress[$task->nid]['participated'], '@required' => $study->participant_count));
+      $row[] = theme('uts_progress', $progress[$task->nid]['completed'], $study->participant_count);
+
+      $rows[] = $row;
+    }
+  }
+
+  return theme('uts_dashboard_studies', $header, $rows);
+}
+
+function theme_uts_dashboard_studies($header, $rows) {
+  drupal_add_js(drupal_get_path('module', 'uts') . '/uts.js');
+
+  $js = array(
+    'images' => array(
+      theme('image', 'misc/menu-collapsed.png', 'Expand', 'Expand'),
+      theme('image', 'misc/menu-expanded.png', 'Collapsed', 'Collapsed'),
+    ),
+  );
+
+  foreach ($rows as $key => $row) {
+    $name = $rows[$key][0]['data'];
+    if ($id = $rows[$key][0]['id']) {
+      $last_study_id = 'uts-study-' . $id;
+      $rows[$key][0] = array(
+        'data'  => '<div class="uts-image" id="' . $last_study_id . '"></div>' . $name,
+        'class' => 'uts-study',
+        'style' => 'font-weight: bold;'
+      );
+      $js[$last_study_id] = array(
+        'imageDirection' => 0 // Collapsed.
+      );
+    }
+    else {
+      $rows[$key][0] = theme('indentation', 1) . $name;
+      $rows[$key] = array(
+        'data' => $rows[$key],
+        'class' => $last_study_id . '-task uts-task',
+        'style' => 'display: none;'
+      );
+    }
+  }
+
+  drupal_add_js(array('uts' => $js), 'setting');
+  return theme('table', $header, $rows);
+}
+
+function uts_dashboard_studies_progress($study) {
+  $sessions = uts_session_load_all($study->nid);
+
+  // Get the number of sessions that completed each task.
+  $tasks = uts_tasks_load($study->nid);
+
+  // Initialize all progress results to 0.
+  $progress = array();
+  $progress['overal']['completed'] = 0;
+  $progress['overal']['participated'] = count($sessions);
+  foreach ($tasks as $task) {
+    $progress[$task->nid]['completed'] = 0;
+    $progress[$task->nid]['participated'] = 0;
+  }
+
+  // Collect task progress data based on the related sessions.
+  foreach ($sessions as $session_id) {
+    $session = uts_session_load($session_id);
+
+    if ($session->complete) {
+      // Session completed all tasks.
+      foreach ($tasks as $task) {
+        $progress['overal']['completed']++;
+        $progress[$task->nid]['completed']++;
+        $progress[$task->nid]['participated']++;
+      }
+    }
+    else {
+      // See how far the session has progressed.
+      foreach ($tasks as $task) {
+        if ($session->current_task != $task->nid) {
+          // Made it past this task.
+          $progress['overal']['completed']++;
+          $progress[$task->nid]['completed']++;
+          $progress[$task->nid]['participated']++;
+        }
+        else {
+          $progress[$task->nid]['participated']++;
+          break;
+        }
+      }
+    }
+  }
+  return $progress;
+}
+
+function theme_uts_progress($progress, $total) {
+  if ($total) {
+    $part = round(($progress / $total) * 100);
+    $whole = 100 - $part;
+  }
+  return '<div id="uts-dashboard-progess">' . ($total ?
+           '<div id="uts-dashboard-progess-part" style="width: ' . $part . 'px;"></div>' .
+           '<div id="uts-dashboard-progess-whole" style="width: ' . $whole . 'px;"></div>' : '') .
+         '</div>';
 }
 
 /**
Index: uts.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uts/uts.module,v
retrieving revision 1.47
diff -u -r1.47 uts.module
--- uts.module	13 Oct 2008 01:27:35 -0000	1.47
+++ uts.module	27 Dec 2008 07:13:11 -0000
@@ -521,6 +521,12 @@
     ),
     'uts_participate_start_form_data_collection' => array(
       'arguments' => array('form' => NULL)
+    ),
+    'uts_dashboard_studies' => array(
+      'arguments' => array('header' => NULL, 'rows' => NULL)
+    ),
+    'uts_progress' => array(
+      'arguments' => array('progress' => 0, 'total' => 100)
     )
   );
 }
Index: uts.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uts/uts.css,v
retrieving revision 1.1
diff -u -r1.1 uts.css
--- uts.css	13 Oct 2008 01:27:35 -0000	1.1
+++ uts.css	27 Dec 2008 07:13:10 -0000
@@ -9,8 +9,40 @@
 a#uts-create-study {
   padding: 7px;
   border: 1px solid;
+  font-weight: bold;
 }
 
 h3#uts-learn {
   margin-top: 20px;
 }
+
+/* Dashboard studies
+ *******************/
+div.uts-image {
+  cursor: pointer;
+  display: inline;
+  margin-right: 5px;
+}
+
+div#uts-dashboard-summary {
+  float: left;
+}
+
+div#uts-dashboard-progess {
+  border: 2px solid #FFFFFF;
+  height: 10px;
+  background: #CCCCCC;
+}
+
+div#uts-dashboard-progess-part, div#uts-dashboard-progess-whole {
+	float: left;
+  height: 10px;
+}
+
+div#uts-dashboard-progess-part {
+  background-color: #92f86e;
+}
+
+div#uts-dashboard-progess-whole {
+  background-color: #f36161;
+}
\ No newline at end of file
Index: uts.js
===================================================================
RCS file: uts.js
diff -N uts.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ uts.js	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,56 @@
+// $Id$
+
+/**
+ * Add collapse/expand triggers to the dashboard rows.
+ *
+ * @see Modified from Drupal 7 core simpletest.js.
+ */
+Drupal.behaviors.utsMenuCollapse = function() {
+   var timeout = null;
+   
+   // Adds expand-collapse functionality.
+   $('div.uts-image').each(function() {
+     direction = Drupal.settings.uts[$(this).attr('id')].imageDirection;
+     $(this).html(Drupal.settings.uts.images[direction]);
+   });
+
+   // Adds group toggling functionality to arrow images.
+   $('div.uts-image').click(function() {
+     var trs = $(this).parents('tbody').children('.' + this.id + '-task');
+     var direction = Drupal.settings.uts[this.id].imageDirection;
+     var row = direction ? trs.size() - 1 : 0;
+
+     // If clicked in the middle of expanding a group, stop so we can switch directions.
+     if (timeout) {
+       clearTimeout(timeout);
+     }
+
+     // Function to toggle an individual row according to the current direction.
+     // We set a timeout of 20 ms until the next row will be shown/hidden to
+     // create a sliding effect.
+     function rowToggle() {
+       if (direction) {
+         if (row >= 0) {
+           $(trs[row]).hide();
+           row--;
+           timeout = setTimeout(rowToggle, 20);
+         }
+       }
+       else {
+         if (row < trs.size()) {
+           $(trs[row]).removeClass('js-hide').show();
+           row++;
+           timeout = setTimeout(rowToggle, 20);
+         }
+       }
+     }
+
+     // Kick-off the toggling upon a new click.
+     rowToggle();
+
+     // Toggle the arrow image next to the test group title.
+     $(this).html(Drupal.settings.uts.images[(direction ? 0 : 1)]);
+     Drupal.settings.uts[this.id].imageDirection = !direction;
+
+   });
+};
