Browse Source

Merge branch '7.x-3.x' into 7.x-3.x-dashboard

Shawna 7 years ago
parent
commit
267e9d87b7

+ 39 - 0
legacy/tripal_core/theme/templates/node--chado-generic.tpl.php

@@ -11,6 +11,8 @@ class TripalBundleUIController extends EntityDefaultUIController {
 
   public function __construct($entity_type, $entity_info) {
      parent::__construct($entity_type, $entity_info);
+     // Set the pager limit to something a bit larger
+     $this->overviewPagerLimit = 100;
   }
 
   /**
@@ -57,6 +59,43 @@ class TripalBundleUIController extends EntityDefaultUIController {
     return $forms;
   }
 
+  /**
+   * Override the EntityDefaultUIController::overviewTable because 
+   * it doesn't sort the content types by name
+   */
+  public function overviewTable($conditions = array()) {
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $this->entityType);
+  
+    // Add all conditions to query.
+    foreach ($conditions as $key => $value) {
+      $query->propertyCondition($key, $value);
+    }
+
+    if ($this->overviewPagerLimit) {
+      $query->pager($this->overviewPagerLimit);
+    }
+
+
+    $query->propertyOrderBy('label', 'ASC');
+    $results = $query->execute();
+
+    $ids = isset($results[$this->entityType]) ? array_keys($results[$this->entityType]) : array();
+    $entities = $ids ? entity_load($this->entityType, $ids) : array();
+
+    $rows = array();
+    foreach ($entities as $entity) {
+      $rows[] = $this->overviewTableRow($conditions, entity_id($this->entityType, $entity), $entity);
+    }
+
+    $render = array(
+      '#theme' => 'table', 
+      '#header' => $this->overviewTableHeaders($conditions, $rows), 
+      '#rows' => $rows, 
+      '#empty' => t('None.'),
+    );
+    return $render;
+  }
 }
 
 /**

+ 6 - 1
tripal/includes/TripalEntityUIController.inc

@@ -862,6 +862,11 @@ function tripal_form_field_ui_display_overview_form_alter(&$form, &$form_state,
  */
 function tripal_field_is_empty($item, $field) {
 
+  // If the $item argument is empty then return TRUE.
+  if (!$item) {
+    return TRUE;
+  }
+
   // If there is no value field then the field is empty.
   if (!array_key_exists('value', $item)) {
     return TRUE;
@@ -896,4 +901,4 @@ function theme_tripal_field_default($variables) {
     $widget = new $widget_class($field, $instance);
     return $widget->theme($element);
   }
-}
+}

+ 8 - 5
tripal/theme/js/tripal.file.js

@@ -5,14 +5,17 @@
       var tripal_files = new TripalUploader();
       
       $(".tripal-html5-file-upload-table-key").each(function(index) {
-        var form_key = $(this).val()
+        var id = $(this).val()
+        var details = id.split("-");
+        var form_key = details[0] + '-' + details[1];
+        var module = details[2];
         tripal_files.addUploadTable(form_key, {
-          'table_id' : '#tripal-html5-file-upload-table-' + form_key,
-          'submit_id': '#tripal-html5-file-upload-submit-' + form_key,
+          'table_id' : '#tripal-html5-file-upload-table-' + id,
+          'submit_id': '#tripal-html5-file-upload-submit-' + id,
           'category' : [form_key],
           'cardinality' : 1,
-          'target_id' : 'tripal-html5-upload-fid-' + form_key,
-          'module' : 'tripal',
+          'target_id' : 'tripal-html5-upload-fid-' + id,
+          'module' : module,
         });
       });
     }

+ 25 - 21
tripal/tripal.module

@@ -693,6 +693,7 @@ function tripal_block_info() {
  */
 function tripal_block_view($delta = ''){
   global $base_path;
+  $block = array();
 
   // The $delta parameter tells us which block is being requested.
   switch ($delta) {
@@ -926,7 +927,8 @@ function tripal_element_info() {
  */
 function tripal_html5_file_process($element, $form_state, $complete_form) {
 
-  $type = $element['#usage_id'] . '-' . $element['#usage_type'];
+  $module = array_key_exists('#usage_module', $element) ? $element['#usage_module'] : 'tripal';
+  $type = $element['#usage_id'] . '-' . $element['#usage_type'] . '-' . $module;
   $name = $element['#name'];
   $name = preg_replace('/[^\w]/', '_', $name);
 
@@ -1000,38 +1002,40 @@ function tripal_html5_file_validate($element, &$form_state) {
 
 
 /**
- * Implements hook_handle_uplaoded_file().
+ * Implements hook_handle_uploaded_file().
  */
 function tripal_handle_uploaded_file($filename, $filepath, $type) {
 
   global $user;
 
   // Split the type into a node ID and form_key
-  list($nid, $form_key) = explode('-', $type);
+  list($id, $form_key) = explode('-', $type);
+
 
   // See if this file is already managed then add another entry fin the
   // usage table.
   $fid = db_select('file_managed', 'fm')
-  ->fields('fm', array('fid'))
-  ->condition('uri', $filepath)
-  ->execute()
-  ->fetchField();
-  if ($fid) {
-    $file = file_load($fid);
-    file_usage_add($file, 'tripal', $form_key, $nid);
-    return $fid;
-  }
+    ->fields('fm', array('fid'))
+    ->condition('uri', $filepath)
+    ->execute()
+    ->fetchField();
 
   // Create a file object.
-  $file = new stdClass();
-  $file->uri = $filepath;
-  $file->filename = $filename;
-  $file->filemime = file_get_mimetype($filepath);
-  $file->uid = $user->uid;
-  $file->status = FILE_STATUS_PERMANENT;
-  $file = file_save($file);
-
-  return $file->fid;
+  if (!$fid) {
+    $file = new stdClass();
+    $file->uri = $filepath;
+    $file->filename = $filename;
+    $file->filemime = file_get_mimetype($filepath);
+    $file->uid = $user->uid;
+    $file->status = FILE_STATUS_PERMANENT;
+    $file = file_save($file);
+    $fid = $file->fid;
+  }
+
+  $file = file_load($fid);
+  file_usage_add($file, 'tripal', $form_key, $id);
+  return $fid;
+
 }
 
 /**

+ 0 - 1
tripal_chado/api/tripal_chado.query.api.inc

@@ -1318,7 +1318,6 @@ function chado_select_record($table, $columns, $values, $options = NULL) {
 
     // Require the field be in the table description.
     if (!array_key_exists($field, $table_desc['fields'])) {
-      dpm(debug_backtrace());
       tripal_report_error('tripal_chado', TRIPAL_ERROR,
         'chado_select_record: The field "%field" does not exist for the table "%table".  Cannot perform query. Values: %array',
         array('%field' => $field, '%table' => $table, '%array' => print_r($values, 1)),

+ 2 - 0
tripal_chado/api/tripal_chado.variables.api.inc

@@ -312,6 +312,7 @@ function chado_generate_var($table, $values, $base_options = array()) {
       // Check to see if the current record maps to an entity.  Because
       // multiple bundles can map to the same table we have to check
       // all bundles for this table.
+ /*
       $bundles = db_select('chado_bundle', 'cb');
       $bundles->fields('tb', array('name'));
       $bundles->join('tripal_bundle', 'tb', 'tb.id = cb.bundle_id');
@@ -328,6 +329,7 @@ function chado_generate_var($table, $values, $base_options = array()) {
           $object->entity_id = $record->entity_id;
         }
       }
+*/
 
       // remove any fields where criteria needs to be evalulated---------------------------------------
       // The fields to be removed can be populated by implementing either

+ 14 - 0
tripal_chado/includes/setup/tripal_chado.setup.inc

@@ -252,6 +252,13 @@ function tripal_chado_prepare_chado() {
         throw new Exception($error['!message']);
       }
     }
+    // Add cvterm mapping for the Map entity type
+    $identifier = array(
+      'cv_id' => array('name' => 'EDAM'),
+      'name' => 'Map'
+    );
+    $cvterm = tripal_get_cvterm($identifier);
+    tripal_chado_add_cvterm_mapping($cvterm->cvterm_id, 'featuremap', NULL);
 
     // Import a publication so we get all of the properties before
     // creating the content type.
@@ -274,6 +281,13 @@ function tripal_chado_prepare_chado() {
         throw new Exception($error['!message']);
       }
     }
+    // Add cvterm mapping for the Publication entity type
+    $identifier = array(
+      'cv_id' => array('name' => 'tripal_pub'),
+      'name' => 'Publication'
+    );
+    $cvterm = tripal_get_cvterm($identifier);
+    tripal_chado_add_cvterm_mapping($cvterm->cvterm_id, 'pub', NULL);
 
     // Now remove the publication that was added above.
     $values = array(

+ 36 - 0
tripal_chado/includes/tripal_chado.entity.inc

@@ -995,4 +995,40 @@ function tripal_chado_update_7305() {
     $error = $e->getMessage();
     throw new DrupalUpdateException('Could not perform update: '. $error);
   }
+}
+
+/**
+ * Add cvterm mapping for the Map entity type
+ */
+function tripal_chado_update_7306() {
+  try {
+    $identifier = array(
+      'cv_id' => array('name' => 'EDAM'),
+      'name' => 'Map'
+    );
+    $cvterm = tripal_get_cvterm($identifier);
+    tripal_chado_add_cvterm_mapping($cvterm->cvterm_id, 'featuremap', NULL);
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
+}
+
+/**
+ * Add cvterm mapping for the Publication entity type
+ */
+function tripal_chado_update_7307() {
+  try {
+    $identifier = array(
+      'cv_id' => array('name' => 'tripal_pub'),
+      'name' => 'Publication'
+    );
+    $cvterm = tripal_get_cvterm($identifier);
+    tripal_chado_add_cvterm_mapping($cvterm->cvterm_id, 'pub', NULL);
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
 }

+ 251 - 62
tripal_daemon/TripalDaemon.inc

@@ -23,6 +23,25 @@ class TripalDaemon extends DrushDaemon {
   // inherits from a library class.
   protected $loop_interval = 20;
 
+  // Keep track of whether we are running a Tripal job or not
+  // and if so, which Tripal jobs are we running.
+  // If this array is empty then we are waiting for jobs ;-).
+  protected $tripal_jobs = array();
+
+  // Queue of Tripal Jobs waiting to be run.
+  protected $queue = array();
+
+  // Boolean as to whether we are aloud to process jobs in parallel.
+  // @todo: Implement actually changing this setting.
+  // NOTE: Can't be set via a drush option to trpjob-daemon since
+  // tripal daemon calls drush daemon which then forks and can't
+  // pass on the options to the child.
+  protected $do_parallel = FALSE; 
+
+  // Maximum number of jobs that can be run in parallel.
+  // @todo: Implement actually changing this setting (see above note).
+  protected $max_num_jobs = 2;
+
   /**
    * Implements DaemonAPIDaemon::executeTask() function.
    *
@@ -39,77 +58,247 @@ class TripalDaemon extends DrushDaemon {
    */
   protected function executeTask($iteration_number) {
 
-    // When sorting the job list we want to use version specific SQL and thus
-    // need to know the postgreSQL version to determine what SQL to execute.
-    $version_string = db_query('SELECT version()')->fetchField();
-    if (preg_match('/PostgreSQL (\d+)\.(\d+)/', $version_string, $matches)) {
-      $version = array('major' => $matches[1], 'minor' => $matches[2]);
+    // If jobs are being run in parallel then we need to check to see if jobs
+    // we think are running have actually been completed.
+    if ($this->do_parallel) {
+      $this->checkJobStatus();
     }
-    // If we can't determine the version then use the deprecated method.
-    else {
-      $version = array('major' => 8, 'minor' => 4);
+
+    // Start the loop by seeing if there is a job to be run :-).
+    $job_id = $this->getTripalJobID();
+    while ($job_id) {
+
+      // Simply run the job :-D.
+      $this->runTripalJob($job_id);
+
+      // Get the next job (if we're aloud to run another one)...
+      $job_id = $this->getTripalJobID();
+    }
+
+    // If jobs are being run in parallel then we need to check to see if jobs
+    // we think are running have actually been completed.
+    if ($this->do_parallel) {
+      $this->checkJobStatus();
     }
+  }
+
+  /**
+   * Get job_id of Tripal Job to run.
+   *
+   * NOTE: This function should only return a job_id if we are aloud to run it.
+   */
+  protected function getTripalJobID() {
 
-    // First check to see if there are any tripal jobs to be run.
-    if ($version['major'] >= 9 ) {
-      $waiting_jobs = db_query(
-        "SELECT
-          count(*) as count,
-          array_to_string(array_agg(j.job_id ORDER BY j.priority ASC, j.job_id ASC),'|') as jobs
-        FROM {tripal_jobs} j
-        WHERE j.status = 'Waiting'"
-      )->fetchObject();
+    // First we need to determine if we are in sequenctial mode or parallel mode.
+    // Parallel:
+    if ($this->do_parallel) {
+
+      // Check that we arn't already running the maximum number of jobs.
+      if (tripal_max_jobs_exceeded($this->max_num_jobs)) {
+        $this->log('Already running the maximum number of jobs.');
+        return FALSE;
+      }
+      // Also check based on our list of running jobs just in case they haven't yet registered in the db.
+      if (sizeof($this->tripal_jobs) >= $this->max_num_jobs) {
+        $this->log('Already running the maximum number of jobs.');
+        return FALSE;
+      }
     }
+    // Sequential:
     else {
-     $waiting_jobs = db_query(
-        "SELECT
-          count(*) as count,
-          array_to_string(array_agg(j.job_id),'|') as jobs
-        FROM (SELECT * FROM {tripal_jobs} WHERE j.status = 'Waiting' ORDER BY priority ASC, job_id ASC) as j"
-      )->fetchObject();
-    }
-
-    $num_waiting_jobs = $waiting_jobs->count;
-    $job_ids = explode('|', $waiting_jobs->jobs);
-
-    // If there are then run them and log the output.
-    if ($num_waiting_jobs > 0) {
-      $this->log($num_waiting_jobs . ' Waiting Tripal Jobs... '
-        . 'Running waiting job(s) now.');
-
-      // Launch all tripal jobs :) Yay for bootstrapping!!
-      foreach ($job_ids as $id) {
-        $this->log('Starting Job (ID=' . $id . ')', '', 1);
-
-        // We would like to log the output from the job.
-        // However, most tripal jobs simply print to the screen :-(
-        // Thus we have to use output buffering to capture the output.
-        // Start Buffering.
-        ob_start();
-
-        // Launch Tripal Job.
-        tripal_launch_job(FALSE, $id);
-
-        // Save the buffer to the log and stop buffering.
-        $this->log(str_repeat('=', 80));
-        $this->log(ob_get_clean());
-        $this->log(str_repeat('=', 80));
-
-        // Report job details.
-        $job = db_query(
-          "SELECT j.*
-          FROM {tripal_jobs} j
-          WHERE j.job_id = :jid",
-          array(':jid' => $id)
-        )->fetchObject();
-        $this->log("Job completed at "
-        . date('d M Y H:i:s', $job->end_time) . " with a status of '"
-        . $job->status . "'", "", 1);
+
+      // Check that we arn't already running a job.
+      if (tripal_is_job_running()) {
+        $this->log('Job is still running. Waiting until it completes before starting another one.');
+        return FALSE;
       }
     }
+
+    // If we reach this point then we're aloud to run a job! :-D.
+    //-----------------------------------------------------------
+
+    // We would like to use a queue to keep track of Tripal Jobs to be run.
+    // This will cut down on the number of queries and help ensure that the same job is
+    // not run repeatedly with parallel processing.
+    // First step, fill the queue if it's empty.
+    if (empty($this->queue)) {
+      $this->queue = db_query(
+        "SELECT job_id FROM {tripal_jobs} TJ
+         WHERE TJ.start_time IS NULL AND TJ.end_time IS NULL AND TJ.status != 'Cancelled'
+         ORDER BY priority ASC, job_id ASC"
+      )->fetchCol();
+    }
+
+    // If the queue is still empty then there are no jobs waiting.
+    if (empty($this->queue)) {
+      return FALSE;
+    }
+
+    // Return the next job in line.
+    $job_id = array_shift($this->queue);
+
+    // But only if it wasn't already run.
+    if (!isset($this->tripal_jobs[$job_id])) {
+      return $job_id;
+    }
+  }
+
+  /**
+   * Run Tripal Job.
+   */
+  protected function runTripalJob($job_id) {
+
+    // Load the job we are going to run.
+    $job = new TripalJob();
+    $job->load($job_id);
+
+    // Tell admins we are running a job.
+    $this->tripal_jobs[$job_id] = $job;
+    $this->setStatus();
+    // And log the details.
+    $this->log('Job (ID='.$job_id.') Started at '.format_date(time(), 'small').'.');
+
+    // Parallel:
+    if ($this->do_parallel) {
+      $this->runParallelTripalJob($job_id);
+    }
+    // Sequential:
     else {
-      $this->log('There are no Tripal Jobs to run');
+      $job = $this->runSequentialTripalJob($job);
+
+      // Job needs to be re-loaded to reflect the new end time and status
+      // since this does not seem to be set by run().
+      $job->load($job_id);
+
+      // If the job is sequential then we know we are done the job
+      // just by the virtue of having reached this code.
+      // As such, tell the admin :-).
+      unset($this->tripal_jobs[$job_id]);
+      $this->setStatus();
+      // And log the details.
+      $this->log('Job (ID='.$job_id.') Completed');
+      $this->log('End DateTime: '.format_date($job->getEndTime(), 'small'), '', 1);
+      $this->log('Status: '.$job->getStatus(), '', 1);
+
     }
+  }
+
+  /**
+   * Run Parallel Tripal Job.
+   */
+  protected function runParallelTripalJob($job_id) {
+
+    // Tripal job launcher needs the user... Unfortunatly we cannot pass one through the
+    // drush command since that is intercepted by drushd.
+    // As such we are going ot use the god user (uid=1) as a default that can be overriden
+    // by passing in the drush "user" option.
+    $uid = drush_get_option('user', 1);
+    $user = user_load($uid);
+    $username = $user->name;
+
+    // We use drush_invoke_process() to fork the daemon safely to run
+    // multiple jobs concurrently. We can't use the PHP-daemon built
+    // in functionality such as workers & tasks b/c they copy the
+    // entire enviro. resulting in mutliple processes using the same
+    // database connection (which causes errors).
+    drush_invoke_process(
+      '@self',                               // Obviously run on the current site.
+      'trp-run-jobs',                        // Run the tripal job launcher.
+      array(),                               // No arguements (only options below).
+      array(
+        'job_id' => $job_id,                 // The job to be run.
+        'username' => $username,             // The user to run it as.
+        'single' => 1,                       // Only run a single job!
+        'parallel' => $this->do_parallel,    // We're aloud to run in parallel.
+        'max_jobs' => $this->max_num_jobs,   // But only this many jobs at once.
+      ),
+      array('fork' => TRUE)                  // This tells drush to spawn a new process.
+    );
+
+  }
+
+  /**
+   * Run Sequential Tripal Job.
+   */
+  protected function runSequentialTripalJob($job) {
+
+    // Run the job.
+    try {
+      $job->run();
+    }
+    catch (Exception $e) {
+      $job->logMessage($e->getMessage(), array(), TRIPAL_ERROR);
+    }
+
+    return $job;
+  }
+
+  /**
+   * Check the status of a given (or all running) jobs.
+   *
+   * @param $job_id
+   *    The job_id of a specific job to check the status us. (OPTIONAL)
+   */
+  protected function checkJobStatus($job_id = FALSE) {
+
+    if ($job_id) {
+      $job = new TripalJob();
+      $job->load($job_id);
+      $jobs = array($job_id);
+    }
+    elseif (!empty($this->tripal_jobs)) {
+      $jobs = array_keys($this->tripal_jobs);
+    }
+    else {
+      return TRUE;
+    }
+
+    $results = db_query(
+      'SELECT job_id, pid, end_time, status FROM {tripal_jobs} WHERE job_id IN (:jobs)',
+      array(':jobs' => $jobs));
+    foreach ($results as $job) {
+      // If the system still thinks the job is running then check it's pid.
+      if ($job->status == 'Running') {
+        $status = shell_exec('ps -p ' . escapeshellarg($job->pid) . ' -o pid=');
+        if (!$status) {
+
+          // Update the job.
+          $job->end_time = time();
+          $job->error_msg = 'Unknown Error Encountered.';
+          $job->status = 'Error';
+          $job->pid = '';
+          drupal_write_record('tripal_jobs', $job, 'job_id');
+        }
+      }
+
+      // The job is finished if it's not running or waiting -tell the admin.
+      if ($job->status != 'Running' AND $job->status != 'Waiting') {
+
+        // As such, tell the admin :-).
+        unset($this->tripal_jobs[$job->job_id]);
+        $this->setStatus();
+        // And log the details.
+        $this->log('Job (ID='.$job->job_id.') Completed');
+        $this->log('End DateTime: '.format_date($job->end_time, 'small'), '', 1);
+        $this->log('Status: '.$job->status, '', 1);
+
+      }
+    }
+  }
+
+  /**
+   * Override to include additional daemon-specific settings for use in reports.
+   *
+   * @return array
+   *   An array of status details where the key should be a human-readable
+   *   name for your detail and the value should be the current state.
+   */
+  protected function getStatusDetails() {
+    $status_details = parent::getStatusDetails();
+
+    $status_details['Running Job'] = (empty($this->tripal_jobs)) ? FALSE : TRUE;
+    $status_details['Current Jobs'] = array_keys($this->tripal_jobs);
 
+    return $status_details;
   }
 }

+ 139 - 15
tripal_daemon/includes/tripal_daemon.blocks.inc

@@ -10,8 +10,23 @@
 function tripal_daemon_block_info() {
   $blocks = array();
 
-  $blocks['tripal_daemon_status'] = array(
+  // Status Blocks.
+  $blocks['trpdaemon_status'] = array(
     'info' => t('Tripal Daemon Status'),
+    'cache' => DRUPAL_NO_CACHE,
+  );
+  $blocks['trpdaemon_status_admin'] = array(
+    'info' => t('Tripal Daemon Status: ADMIN'),
+    'cache' => DRUPAL_NO_CACHE,
+    'status' => TRUE,
+    'region' => 'dashboard_sidebar',
+  );
+
+  // Display Log Block.
+  $blocks['trpdaemon_log'] = array(
+    'info' => t('Tripal Daemon Log'),
+    'status' => TRUE,
+    'region' => 'dashboard_main',
   );
   
   return $blocks;
@@ -24,59 +39,168 @@ function tripal_daemon_block_view($delta='') {
   $block = array();
 
   switch($delta) {
-    case 'tripal_daemon_status':
-      $is_running = drushd_is_daemon_running('tripal_daemon');
-      $status_class = ($is_running) ? 'active' : 'inactive';
+    case 'trpdaemon_status_admin':
+      $block['subject'] = t('Job Daemon Status');
+      $block['content'] = theme_tripal_daemon_status_block_content(TRUE);
+      break;
+    case 'trpdaemon_status':
       $block['subject'] = t('Job Daemon Status');
       $block['content'] = theme_tripal_daemon_status_block_content();
       break;
+    case 'trpdaemon_log':
+      $block['subject'] = t('Job Daemon Log');
+      $block['content'] = drupal_get_form('trpdaemon_display_log_form');
+      break;
   }
   
   return $block;
 }
 
 /** 
+ * Provide markup for the Tripal Job Daemon Status block.
  *
+ * @param $show_all
+ *   A boolean indicating whether to show administrative detail (TRUE) or not (FALSE).
+ * @return
+ *   HTML to be rendered for the block.
  */
-function theme_tripal_daemon_status_block_content() {
+function theme_tripal_daemon_status_block_content($show_all = FALSE) {
   $output = '';
 
   // Get information.
   $is_running = drushd_is_daemon_running('tripal_daemon');
   $status_file = drushd_get_daemon_status_file('tripal_daemon');
   $status = unserialize(file_get_contents($status_file));
+  $PID = $status['PID'];
+  $is_alive = `ps h --pid $PID | wc -l`;
+  $is_alive = trim($is_alive);
 
   $status_class = ($is_running) ? 'active' : 'inactive';
+  $status_class = ($is_running AND !$is_alive) ? 'dead' : $status_class;
 
   // Theme content.
   drupal_add_css(drupal_get_path('module','tripal_daemon') . '/theme/status_block.css');
 
+  // Display the status.
   $output .= '<div class="daemon-status">';
-  if ($is_running) {
+  if ($is_running and $is_alive) {
     $output .= theme_image(array(
       'path' => 'misc/message-24-ok.png',
       'alt' => 'status-ok',
     ));
-    $output .= 'Running';
+    if ($status['Running Job']) {
+      $output .= 'Running Job(s)';
+    }
+    else {
+      $output .= 'Waiting for Job';
+    }
   }
   else {
     $output .= theme_image(array(
       'path' => 'misc/message-24-error.png',
       'alt' => 'status-error',
     ));
-    $output .= 'Stopped';
+    if ($is_running AND !$is_alive) {
+      $output .= 'Dead';
+    }
+    else {
+      $output .= 'Stopped';
+    }
   }
   $output .= '</div>';
 
-  $output .= '<ul>';
-  foreach ($status as $k => $v) {
-    if (is_bool($v)) {
-      $v = ($v) ? 'True' : 'False';
-    }
+  // If asked, show all the details.
+  if ($show_all) {
+    $output .= '<ul>';
+    foreach ($status as $k => $v) {
+
+      // If it's a boolean, then make it readable.
+      if (is_bool($v)) {
+        $v = ($v) ? 'True' : 'False';
+      }
+
+      // If these are current jobs then we want to link to details.
+      if ($k == 'Current Jobs' AND !empty($v)) {
+        $list = array();
+        foreach ($v as $job_id) {
+          $url = 'admin/tripal/tripal_jobs/view/' . $job_id;
+          $list[$job_id] = l($job_id, $url);
+        }
+        $v = $list;
+      }
 
-    $output .= '<li><strong>' . $k . '</strong>: ' . $v . '</li>';
+      // If it's an array then make it a list.
+      if (is_array($v)) {
+        if (empty($v)) {
+          $v = 'None';
+        }
+        else {
+          $v = implode(', ', $v);
+        }
+      }
+
+      $output .= '<li><strong>' . $k . '</strong>: ' . $v . '</li>';
+    }
+    $output .= '</ul>';
   }
-  $output .= '</ul>';
 
   return '<div class="inner '.$status_class.'">' . $output . '</div>';
 }
+
+/**
+ * Form to display a user selected number of lines from the Tripal Job Daemon log file.
+ */
+function trpdaemon_display_log_form($form, $form_state) {
+
+  $form['#attached']['css'][] = drupal_get_path('module','tripal_daemon') . '/theme/tripal_daemon.log_block.css';
+
+  $status_file = drushd_get_daemon_status_file('tripal_daemon');
+  $status = unserialize(file_get_contents($status_file));
+  $file = $status['Current Log File'];
+
+  $form['num_lines'] = array(
+    '#type' => 'radios',
+    '#title' => 'Lines',
+    '#description' => 'The number of lines to display from the end of the Tripal Job Daemon Log file.',
+    '#options' => array(
+      '10' => '10',
+      '25' => '25',
+      '50' => '50',
+      '100' => '100',
+      '200' => '200',
+      '500' => '500',
+    ),
+    '#default_value' => '25',
+    '#attributes'     => array(
+      'onChange' => 'this.form.submit();',
+      'class' => array('container-inline'),
+    ),
+  );
+  $num_lines = (isset($form_state['values'])) ? $form_state['values']['num_lines'] : $form['num_lines']['#default_value'];
+
+  $text = `tail -n $num_lines $file`;
+  $text = str_replace("\n", '<br />', $text);
+  $form['log'] = array(
+    '#type' => 'markup',
+    '#markup' => $text,
+    '#prefix' => '<pre id="daemon-log">',
+    '#suffix' => '</pre>',
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Apply'),
+    '#attributes' => array(
+      'style' => array('display: none;'),
+     ),
+  );
+
+  return $form;
+}
+
+/**
+ * Display Log Form: Submit.
+ */
+function trpdaemon_display_log_form_submit($form, &$form_state) {
+  $form_state['rebuild'] = TRUE;
+}

+ 13 - 7
tripal_daemon/theme/status_block.css

@@ -1,29 +1,35 @@
 /**
  * Tripal Daemon Status Block.
  */
-#dashboard #block-tripal-daemon-tripal-daemon-status div.content,
-  div#block-tripal-daemon-tripal-daemon-status div.content {
+#dashboard div.block.block-tripal-daemon div.content,
+  div.block-tripal-daemon div.content {
     padding: 0;
 }
-#block-tripal-daemon-tripal-daemon-status div.content div.inner {
+div.block-tripal-daemon div.content div.inner {
   padding: 15px; 
 }
-#block-tripal-daemon-tripal-daemon-status .active {
+
+div.block-tripal-daemon .active {
   background-color: #f8fff0; 
   color: #234600;
 }
-#block-tripal-daemon-tripal-daemon-status .inactive {
+div.block-tripal-daemon .dead {
   background-color: #fef5f1;
   color: #8c2e0b;
 }
+div.block-tripal-daemon .inactive {
+  background-color: #fef5f1;
+  color: #b3b3b3;
+}
 
-#block-tripal-daemon-tripal-daemon-status .daemon-status {
+div.block-tripal-daemon .daemon-status {
   font-weight: bolder;
   font-size: 1.2em;
   margin-bottom: 15px;
 }
-#block-tripal-daemon-tripal-daemon-status .daemon-status img {
+div.block-tripal-daemon .daemon-status img {
   top: 6px;
   position: relative;
   padding-right: 5px;
+  border: 0;
 }

+ 12 - 0
tripal_daemon/theme/tripal_daemon.log_block.css

@@ -0,0 +1,12 @@
+/**
+ * Themeing for the Tripal Daemon Log Block.
+ */
+
+#trpdaemon-display-log-form {
+  padding: 15px;
+}
+
+#trpdaemon-display-log-form .form-radios .form-item {
+  padding-right: 5px;
+}
+

+ 6 - 1
tripal_ds/theme/css/tripaldsfeature.css → tripal_ds/theme/css/tripal_ds.css

@@ -69,4 +69,9 @@ span.download-icon {
     border: none;
 }
 
-
+.tripal_pane-fieldset-buttons {
+  float: right;
+  cursor: pointer;
+  margin-top: 4px;
+  color: #777777;
+}

+ 10 - 12
tripal_ds/theme/js/tripal_ds.js

@@ -5,19 +5,18 @@
 
       // Add a close button for each pane except for the te_base
       $('div.tripal_pane').each(function (i) {
-        $(this).prepend('<div class="tripal_pane-fieldset-close_button">'+
-              '<div id="tripal-pane-close-button" class="tripal-pane-button">'+
-                '<i class="fa fa-window-close-o fa-lg"></i>'+
-              '</div>'+
-            '</div>'
-           );
+        $(this).prepend(
+          '<div class="tripal_pane-fieldset-buttons">' +
+            '<div id="tripal-pane-close-button" class="tripal-pane-button">' +
+              '<i class="fa fa-window-close-o fa-lg"></i>' +
+            '</div>' +
+          '</div>'
+        );
         var id = '.tripal_pane-fieldset-' + $(this).attr('id');
       });
+
       // Hide the pane when the close button is clicked
-      $('.tripal_pane-fieldset-close_button').each(function (i) {
-        $(this).css('float', 'right');
-        $(this).css('cursor', 'pointer');
-        $(this).css('margin', '0px 5px');
+      $('#tripal-pane-close-button').each(function (i) {
         $(this).click(function () {
           var fs = $(this).parents('div.tripal_pane');
           if($(fs).hasClass('showTripalPane'))  {
@@ -37,8 +36,7 @@
             // If the user clicks on other TOC item, move its fieldset to the top 
             $(id + ' fieldset').removeClass('collapsed');
             $(id + ' fieldset .fieldset-wrapper').show();
-            console.log(prevObj);
-            console.log(id);
+
             // Highlight the fieldset instead of moving if it's already at the top
             if (prevObj.indexOf('group-tripal-pane-content-top') == 0) {
               $(id + ' fieldset').fadeTo(10, 0.3, function() {});

+ 1 - 1
tripal_ds/tripal_ds.info

@@ -5,7 +5,7 @@ project = tripal
 package = Tripal
 version = 7.x-3.0-beta3
 
-stylesheets[all][] = theme/css/tripaldsfeature.css
+stylesheets[all][] = theme/css/tripal_ds.css
 
 dependencies[] = ds
 dependencies[] = field_group

+ 21 - 19
tripal_ds/tripal_ds.module

@@ -6,7 +6,7 @@ require_once "includes/tripal_ds.field_group.inc";
 require_once "includes/tripal_ds.field_formatter.inc";
 
 function tripal_ds_init() {
-  drupal_add_css(drupal_get_path('module', 'tripal_ds') . '/theme/css/tripaldsfeature.css');
+  drupal_add_css(drupal_get_path('module', 'tripal_ds') . '/theme/css/tripal_ds.css');
   drupal_add_js(drupal_get_path('module', 'tripal_ds') . '/theme/js/tripal_ds.js');
 
   $theme_dir = url(drupal_get_path('module', 'tripal_ds') . '/theme');
@@ -420,23 +420,25 @@ function tripal_ds_update_ds_layout($bundle_name, $field_name, $tripal_pane_name
  * @param $context
  */
 function tripal_ds_field_display_alter(&$display, $context){
-  $field_name = $context['field']['field_name'];
-  $bundle = $context['entity']->bundle;
-  $bundle_info = tripal_load_bundle_entity(array('name' => $bundle));
-  $hide_variable = tripal_get_bundle_variable('hide_empty_field', $bundle_info->id, 'hide');
-
-  if ($field_name && ($hide_variable == 'hide')) {
-    $item = field_get_items('TripalEntity', $context['entity'], $field_name);
-    $field = field_info_field($field_name);
-    if ($item) {
-      if (tripal_field_is_empty($item[0], $field)) {
-        $parent_field_info = tripal_ds_find_field_group_parent($field_name, 'TripalEntity', $bundle, $context);
-        if (!empty($parent_field_info)) {
-          foreach ($parent_field_info as $parent_key => $parent_field){
-            // Stop the right rail element from rendering.
-            drupal_add_css('.' . $parent_field_info[$parent_key] . ' {display:none;}', 'inline');
-            // Hide any associated menu links.
-            drupal_add_css('#' . $parent_field_info[$parent_key] . ' {display:none;}', 'inline');
+  if ($context['entity_type'] == 'TripalEntity') {
+    $field_name = $context['field']['field_name'];
+    $bundle = $context['entity']->bundle;
+    $bundle_info = tripal_load_bundle_entity(array('name' => $bundle));
+    $hide_variable = tripal_get_bundle_variable('hide_empty_field', $bundle_info->id, 'hide');
+
+    if ($field_name && ($hide_variable == 'hide')) {
+      $item = field_get_items('TripalEntity', $context['entity'], $field_name);
+      $field = field_info_field($field_name);
+      if ($item) {
+        if (tripal_field_is_empty($item[0], $field)) {
+          $parent_field_info = tripal_ds_find_field_group_parent($field_name, 'TripalEntity', $bundle, $context);
+          if (!empty($parent_field_info)) {
+            foreach ($parent_field_info as $parent_key => $parent_field){
+              // Stop the right rail element from rendering.
+              drupal_add_css('.' . $parent_field_info[$parent_key] . ' {display:none;}', 'inline');
+              // Hide any associated menu links.
+              drupal_add_css('#' . $parent_field_info[$parent_key] . ' {display:none;}', 'inline');
+            }
           }
         }
       }
@@ -481,7 +483,7 @@ function tripal_ds_find_field_group_parent($field_name, $entity_type, $bundle, $
         foreach ($children as $kids => $child) {
           // Now check if each child if empty.
           $item = field_get_items('TripalEntity', $context['entity'], $child);
-          $field = field_info_fild($child);
+          $field = field_info_field($child);
           if(!tripal_field_is_empty($item[0], $field)){
             //If any of the fields are not empty do not add the parent.
             break 2;

+ 0 - 7
tripal_ws/tripal_ws.module

@@ -33,13 +33,6 @@ function tripal_ws_init() {
  */
 function tripal_ws_menu() {
 
-  // Web Services API callbacks.
-  $items['ws'] = array(
-    'title' => 'Tripal Web Services API',
-    'page callback' => 'tripal_ws_services',
-    'access arguments' => array('access content'),
-    'type' => MENU_CALLBACK,
-  );
   // Web Services API callbacks.
   $items['web-services'] = array(
     'title' => 'Tripal Web Services API',