Эх сурвалжийг харах

HUE-897 Ported Job Browser to Hue 3

Enrico Berti 12 жил өмнө
parent
commit
778992e

+ 116 - 102
apps/jobbrowser/src/jobbrowser/templates/attempt.mako

@@ -24,116 +24,130 @@ ${ commonheader(_('Task Attempt: %(attemptId)s') % dict(attemptId=attempt.attemp
 <link href="/jobbrowser/static/css/jobbrowser.css" rel="stylesheet">
 
 <div class="container-fluid">
-    <h1>${_('Task Attempt: %(attemptId)s - Job Browser') % dict(attemptId=attempt.attemptId_short)}</h1>
-    <div class="row-fluid">
-        <div class="span2">
-            <div class="well sidebar-nav">
-                <ul class="nav nav-list">
-                    <li class="nav-header">${_('Attempt ID')}</li>
-                    <li class="hellipsify">${attempt.attemptId_short}</li>
-                    <li class="nav-header">${_('Task')}</li>
-                    <li><a href="${url('jobbrowser.views.single_task', job=joblnk.jobId, taskid=taskid)}" class="hellipsify">${task.taskId_short}</a>
-                    </li>
-                    <li class="nav-header">${_('Job')}</li>
-                    <li><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}" class="hellipsify">${joblnk.jobId_short}</a></li>
-                    <li class="nav-header">${_('Status')}</li>
-                    <li>
-                        <%
-                            status = attempt.state.lower()
-                        %>
-                        % if status == 'running' or status == 'pending':
-                                <span class="label label-warning">${status}</span>
-                        % elif status == 'succeeded':
-                                <span class="label label-success">${status}</span>
-                        % else:
-                                <span class="label">${status}</span>
-                        % endif
-                    </li>
-                </ul>
-            </div>
-        </div>
+  <div class="row-fluid">
+    <div class="span2">
+      <div class="sidebar-nav">
+        <ul class="nav nav-list">
+          <li class="nav-header">${_('Attempt ID')}</li>
+          <li class="white hellipsify">${attempt.attemptId_short}</li>
+          <li class="nav-header">${_('Task')}</li>
+          <li><a href="${url('jobbrowser.views.single_task', job=joblnk.jobId, taskid=taskid)}"
+                 class="hellipsify">${task.taskId_short}</a>
+          </li>
+          <li class="nav-header">${_('Job')}</li>
+          <li><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}"
+                 class="hellipsify">${joblnk.jobId_short}</a></li>
+          <li class="nav-header">${_('Status')}</li>
+          <li class="white">
+            <%
+              status = attempt.state.lower()
+            %>
+            % if status == 'running' or status == 'pending':
+                <span class="label label-warning">${status}</span>
+            % elif status == 'succeeded':
+                <span class="label label-success">${status}</span>
+            % else:
+                <span class="label">${status}</span>
+            % endif
+          </li>
+        </ul>
+      </div>
+    </div>
 
-        <div class="span10">
-            <ul id="tabs" class="nav nav-tabs">
-                <li class="active"><a href="#metadata" data-toggle="tab">${_('Metadata')}</a></li>
-                <li><a href="#counters" data-toggle="tab">${_('Counters')}</a></li>
-                <li><a href="${ url('jobbrowser.views.single_task_attempt_logs', job=task.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }">${_('Logs')}</a></li>
-            </ul>
+    <div class="span10">
+      <div class="card" style="margin-top:0">
+        <h1 class="card-heading simple">${_('Task Attempt: %(attemptId)s - Job Browser') % dict(attemptId=attempt.attemptId_short)}</h1>
 
-            <div class="tab-content">
-                <div class="tab-pane active" id="metadata">
-                    <table id="metadataTable" class="table table-striped table-condensed">
-                        <thead>
-                        <tr>
-                            <th>${_('Name')}</th>
-                            <th>${_('Value')}</th>
-                        </tr>
-                        </thead>
-                        <tbody>
-                        <tr>
-                            <td>${_('Attempt ID')}</td>
-                            <td>${attempt.attemptId_short}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Task ID')}</td>
-                            <td><a href="${url('jobbrowser.views.single_task', job=joblnk.jobId, taskid=taskid)}" title="${_('View this task')}">${task.taskId_short}</a></td>
-                        </tr>
-                        <tr>
-                            <td>${_('Task Type')}</td>
-                            <td>${task.taskType}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('JobId')}</td>
-                            <td><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}" title="${_('View this job')}">${joblnk.jobId_short}</a></td>
-                        </tr>
-                        <tr>
-                            <td>${_('State')}</td>
-                            <td>${attempt.state}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Start Time')}</td>
-                            <td>${attempt.startTimeFormatted}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Finish Time')}</td>
-                            <td>${attempt.finishTimeFormatted}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Progress')}</td>
-                            <td>${"%d" % (attempt.progress * 100)}%</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Task Tracker')}</td>
-                            <td>
-                              % if attempt.is_mr2:
-                                ${ comps.get_container_link(status, attempt.taskTrackerId) }
-                              % else:
-                                <a href="/jobbrowser/trackers/${attempt.taskTrackerId}" class="task_tracker_link">${attempt.taskTrackerId}</a>
-                              % endif
-                            </td>
-                        </tr>
-                        <tr>
-                            <td>${_('Phase')}</td>
-                            <td>${attempt.phase}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Output Size')}</td>
-                            <td>${attempt.outputSize}</td>
-                        </tr>
-                        </tbody>
-                    </table>
-                </div>
+        <div class="card-body">
+          <p>
+          <ul id="tabs" class="nav nav-tabs">
+            <li class="active"><a href="#metadata" data-toggle="tab">${_('Metadata')}</a></li>
+            <li><a href="#counters" data-toggle="tab">${_('Counters')}</a></li>
+            <li><a
+                href="${ url('jobbrowser.views.single_task_attempt_logs', job=task.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }">${_('Logs')}</a>
+            </li>
+          </ul>
+
+          <div class="tab-content">
+            <div class="tab-pane active" id="metadata">
+              <table id="metadataTable" class="table table-condensed">
+                <thead>
+                <tr>
+                  <th>${_('Name')}</th>
+                  <th>${_('Value')}</th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr>
+                  <td>${_('Attempt ID')}</td>
+                  <td>${attempt.attemptId_short}</td>
+                </tr>
+                <tr>
+                  <td>${_('Task ID')}</td>
+                  <td><a href="${url('jobbrowser.views.single_task', job=joblnk.jobId, taskid=taskid)}"
+                         title="${_('View this task')}">${task.taskId_short}</a></td>
+                </tr>
+                <tr>
+                  <td>${_('Task Type')}</td>
+                  <td>${task.taskType}</td>
+                </tr>
+                <tr>
+                  <td>${_('JobId')}</td>
+                  <td><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}"
+                         title="${_('View this job')}">${joblnk.jobId_short}</a></td>
+                </tr>
+                <tr>
+                  <td>${_('State')}</td>
+                  <td>${attempt.state}</td>
+                </tr>
+                <tr>
+                  <td>${_('Start Time')}</td>
+                  <td>${attempt.startTimeFormatted}</td>
+                </tr>
+                <tr>
+                  <td>${_('Finish Time')}</td>
+                  <td>${attempt.finishTimeFormatted}</td>
+                </tr>
+                <tr>
+                  <td>${_('Progress')}</td>
+                  <td>${"%d" % (attempt.progress * 100)}%</td>
+                </tr>
+                <tr>
+                  <td>${_('Task Tracker')}</td>
+                  <td>
+                      % if attempt.is_mr2:
+                      ${ comps.get_container_link(status, attempt.taskTrackerId) }
+                      % else:
+                        <a href="/jobbrowser/trackers/${attempt.taskTrackerId}"
+                           class="task_tracker_link">${attempt.taskTrackerId}</a>
+                      % endif
+                  </td>
+                </tr>
+                <tr>
+                  <td>${_('Phase')}</td>
+                  <td>${attempt.phase}</td>
+                </tr>
+                <tr>
+                  <td>${_('Output Size')}</td>
+                  <td>${attempt.outputSize}</td>
+                </tr>
+                </tbody>
+              </table>
+            </div>
 
-                <div class="tab-pane" id="counters">
-                    % if task.is_mr2:
+            <div class="tab-pane" id="counters">
+                % if task.is_mr2:
                         ${ comps.task_counters_mr2(task.counters) }
-                    % else:
+                % else:
                         ${ comps.task_counters(task.counters) }
-                    % endif
-                </div>
+                % endif
             </div>
+          </div>
+          </p>
         </div>
+      </div>
     </div>
+  </div>
 </div>
 
 <script src="/jobbrowser/static/js/utils.js" type="text/javascript" charset="utf-8"></script>

+ 88 - 84
apps/jobbrowser/src/jobbrowser/templates/attempt_logs.mako

@@ -21,99 +21,103 @@
 
 ${ commonheader(_('Task Attempt: %(attemptId)s') % dict(attemptId=attempt.attemptId_short), "jobbrowser", user) | n,unicode }
 <div class="container-fluid">
-    <h1>${_('Task Attempt: %(attemptId)s - Job Browser') % dict(attemptId=attempt.attemptId_short)}</h1>
-    <div class="row-fluid">
-        <div class="span2">
-            <div class="well sidebar-nav">
-                <ul class="nav nav-list">
-                    <li class="nav-header">${_('Attempt ID')}</li>
-                    <li>${attempt.attemptId_short}</li>
-                    <li class="nav-header">${_('Task')}</li>
-                    <li><a href="${url('jobbrowser.views.single_task', job=joblnk.jobId, taskid=taskid)}" title="${_('View this task')}">${task.taskId_short}</a>
-                    </li>
-                    <li class="nav-header">${_('Job')}</li>
-                    <li><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}" title="${_('View this job')}">${joblnk.jobId_short}</a></li>
-                    <li class="nav-header">${_('Status')}</li>
-                    <li>
-                        <%
-                            status = attempt.state.lower()
-                        %>
-                        % if status == 'running' or status == 'pending':
-                                <span class="label label-warning">${status}</span>
-                        % elif status == 'succeeded':
-                                <span class="label label-success">${status}</span>
-                        % else:
-                                <span class="label">${status}</span>
-                        % endif
-                    </li>
-                </ul>
-            </div>
-        </div>
+  <div class="row-fluid">
+    <div class="span2">
+      <div class="sidebar-nav">
+        <ul class="nav nav-list">
+          <li class="nav-header">${_('Attempt ID')}</li>
+          <li class="white">${attempt.attemptId_short}</li>
+          <li class="nav-header">${_('Task')}</li>
+          <li><a href="${url('jobbrowser.views.single_task', job=joblnk.jobId, taskid=taskid)}" title="${_('View this task')}">${task.taskId_short}</a>
+          </li>
+          <li class="nav-header">${_('Job')}</li>
+          <li><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}" title="${_('View this job')}">${joblnk.jobId_short}</a></li>
+          <li class="nav-header">${_('Status')}</li>
+          <li class="white">
+              <%
+                  status = attempt.state.lower()
+              %>
+              % if status == 'running' or status == 'pending':
+                      <span class="label label-warning">${status}</span>
+              % elif status == 'succeeded':
+                      <span class="label label-success">${status}</span>
+              % else:
+                      <span class="label">${status}</span>
+              % endif
+          </li>
+        </ul>
+      </div>
+    </div>
 
-        <div class="span10">
+    <div class="span10">
+      <div class="card" style="margin-top: 0">
+        <h1 class="card-heading simple">${_('Task Attempt: %(attemptId)s - Job Browser') % dict(attemptId=attempt.attemptId_short)}</h1>
+        <div class="card-body">
+          <p>
             <ul class="nav nav-tabs">
-                <li><a href="${ url('jobbrowser.views.single_task_attempt', job=joblnk.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }#tmetadata">${_('Metadata')}</a></li>
-                <li><a href="${ url('jobbrowser.views.single_task_attempt', job=joblnk.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }#tcounters">${_('Counters')}</a></li>
-                <li class="active"><a href="#logs" data-toggle="tab">${_('Logs')}</a></li>
+              <li><a href="${ url('jobbrowser.views.single_task_attempt', job=joblnk.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }#tmetadata">${_('Metadata')}</a></li>
+              <li><a href="${ url('jobbrowser.views.single_task_attempt', job=joblnk.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }#tcounters">${_('Counters')}</a></li>
+              <li class="active"><a href="#logs" data-toggle="tab">${_('Logs')}</a></li>
             </ul>
-
             <div class="tab-content">
-                <div class="tab-pane active" id="logs">
-                  <%def name="format_log(raw)">
-                    ## have to remove any indentation here or it breaks inside the pre tags
-                    % for line in raw.split('\n'):
-${ line | unicode,trim }
-                    % endfor
-                  </%def>
-                  <%
-                      log_diagnostic = logs[0]
-                      log_stdout = logs[1]
-                      log_stderr = logs[2]
-                      log_syslog = logs[3]
-                  %>
-                  <div class="tabbable">
-                    <ul class="nav nav-pills">
-                      <li class="${ first_log_tab == 0 and 'active' or '' }"><a href="#logsDiagnostic" data-toggle="tab">${_('task diagnostic log')}</a></li>
-                      <li class="${ first_log_tab == 1 and 'active' or '' }"><a href="#logsStdOut" data-toggle="tab">${_('stdout')}</a></li>
-                      <li class="${ first_log_tab == 2 and 'active' or '' }"><a href="#logsStdErr" data-toggle="tab">${_('stderr')}</a></li>
-                      <li class="${ first_log_tab == 3 and 'active' or '' }"><a href="#logsSysLog" data-toggle="tab">${_('syslog')}</a></li>
-                    </ul>
-                    <div class="tab-content">
-                      <div class="tab-pane ${ first_log_tab == 0 and 'active' or '' }" id="logsDiagnostic">
-                          % if not log_diagnostic:
-                            <pre>-- empty --</pre>
-                          % else:
-                            <pre>${format_log(log_diagnostic)}</pre>
-                          % endif
-                      </div>
-                      <div class="tab-pane ${ first_log_tab == 1 and 'active' or '' }" id="logsStdOut">
-                          % if not log_stdout:
-                            <pre>-- empty --</pre>
-                          % else:
-                            <pre>${format_log(log_stdout)}</pre>
-                          % endif
-                      </div>
-                      <div class="tab-pane ${ first_log_tab == 2 and 'active' or '' }" id="logsStdErr">
-                          % if not log_stderr:
-                            <pre>-- empty --</pre>
-                          % else:
-                            <pre>${format_log(log_stderr)}</pre>
-                          % endif
-                      </div>
-                      <div class="tab-pane ${ first_log_tab == 3 and 'active' or '' }" id="logsSysLog">
-                          % if not log_syslog:
-                            <pre>-- empty --</pre>
-                          % else:
-                            <pre>${format_log(log_syslog)}</pre>
-                          % endif
-                      </div>
-                    </div>
+              <div class="tab-pane active" id="logs">
+              <%def name="format_log(raw)">
+                ## have to remove any indentation here or it breaks inside the pre tags
+                % for line in raw.split('\n'):
+  ${ line | unicode,trim }
+                % endfor
+              </%def>
+              <%
+                  log_diagnostic = logs[0]
+                  log_stdout = logs[1]
+                  log_stderr = logs[2]
+                  log_syslog = logs[3]
+              %>
+              <div class="tabbable">
+                <ul class="nav nav-pills">
+                  <li class="${ first_log_tab == 0 and 'active' or '' }"><a href="#logsDiagnostic" data-toggle="tab">${_('task diagnostic log')}</a></li>
+                  <li class="${ first_log_tab == 1 and 'active' or '' }"><a href="#logsStdOut" data-toggle="tab">${_('stdout')}</a></li>
+                  <li class="${ first_log_tab == 2 and 'active' or '' }"><a href="#logsStdErr" data-toggle="tab">${_('stderr')}</a></li>
+                  <li class="${ first_log_tab == 3 and 'active' or '' }"><a href="#logsSysLog" data-toggle="tab">${_('syslog')}</a></li>
+                </ul>
+                <div class="tab-content">
+                  <div class="tab-pane ${ first_log_tab == 0 and 'active' or '' }" id="logsDiagnostic">
+                      % if not log_diagnostic:
+                        <pre>-- empty --</pre>
+                      % else:
+                        <pre>${format_log(log_diagnostic)}</pre>
+                      % endif
+                  </div>
+                  <div class="tab-pane ${ first_log_tab == 1 and 'active' or '' }" id="logsStdOut">
+                      % if not log_stdout:
+                        <pre>-- empty --</pre>
+                      % else:
+                        <pre>${format_log(log_stdout)}</pre>
+                      % endif
+                  </div>
+                  <div class="tab-pane ${ first_log_tab == 2 and 'active' or '' }" id="logsStdErr">
+                      % if not log_stderr:
+                        <pre>-- empty --</pre>
+                      % else:
+                        <pre>${format_log(log_stderr)}</pre>
+                      % endif
+                  </div>
+                  <div class="tab-pane ${ first_log_tab == 3 and 'active' or '' }" id="logsSysLog">
+                      % if not log_syslog:
+                        <pre>-- empty --</pre>
+                      % else:
+                        <pre>${format_log(log_syslog)}</pre>
+                      % endif
                   </div>
-
                 </div>
+              </div>
+            </div>
             </div>
+          </p>
         </div>
+      </div>
     </div>
+  </div>
 </div>
 
 <script src="/jobbrowser/static/js/utils.js" type="text/javascript" charset="utf-8"></script>

+ 191 - 205
apps/jobbrowser/src/jobbrowser/templates/job.mako

@@ -27,7 +27,7 @@
 %>
 
 <%def name="task_table(dom_id, tasks)">
-    <table id="${ dom_id }" class="taskTable table table-striped table-condensed">
+    <table id="${ dom_id }" class="taskTable table table-condensed">
         <thead>
         <tr>
             <th>${_('Logs')}</th>
@@ -106,225 +106,211 @@ ${ commonheader(_('Job: %(jobId)s') % dict(jobId=job.jobId_short), "jobbrowser",
 </style>
 
 <div class="container-fluid">
-    <h1>${_('Job: %(jobId)s - Job Browser') % dict(jobId=job.jobId_short)}</h1>
-    <div class="row-fluid">
-        <div class="span2">
-            <div class="well sidebar-nav">
-                <ul class="nav nav-list">
-                    <li class="nav-header">${_('Job ID')}</li>
-                    <li class="hellipsify">${job.jobId_short}</li>
-                    <li class="nav-header">${_('User')}</li>
-                    <li>${job.user}</li>
-                    <li class="nav-header">${_('Status')}</li>
-                    <li id="jobStatus">&nbsp;</li>
-                    <li class="nav-header">${_('Logs')}</li>
-                    <li><a href="${ url('jobbrowser.views.job_single_logs', job=job.jobId) }"><i class="icon-tasks"></i> ${_('Logs')}</a></li>
-
-                    % if not job.is_retired:
-                        <li class="nav-header">${_('Maps:')}</li>
-                        <li id="jobMaps">&nbsp;</li>
-                        <li class="nav-header">${_('Reduces:')}</li>
-                        <li id="jobReduces">&nbsp;</li>
-                    % endif
-
-                    <li class="nav-header">${_('Duration:')}</li>
-                    <li id="jobDuration">&nbsp;</li>
-
-                    <%
-                        output_dir = job.conf_keys.get('mapredOutputDir', "")
-                        location_url = location_to_url(output_dir)
-                        basename = os.path.basename(output_dir)
-                        dir_name = basename.split('/')[-1]
-                    %>
-                    % if dir_name != '':
-                        <li class="nav-header">${_('Output')}</li>
-                        <li>
-                        <%
-                            output_dir = job.conf_keys.get('mapredOutputDir', "")
-                            location_url = location_to_url(output_dir)
-                            basename = os.path.basename(output_dir)
-                            dir_name = basename.split('/')[-1]
-                        %>
-                        % if location_url != None:
-                            <a href="${location_url}" title="${output_dir}">
-                        % endif
-                        <i class="icon-folder-open"></i> ${dir_name}
-                        % if location_url != None:
-                            </a>
-                        % endif
-                        </li>
-                    % endif
-
-                    <li class="nav-header killJob">${_('Actions')}</li>
-                    <li id="killJobContainer" class="killJob"></li>
-                </ul>
-            </div>
-        </div>
-        <div class="span10">
-            <ul class="nav nav-tabs">
+  <div class="row-fluid">
+    <div class="span2">
+      <div class="sidebar-nav">
+        <ul class="nav nav-list">
+          <li class="nav-header">${_('Job ID')}</li>
+          <li class="white hellipsify">${job.jobId_short}</li>
+          <li class="nav-header">${_('User')}</li>
+          <li class="white">${job.user}</li>
+          <li class="nav-header">${_('Status')}</li>
+          <li class="white" id="jobStatus">&nbsp;</li>
+          <li class="nav-header">${_('Logs')}</li>
+          <li><a href="${ url('jobbrowser.views.job_single_logs', job=job.jobId) }"><i class="icon-tasks"></i> ${_('Logs')}</a></li>
+          % if not job.is_retired:
+          <li class="nav-header">${_('Maps:')}</li>
+          <li class="white" id="jobMaps">&nbsp;</li>
+          <li class="nav-header">${_('Reduces:')}</li>
+          <li class="white" id="jobReduces">&nbsp;</li>
+          % endif
+          <li class="nav-header">${_('Duration:')}</li>
+          <li class="white" id="jobDuration">&nbsp;</li>
+          <%
+              output_dir = job.conf_keys.get('mapredOutputDir', "")
+              location_url = location_to_url(output_dir)
+              basename = os.path.basename(output_dir)
+              dir_name = basename.split('/')[-1]
+          %>
+          % if dir_name != '':
+          <li class="nav-header">${_('Output')}</li>
+          <li class="white">
+            % if location_url != None:
+            <a href="${location_url}" title="${output_dir}">
+            % endif
+            <i class="icon-folder-open"></i> ${dir_name}
+            % if location_url != None:
+            </a>
+            % endif
+          </li>
+          % endif
+          <li class="nav-header killJob">${_('Actions')}</li>
+          <li id="killJobContainer" class="white killJob"></li>
+        </ul>
+      </div>
+    </div>
+    <div class="span10">
+      <div class="card" style="margin-top:0">
+        <h1 class="card-heading simple">${_('Job: %(jobId)s - Job Browser') % dict(jobId=job.jobId_short)}</h1>
+          <div class="card-body">
+            <p>
+              <ul class="nav nav-tabs">
                 % if job.is_mr2:
-                    <li class="active"><a href="#attempts" data-toggle="tab">${_('Attempts')}</a></li>
-                    <li><a href="#tasks" data-toggle="tab">${_('Tasks')}</a></li>
+                <li class="active"><a href="#attempts" data-toggle="tab">${_('Attempts')}</a></li>
+                <li><a href="#tasks" data-toggle="tab">${_('Tasks')}</a></li>
                 % else:
-                    <li class="active"><a href="#tasks" data-toggle="tab">${_('Tasks')}</a></li>
+                <li class="active"><a href="#tasks" data-toggle="tab">${_('Tasks')}</a></li>
                 % endif
                 <li><a href="#metadata" data-toggle="tab">${_('Metadata')}</a></li>
                 % if not job.is_retired:
-                    <li><a href="#counters" data-toggle="tab">${_('Counters')}</a></li>
+                <li><a href="#counters" data-toggle="tab">${_('Counters')}</a></li>
                 % endif
-            </ul>
+              </ul>
 
-            <div class="tab-content">
+              <div class="tab-content">
                 % if job.is_mr2:
-                    <div class="tab-pane active" id="attempts">
-                        <table id="jobAttemptTable" class="table table-striped table-condensed">
-                            <thead>
-                                <th width="20">${_('Logs')}</th>
-                                <th width="30">${_('Id')}</th>
-                                <th>${_('Container')}</th>
-                            </thead>
-                            <tbody>
-                                % for attempt in job.job_attempts['jobAttempt']:
-                                    <tr>
-                                        <td>
-                                            <a href="${ url('jobbrowser.views.job_attempt_logs', job=job.jobId, attempt_index=loop.index) }"
-                                                data-row-selector="true">
-                                                <i class="icon-tasks"></i>
-                                            </a>
-                                        </td>
-                                        <td>${ attempt['id'] }</td>
-                                        <td>${ comps.get_container_link(job.status, attempt['containerId']) }</td>
-                                    </tr>
-                                % endfor
-                            </tbody>
-                        </table>
-                    </div>
-                    <div class="tab-pane" id="tasks">
+                <div class="tab-pane active" id="attempts">
+                  <table id="jobAttemptTable" class="table table-condensed">
+                    <thead>
+                      <th width="20">${_('Logs')}</th>
+                      <th width="30">${_('Id')}</th>
+                      <th>${_('Container')}</th>
+                    </thead>
+                    <tbody>
+                      % for attempt in job.job_attempts['jobAttempt']:
+                      <tr>
+                        <td>
+                          <a href="${ url('jobbrowser.views.job_attempt_logs', job=job.jobId, attempt_index=loop.index) }" data-row-selector="true">
+                            <i class="icon-tasks"></i>
+                          </a>
+                        </td>
+                        <td>${ attempt['id'] }</td>
+                        <td>${ comps.get_container_link(job.status, attempt['containerId']) }</td>
+                      </tr>
+                      % endfor
+                    </tbody>
+                  </table>
+                </div>
+                <div class="tab-pane" id="tasks">
                 % else:
-                    <div class="tab-pane active" id="tasks">
+                <div class="tab-pane active" id="tasks">
                 % endif
-                    % if job.is_retired and not job.is_mr2:
-                       ${ _('This jobs is ')} <span class="label label-warning">${ _('retired') }</span> ${ _(' and so has little information available.') }
-                       <br/>
-                       <br/>
-                    % else:
-                        <div id="failedTasksContainer">
-                            <a style="float:right;margin-right:10px;margin-top: 10px" href="${url('jobbrowser.views.tasks', job=job.jobId)}?taskstate=failed">${_('View All Failed Tasks')} &raquo;</a>
-                            <h3>
-                                ${_('Failed Tasks')}
-                            </h3>
-                            <div>
-                            ${task_table('failedTasks', failed_tasks)}
-                            </div>
-                        </div>
-                        <div>
-                            <a style="float:right;margin-right:10px;margin-top: 10px" href="${url('jobbrowser.views.tasks', job=job.jobId)}">${_('View All Tasks')} &raquo;</a>
-                            <h3>
-                                ${_('Recent Tasks')}
-                            </h3>
-                            <div>
-                                ${task_table('recentTasks', recent_tasks)}
-                            </div>
-                        </div>
-                    % endif
-                </div>
-                <div id="metadata" class="tab-pane">
-                    <div class="well hueWell">
-                        <form class="form-search">
-                            <input type="text" id="metadataFilter" class="input-xlarge search-query" placeholder="${_('Text Filter')}">
-                        </form>
+                % if job.is_retired and not job.is_mr2:
+                  ${ _('This jobs is ')} <span class="label label-warning">${ _('retired') }</span> ${ _(' and so has little information available.') }
+                  <br/>
+                  <br/>
+                % else:
+                  <div id="failedTasksContainer">
+                    <a style="float:right;margin-right:10px;margin-top: 10px" href="${url('jobbrowser.views.tasks', job=job.jobId)}?taskstate=failed">${_('View All Failed Tasks')} &raquo;</a>
+                    <h3>${_('Failed Tasks')}</h3>
+                    <div>
+                      ${task_table('failedTasks', failed_tasks)}
                     </div>
-                    <table id="metadataTable" class="table table-striped table-condensed">
-                        <thead>
-                            <th>${_('Name')}</th>
-                            <th>${_('Value')}</th>
-                        </thead>
-                        <tbody>
-                        <tr>
-                            <td>${_('ID')}</td>
-                            <td>${job.jobId_short}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('User')}</td>
-                            <td>${job.user}</td>
-                        </tr>
-                        % if not job.is_retired:
-                        <tr>
-                            <td>${_('Maps')}</td>
-                            <td>${job.finishedMaps} of ${job.desiredMaps}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Reduces')}</td>
-                            <td>${job.finishedReduces} of ${job.desiredReduces}</td>
-                        </tr>
-                        % endif
-                        <tr>
-                            <td>${_('Started')}</td>
-                            <td>${job.startTimeFormatted}</td>
-                        </tr>
-                        % if not job.is_retired:
-                        <tr>
-                            <td>${_('Ended')}</td>
-                            <td>${job.finishTimeFormatted}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Duration')}</td>
-                            <td>${job.duration}</td>
-                        </tr>
-                        % endif
-                        <tr>
-                            <td>${_('Status')}</td>
-                            <td>${job.status}</td>
-                        </tr>
-
-                        ${rows_for_conf_vars(job.conf_keys)}
-
-                        </tbody>
-                    </table>
-                    <h3>${_('Raw configuration:')}</h3>
-                    <table id="rawConfigurationTable" class="table table-striped table-condensed">
-                        <thead>
-                        <th>${_('Name')}</th>
-                        <th>${_('Value')}</th>
-                        </thead>
-                        <tbody>
-                          % if job.is_mr2:
-                            % for line in job.full_job_conf['property']:
-                                <tr>
-                                    <td width="20%">${ line['name'] }</td>
-                                    <td>
-                                        <div class="wordbreak">
-                                        ${ line['value'] }
-                                        </div>
-                                    </td>
-                                </tr>
-                            % endfor
-                          % else:
-                            % for key, value in sorted(job.full_job_conf.items()):
-                                <tr>
-                                    <td width="20%">${key}</td>
-                                    <td>
-                                        <div class="wordbreak">
-                                        ${value}
-                                        </div>
-                                    </td>
-                                </tr>
-                            % endfor
-                          % endif
-                        </tbody>
-                    </table>
-
+                  </div>
+                  <div>
+                  <a style="float:right;margin-right:10px;margin-top: 10px" href="${url('jobbrowser.views.tasks', job=job.jobId)}">${_('View All Tasks')} &raquo;</a>
+                  <h3>${_('Recent Tasks')}</h3>
+                  <div>
+                    ${task_table('recentTasks', recent_tasks)}
+                  </div>
                 </div>
-                <div id="counters" class="tab-pane">
-                    % if job.is_mr2:
-                      ${ comps.job_counters_mr2(job.counters) }
-                    % else:
-                      ${ comps.job_counters(job.counters) }
+                % endif
+              </div>
+              <div id="metadata" class="tab-pane">
+                <form class="form-search">
+                  <input type="text" id="metadataFilter" class="input-xlarge search-query" placeholder="${_('Text Filter')}">
+                </form>
+                <table id="metadataTable" class="table table-condensed">
+                  <thead>
+                    <th>${_('Name')}</th>
+                    <th>${_('Value')}</th>
+                  </thead>
+                  <tbody>
+                    <tr>
+                      <td>${_('ID')}</td>
+                      <td>${job.jobId_short}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('User')}</td>
+                      <td>${job.user}</td>
+                    </tr>
+                    % if not job.is_retired:
+                    <tr>
+                      <td>${_('Maps')}</td>
+                      <td>${job.finishedMaps} of ${job.desiredMaps}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('Reduces')}</td>
+                      <td>${job.finishedReduces} of ${job.desiredReduces}</td>
+                    </tr>
                     % endif
-                </div>
+                    <tr>
+                      <td>${_('Started')}</td>
+                      <td>${job.startTimeFormatted}</td>
+                    </tr>
+                    % if not job.is_retired:
+                    <tr>
+                      <td>${_('Ended')}</td>
+                      <td>${job.finishTimeFormatted}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('Duration')}</td>
+                      <td>${job.duration}</td>
+                    </tr>
+                    % endif
+                    <tr>
+                      <td>${_('Status')}</td>
+                      <td>${job.status}</td>
+                    </tr>
+                    ${rows_for_conf_vars(job.conf_keys)}
+                  </tbody>
+                </table>
+                <h3>${_('Raw configuration:')}</h3>
+                <table id="rawConfigurationTable" class="table table-condensed">
+                  <thead>
+                    <th>${_('Name')}</th>
+                    <th>${_('Value')}</th>
+                  </thead>
+                  <tbody>
+                  % if job.is_mr2:
+                    % for line in job.full_job_conf['property']:
+                    <tr>
+                      <td width="20%">${ line['name'] }</td>
+                      <td>
+                        <div class="wordbreak">
+                          ${ line['value'] }
+                        </div>
+                      </td>
+                    </tr>
+                    % endfor
+                  % else:
+                    % for key, value in sorted(job.full_job_conf.items()):
+                    <tr>
+                      <td width="20%">${key}</td>
+                      <td>
+                        <div class="wordbreak">
+                          ${value}
+                        </div>
+                      </td>
+                    </tr>
+                    % endfor
+                  % endif
+                  </tbody>
+                </table>
+              </div>
+              <div id="counters" class="tab-pane">
+                % if job.is_mr2:
+                ${ comps.job_counters_mr2(job.counters) }
+                % else:
+                ${ comps.job_counters(job.counters) }
+                % endif
+              </div>
             </div>
-        </div>
+          </div>
+        </p>
+      </div>
     </div>
+  </div>
 </div>
 
 

+ 41 - 36
apps/jobbrowser/src/jobbrowser/templates/job_attempt_logs.mako

@@ -23,50 +23,55 @@
 ${ commonheader(_('Job Attempt: %(attempt_index)s') % {'attempt_index': attempt_index}, "jobbrowser", user) | n,unicode }
 
 <div class="container-fluid">
-    <h1>
-        ${ _('Job Browser') } -
-        ${ _('Job') } <a href="${url('jobbrowser.views.single_job', job=job.jobId)}" title="${_('View this job')}">${ job.jobId_short }</a>
-        ${ _('Attempt: %(attempt_index)s') % {'attempt_index': attempt_index} }
-    </h1>
-    <br/>
-    <div class="row-fluid">
-        <div class="span2">
-            <div class="well sidebar-nav">
-                <ul class="nav nav-list">
-                    <li class="nav-header">${ _('Attempt ID') }</li>
-                    <li>${ attempt_index }</li>
-                </ul>
-            </div>
-        </div>
+  <div class="row-fluid">
+    <div class="span2">
+      <div class="sidebar-nav">
+        <ul class="nav nav-list">
+          <li class="nav-header">${ _('Attempt ID') }</li>
+          <li class="white">${ attempt_index }</li>
+        </ul>
+      </div>
+    </div>
 
-        <div class="span10">
+    <div class="span10">
+      <div class="card">
+        <h1 class="card-heading simple">
+          ${ _('Job Browser') } -
+          ${ _('Job') } <a href="${url('jobbrowser.views.single_job', job=job.jobId)}" title="${_('View this job')}">${ job.jobId_short }</a>
+          ${ _('Attempt: %(attempt_index)s') % {'attempt_index': attempt_index} }
+        </h1>
+        <div class="card-body">
+          <p>
             <ul class="nav nav-pills">
-                <li class="active"><a href="#stdout" data-toggle="tab">${_('stdout')}</a></li>
-                <li><a href="#stderr" data-toggle="tab">${_('stderr')}</a></li>
-                <li><a href="#syslog" data-toggle="tab">${_('syslog')}</a></li>
+              <li class="active"><a href="#stdout" data-toggle="tab">${_('stdout')}</a></li>
+              <li><a href="#stderr" data-toggle="tab">${_('stderr')}</a></li>
+              <li><a href="#syslog" data-toggle="tab">${_('syslog')}</a></li>
             </ul>
 
             <div class="tab-content">
-                <div class="tab-pane active" id="stdout">
-                    <pre id="stdout-container">
-                        ${_('Loading...')} <img src="/static/art/login-spinner.gif">
-                    </pre>
-                </div>
-
-                <div class="tab-pane" id="stderr">
-                    <pre id="stderr-container">
-                        ${_('Loading...')} <img src="/static/art/login-spinner.gif">
-                    </pre>
-                </div>
-
-                <div class="tab-pane" id="syslog">
-                    <pre id="syslog-container">
-                        ${_('Loading...')} <img src="/static/art/login-spinner.gif">
-                    </pre>
-                </div>
+              <div class="tab-pane active" id="stdout">
+                <pre id="stdout-container">
+                  ${_('Loading...')} <img src="/static/art/login-spinner.gif">
+                </pre>
+              </div>
+
+              <div class="tab-pane" id="stderr">
+                <pre id="stderr-container">
+                  ${_('Loading...')} <img src="/static/art/login-spinner.gif">
+                </pre>
+              </div>
+
+              <div class="tab-pane" id="syslog">
+                <pre id="syslog-container">
+                  ${_('Loading...')} <img src="/static/art/login-spinner.gif">
+                </pre>
+              </div>
             </div>
+          </p>
         </div>
+      </div>
     </div>
+  </div>
 </div>
 
 <script src="/jobbrowser/static/js/utils.js" type="text/javascript" charset="utf-8"></script>

+ 4 - 4
apps/jobbrowser/src/jobbrowser/templates/jobbrowser_components.mako

@@ -23,7 +23,7 @@
     %>
     % for group in counters.groups:
         <h3>${format_counter_name(group.displayName)}</h3>
-        <table class="taskCountersTable table table-striped table-condensed">
+        <table class="taskCountersTable table table-condensed">
             <thead>
             <tr>
                 <th>${_('Counter Name')}</th>
@@ -49,7 +49,7 @@
     %>
     % for group in counters.get('taskCounterGroup', []):
         <h3>${ format_counter_name(group['counterGroupName']) }</h3>
-        <table class="taskCountersTable table table-striped table-condensed">
+        <table class="taskCountersTable table table-condensed">
             <thead>
             <tr>
                 <th>${_('Counter Name')}</th>
@@ -75,7 +75,7 @@
     %>
     % for group in counters.itervalues():
         <h3>${format_counter_name(group['displayName'])}</h3>
-        <table class="jobCountersTable table table-striped table-condensed">
+        <table class="jobCountersTable table table-condensed">
             <thead>
             <tr>
                 <th>${_('Name')}</th>
@@ -116,7 +116,7 @@
     %>
     % for counter_group in counters.get('counterGroup', []):
         <h3>${ format_counter_name(counter_group['counterGroupName']) }</h3>
-        <table class="jobCountersTable table table-striped table-condensed">
+        <table class="jobCountersTable table table-condensed">
             <thead>
             <tr>
                 <th>${_('Name')}</th>

+ 5 - 3
apps/jobbrowser/src/jobbrowser/templates/jobs.mako

@@ -26,7 +26,8 @@ ${ commonheader(None, "jobbrowser", user) | n,unicode }
 <link href="/jobbrowser/static/css/jobbrowser.css" rel="stylesheet">
 
 <div class="container-fluid">
-  <h1>${_('Job Browser')}</h1>
+  <div class="card">
+  <h1 class="card-heading simple">${_('Job Browser')}</h1>
 
   <%actionbar:render>
     <%def name="search()">
@@ -55,7 +56,7 @@ ${ commonheader(None, "jobbrowser", user) | n,unicode }
 
   <div id="noJobs" class="alert"><i class="icon-warning-sign"></i>&nbsp; ${_('There are no jobs that match your search criteria.')}</div>
 
-  <table id="jobsTable" class="datatables table table-striped table-condensed">
+  <table id="jobsTable" class="datatables table table-condensed">
     <thead>
     <tr>
       <th>${_('Logs')}</th>
@@ -75,6 +76,7 @@ ${ commonheader(None, "jobbrowser", user) | n,unicode }
     <tbody>
     </tbody>
   </table>
+    </div>
 </div>
 
 <div id="killModal" class="modal hide fade">
@@ -103,7 +105,7 @@ ${ commonheader(None, "jobbrowser", user) | n,unicode }
       "iDisplayLength": 30,
       "bLengthChange": false,
       "bAutoWidth": false,
-      "sDom": "<'row'r>t<'row'<'span6'i><''p>>",
+      "sDom": "<'row'r>t<'row-fluid'<'dt-pages'p><'dt-records'i>>",
       "aaSorting": [
         [1, "desc"]
       ],

+ 131 - 124
apps/jobbrowser/src/jobbrowser/templates/task.mako

@@ -24,137 +24,144 @@ ${ commonheader(_('Job Task: %(taskId)s') % dict(taskId=task.taskId_short), "job
 <link href="/jobbrowser/static/css/jobbrowser.css" rel="stylesheet">
 
 <div class="container-fluid">
-    <h1>${_('Job Task: %(taskId)s - Job Browser') % dict(taskId=task.taskId_short)}</h1>
-    <div class="row-fluid">
-        <div class="span2">
-            <div class="well sidebar-nav">
-                <ul class="nav nav-list">
-                    <li class="nav-header">${_('Task ID')}</li>
-                    <li class="hellipsify">${task.taskId_short}</li>
-                    <li class="nav-header">${_('Job')}</li>
-                    <li><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}" class="hellipsify">${joblnk.jobId_short}</a></li>
-                    <li class="nav-header">${_('Status')}</li>
-                    <li>
-                            % if task.state.lower() == 'running' or task.state.lower() == 'pending':
-                                <span class="label label-warning">${task.state.lower()}</span>
-                            % elif task.state.lower() == 'succeeded':
-                                <span class="label label-success">${task.state.lower()}</span>
-                            % else:
-                                <span class="label">${task.state.lower()}</span>
-                            % endif
-                    </li>
-                </ul>
-            </div>
-        </div>
-        <div class="span10">
+  <div class="row-fluid">
+    <div class="span2">
+      <div class="sidebar-nav">
+        <ul class="nav nav-list">
+          <li class="nav-header">${_('Task ID')}</li>
+          <li class="white hellipsify">${task.taskId_short}</li>
+          <li class="nav-header">${_('Job')}</li>
+          <li><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}" class="hellipsify">${joblnk.jobId_short}</a></li>
+          <li class="nav-header">${_('Status')}</li>
+          <li class="white">
+            % if task.state.lower() == 'running' or task.state.lower() == 'pending':
+                <span class="label label-warning">${task.state.lower()}</span>
+            % elif task.state.lower() == 'succeeded':
+                <span class="label label-success">${task.state.lower()}</span>
+            % else:
+                <span class="label">${task.state.lower()}</span>
+            % endif
+          </li>
+      </ul>
+    </div>
+  </div>
+    <div class="span10">
+      <div class="card" style="margin-top:0">
+        <h1 class="card-heading simple">${_('Job Task: %(taskId)s - Job Browser') % dict(taskId=task.taskId_short)}</h1>
+        <div class="card-body">
+          <p>
             <ul class="nav nav-tabs">
-                <li class="active"><a href="#attempts" data-toggle="tab">${_('Attempts')}</a></li>
-                <li><a href="#metadata" data-toggle="tab">${_('Metadata')}</a></li>
-                <li><a href="#counters" data-toggle="tab">${_('Counters')}</a></li>
+              <li class="active"><a href="#attempts" data-toggle="tab">${_('Attempts')}</a></li>
+              <li><a href="#metadata" data-toggle="tab">${_('Metadata')}</a></li>
+              <li><a href="#counters" data-toggle="tab">${_('Counters')}</a></li>
             </ul>
 
             <div class="tab-content">
-                <div class="tab-pane active" id="attempts">
-                    <table id="attemptsTable" class="table table-striped table-condensed">
-                        <thead>
-                        <tr>
-                            <th>${_('Logs')}</th>
-                            <th>${_('Attempt ID')}</th>
-                            <th>${_('Progress')}</th>
-                            <th>${_('State')}</th>
-                            <th>${_('Task Tracker')}</th>
-                            <th>${_('Start Time')}</th>
-                            <th>${_('End Time')}</th>
-                            <th>${_('Output Size')}</th>
-                            <th>${_('Phase')}</th>
-                            <th>${_('Shuffle Finish')}</th>
-                            <th>${_('Sort Finish')}</th>
-                            <th>${_('Map Finish')}</th>
-                        </tr>
-                        </thead>
-                        <tbody>
-                                % for attempt in task.attempts:
-                                <tr>
-                                    <td data-row-selector-exclude="true"><a href="${ url('jobbrowser.views.single_task_attempt_logs', job=joblnk.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }" data-row-selector-exclude="true"><i class="icon-tasks"></i></a></td>
-                                    <td><a title="${_('View this attempt')}"
-                                           href="${ url('jobbrowser.views.single_task_attempt', job=joblnk.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }" data-row-selector="true">${attempt.attemptId_short}</a></td>
-                                    <td>${"%d" % (attempt.progress * 100)}%</td>
-                                    <td><span class="status_link ${attempt.state}">${attempt.state}</span></td>
-                                    <td>
-                                      % if task.is_mr2:
-                                        ${ comps.get_container_link(task.state, attempt.taskTrackerId) }
-                                      % else:
-                                        <a href="/jobbrowser/trackers/${attempt.taskTrackerId}" class="task_tracker_link">${attempt.taskTrackerId}</a>
-                                      % endif
-                                    </td>
-                                    <td>${attempt.startTimeFormatted}</td>
-                                    <td>${attempt.finishTimeFormatted}</td>
-                                    <td>${attempt.outputSize}</td>
-                                    <td>${attempt.phase}</td>
-                                    <td>${attempt.shuffleFinishTimeFormatted}</td>
-                                    <td>${attempt.sortFinishTimeFormatted}</td>
-                                    <td>${attempt.mapFinishTimeFormatted}</td>
-                                </tr>
-                                % endfor
-                        </tbody>
-                    </table>
-                </div>
-                <div id="metadata" class="tab-pane">
-                    <table id="metadataTable" class="table table-striped table-condensed">
-                        <thead>
-                        <th>${_('Name')}</th>
-                        <th>${_('Value')}</th>
-                        </thead>
-                        <tbody>
-                        <tr>
-                            <td>${_('Task id')}</td>
-                            <td>${task.taskId}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Type')}</td>
-                            <td>${task.taskType}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('JobId')}</td>
-                            <td><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}" title="${_('View this job')}">${joblnk.jobId}</a></td>
-                        </tr>
-                        <tr>
-                            <td>${_('State')}</td>
-                            <td>${task.state}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Status')}</td>
-                            <td>${task.mostRecentState}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Start Time')}</td>
-                            <td>${task.startTimeFormatted}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Execution Start Time')}</td>
-                            <td>${task.execStartTimeFormatted}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Execution Finish Time')}</td>
-                            <td>${task.execFinishTimeFormatted}</td>
-                        </tr>
-                        <tr>
-                            <td>${_('Progress')}</td>
-                            <td>${"%d" % (task.progress * 100)}%</td>
-                        </tr>
-                        </tbody>
-                    </table>
-                </div>
-                <div id="counters" class="tab-pane">
-                    % if task.is_mr2:
-                        ${ comps.task_counters_mr2(task.counters) }
-                    % else:
-                        ${ comps.task_counters(task.counters) }
-                    % endif
-                </div>
+              <div class="tab-pane active" id="attempts">
+                <table id="attemptsTable" class="table table-condensed">
+                  <thead>
+                    <tr>
+                      <th>${_('Logs')}</th>
+                      <th>${_('Attempt ID')}</th>
+                      <th>${_('Progress')}</th>
+                      <th>${_('State')}</th>
+                      <th>${_('Task Tracker')}</th>
+                      <th>${_('Start Time')}</th>
+                      <th>${_('End Time')}</th>
+                      <th>${_('Output Size')}</th>
+                      <th>${_('Phase')}</th>
+                      <th>${_('Shuffle Finish')}</th>
+                      <th>${_('Sort Finish')}</th>
+                      <th>${_('Map Finish')}</th>
+                    </tr>
+                  </thead>
+                  <tbody>
+                  % for attempt in task.attempts:
+                    <tr>
+                      <td data-row-selector-exclude="true"><a href="${ url('jobbrowser.views.single_task_attempt_logs', job=joblnk.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }" data-row-selector-exclude="true"><i class="icon-tasks"></i></a></td>
+                      <td><a title="${_('View this attempt')}" href="${ url('jobbrowser.views.single_task_attempt', job=joblnk.jobId, taskid=task.taskId, attemptid=attempt.attemptId) }" data-row-selector="true">${attempt.attemptId_short}</a></td>
+                      <td>${"%d" % (attempt.progress * 100)}%</td>
+                      <td><span class="status_link ${attempt.state}">${attempt.state}</span></td>
+                      <td>
+                        % if task.is_mr2:
+                          ${ comps.get_container_link(task.state, attempt.taskTrackerId) }
+                        % else:
+                          <a href="/jobbrowser/trackers/${attempt.taskTrackerId}" class="task_tracker_link">${attempt.taskTrackerId}</a>
+                        % endif
+                      </td>
+                      <td>${attempt.startTimeFormatted}</td>
+                      <td>${attempt.finishTimeFormatted}</td>
+                      <td>${attempt.outputSize}</td>
+                      <td>${attempt.phase}</td>
+                      <td>${attempt.shuffleFinishTimeFormatted}</td>
+                      <td>${attempt.sortFinishTimeFormatted}</td>
+                      <td>${attempt.mapFinishTimeFormatted}</td>
+                    </tr>
+                  % endfor
+                  </tbody>
+                </table>
+              </div>
+              <div id="metadata" class="tab-pane">
+                <table id="metadataTable" class="table table-condensed">
+                  <thead>
+                    <tr>
+                      <th>${_('Name')}</th>
+                      <th>${_('Value')}</th>
+                    </tr>
+                  </thead>
+                  <tbody>
+                    <tr>
+                      <td>${_('Task id')}</td>
+                      <td>${task.taskId}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('Type')}</td>
+                      <td>${task.taskType}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('JobId')}</td>
+                      <td><a href="${url('jobbrowser.views.single_job', job=joblnk.jobId)}" title="${_('View this job')}">${joblnk.jobId}</a></td>
+                    </tr>
+                    <tr>
+                      <td>${_('State')}</td>
+                      <td>${task.state}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('Status')}</td>
+                      <td>${task.mostRecentState}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('Start Time')}</td>
+                      <td>${task.startTimeFormatted}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('Execution Start Time')}</td>
+                      <td>${task.execStartTimeFormatted}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('Execution Finish Time')}</td>
+                      <td>${task.execFinishTimeFormatted}</td>
+                    </tr>
+                    <tr>
+                      <td>${_('Progress')}</td>
+                      <td>${"%d" % (task.progress * 100)}%</td>
+                    </tr>
+                  </tbody>
+                </table>
+              </div>
+              <div id="counters" class="tab-pane">
+                % if task.is_mr2:
+                  ${ comps.task_counters_mr2(task.counters) }
+                % else:
+                  ${ comps.task_counters(task.counters) }
+                % endif
+              </div>
             </div>
+          </p>
         </div>
+      </div>
     </div>
+  </div>
 </div>
 
 <script src="/jobbrowser/static/js/utils.js" type="text/javascript" charset="utf-8"></script>

+ 69 - 68
apps/jobbrowser/src/jobbrowser/templates/tasks.mako

@@ -30,83 +30,84 @@ ${ commonheader(_('Task View: Job: %(jobId)s') % dict(jobId=job.jobId_short), "j
 </%def>
 
 <div class="container-fluid">
-    <h1>${_('Task View: Job: %(jobId)s') % dict(jobId=job.jobId_short)}</h1>
-    <div class="well hueWell">
+  <div class="card">
+    <h1 class="card-heading simple">${_('Task View: Job: %(jobId)s') % dict(jobId=job.jobId_short)}</h1>
+    <div class="card-body">
+      <p>
         <form method="get" action="${ url('jobbrowser.views.tasks', job=job.jobId) }">
-            <b>${_('Filter tasks:')}</b>
+          <b>${_('Filter tasks:')}</b>
+          <select name="taskstate" class="submitter">
+            <option value="">${_('All states')}</option>
+            <option value="succeeded" ${selected('succeeded', taskstate)}>${_('succeeded')}</option>
+            <option value="running" ${selected('running', taskstate)}>${_('running')}</option>
+            <option value="failed" ${selected('failed', taskstate)}>${_('failed')}</option>
+            <option value="killed" ${selected('killed', taskstate)}>${_('killed')}</option>
+            <option value="pending" ${selected('pending', taskstate)}>${_('pending')}</option>
+          </select>
 
-            <select name="taskstate" class="submitter">
-                <option value="">${_('All states')}</option>
-                <option value="succeeded" ${selected('succeeded', taskstate)}>${_('succeeded')}</option>
-                <option value="running" ${selected('running', taskstate)}>${_('running')}</option>
-                <option value="failed" ${selected('failed', taskstate)}>${_('failed')}</option>
-                <option value="killed" ${selected('killed', taskstate)}>${_('killed')}</option>
-                <option value="pending" ${selected('pending', taskstate)}>${_('pending')}</option>
-            </select>
+          <select name="tasktype" class="submitter">
+            <option value="">${_('All types')}</option>
+            <option value="map" ${selected('map', tasktype)}>${_('maps')}</option>
+            <option value="reduce" ${selected('reduce', tasktype)}>${_('reduces')}</option>
+            <option value="job_cleanup" ${selected('job_cleanup', tasktype)}>${_('cleanups')}</option>
+            <option value="job_setup" ${selected('job_setup', tasktype)}>${_('setups')}</option>
+          </select>
 
-            <select name="tasktype" class="submitter">
-                <option value="">${_('All types')}</option>
-                <option value="map" ${selected('map', tasktype)}>${_('maps')}</option>
-                <option value="reduce" ${selected('reduce', tasktype)}>${_('reduces')}</option>
-                <option value="job_cleanup" ${selected('job_cleanup', tasktype)}>${_('cleanups')}</option>
-                <option value="job_setup" ${selected('job_setup', tasktype)}>${_('setups')}</option>
-            </select>
-
-
-            <input type="text" name="tasktext"  class="submitter" title="${_('Text filter')}" placeholder="${_('Text Filter')}"
-                % if tasktext:
-                   value="${tasktext}"
-                % endif
-            />
+          <input type="text" name="tasktext"  class="submitter" title="${_('Text filter')}" placeholder="${_('Text Filter')}"
+              % if tasktext:
+                 value="${tasktext}"
+              % endif
+          />
         </form>
+      </p>
     </div>
 
-
     % if not page.object_list:
-         <p>${_('There were no tasks that match your search criteria.')}</p>
+    <p>${_('There were no tasks that match your search criteria.')}</p>
     % else:
-        <table class="datatables table table-striped table-condensed">
-            <thead>
-            <tr>
-                <th>${_('Logs')}</th>
-                <th>${_('Task ID')}</th>
-                <th>${_('Type')}</th>
-                <th>${_('Progress')}</th>
-                <th>${_('Status')}</th>
-                <th>${_('State')}</th>
-                <th>${_('Start Time')}</th>
-                <th>${_('End Time')}</th>
-                <th>${_('View Attempts')}</th>
-            </tr>
-            </thead>
-	        <tbody>
-	            %for t in page.object_list:
-	            <tr>
-                    <td data-row-selector-exclude="true">
-                        %if t.taskAttemptIds:
-                            <a href="${ url('jobbrowser.views.single_task_attempt_logs', job=t.jobId, taskid=t.taskId, attemptid=t.taskAttemptIds[-1]) }" data-row-selector-exclude="true"><i class="icon-tasks"></i></a>
-                        %endif
-                    </td>
-	                <td>${t.taskId_short}</td>
-	                <td>${t.taskType}</td>
-	                <td>
-	                   <div class="bar">${ "%d" % (t.progress * 100) }%</div>
-	                </td>
-	                <td>
-	                    <a href="${ url('jobbrowser.views.tasks', job=job.jobId) }?${ get_state_link(request, 'taskstate', t.state.lower()) }"
-	                       title="${ _('Show only %(state)s tasks') % dict(state=t.state.lower()) }"
-	                       class="${ t.state.lower() }">${ t.state.lower() }
-	                    </a>
-	                </td>
-	                <td>${t.mostRecentState}</td>
-	                <td>${t.execStartTimeFormatted}</td>
-	                <td>${t.execFinishTimeFormatted}</td>
-	                <td><a href="${ url('jobbrowser.views.single_task', job=job.jobId, taskid=t.taskId) }" data-row-selector="true">${_('Attempts')}</a></td>
-	            </tr>
-	            %endfor
-	        </tbody>
-        </table>
+    <table class="datatables table table-condensed">
+      <thead>
+        <tr>
+          <th>${_('Logs')}</th>
+          <th>${_('Task ID')}</th>
+          <th>${_('Type')}</th>
+          <th>${_('Progress')}</th>
+          <th>${_('Status')}</th>
+          <th>${_('State')}</th>
+          <th>${_('Start Time')}</th>
+          <th>${_('End Time')}</th>
+          <th>${_('View Attempts')}</th>
+        </tr>
+      </thead>
+      <tbody>
+      %for t in page.object_list:
+        <tr>
+          <td data-row-selector-exclude="true">
+              %if t.taskAttemptIds:
+              <a href="${ url('jobbrowser.views.single_task_attempt_logs', job=t.jobId, taskid=t.taskId, attemptid=t.taskAttemptIds[-1]) }" data-row-selector-exclude="true"><i class="icon-tasks"></i></a>
+              %endif
+          </td>
+          <td>${t.taskId_short}</td>
+          <td>${t.taskType}</td>
+          <td>
+            <div class="bar">${ "%d" % (t.progress * 100) }%</div>
+          </td>
+          <td>
+            <a href="${ url('jobbrowser.views.tasks', job=job.jobId) }?${ get_state_link(request, 'taskstate', t.state.lower()) }"
+               title="${ _('Show only %(state)s tasks') % dict(state=t.state.lower()) }"
+               class="${ t.state.lower() }">${ t.state.lower() }
+            </a>
+          </td>
+          <td>${t.mostRecentState}</td>
+          <td>${t.execStartTimeFormatted}</td>
+          <td>${t.execFinishTimeFormatted}</td>
+          <td><a href="${ url('jobbrowser.views.single_task', job=job.jobId, taskid=t.taskId) }" data-row-selector="true">${_('Attempts')}</a></td>
+        </tr>
+      %endfor
+      </tbody>
+    </table>
     %endif
+  </div>
 </div>
 
 <script type="text/javascript" charset="utf-8">

+ 0 - 4
apps/jobbrowser/static/css/jobbrowser.css

@@ -39,10 +39,6 @@
   display: none;
 }
 
-.sidebar-nav {
-  padding: 9px 0;
-}
-
 .nochrome::-moz-focus-inner {
   border: 0;
   padding: 0

+ 2 - 2
apps/jobbrowser/static/js/utils.js

@@ -19,7 +19,7 @@ function initLogsElement(element) {
   element.scroll(function () {
     element.data("logsAtEnd", ($(this).scrollTop() + $(this).height() + 20 >= $(this)[0].scrollHeight));
   });
-  element.css("overflow", "auto").height($(window).height() - element.offset().top - 50);
+  element.css("overflow", "auto").height($(window).height() - element.offset().top - 80);
 }
 
 function appendAndScroll(element, logs) {
@@ -31,7 +31,7 @@ function appendAndScroll(element, logs) {
 }
 
 function resizeLogs(element) {
-  element.css("overflow", "auto").height($(window).height() - element.offset().top - 50);
+  element.css("overflow", "auto").height($(window).height() - element.offset().top - 80);
 }
 
 var _resizeTimeout = -1;

+ 0 - 9
apps/jobsub/static/css/jobsub.css

@@ -28,13 +28,4 @@ a.advanced, a.advanced:link, a.advanced:hover {
 
 input.search-query {
   vertical-align: top;
-}
-
-.dt-records {
-  margin-left: 10px;
-}
-
-.dt-pages {
-  margin-right: 10px;
-  float: right;
 }

+ 26 - 0
desktop/core/static/css/hue3.css

@@ -1275,4 +1275,30 @@ a#advanced-btn:hover {
 
 .card-heading-blue {
   color: #338BB8!important;
+}
+
+.dt-records {
+  margin-left: 10px;
+}
+
+.dt-pages {
+  margin-right: 10px;
+  float: right;
+}
+
+.progress {
+  height: 20px;
+  margin-bottom: 0;
+  padding: 0;
+}
+
+.nav-list > li.white {
+  margin-left: -15px;
+  margin-right: -15px;
+  background-color: #FFFFFF;
+  border-left: 2px solid transparent;
+  margin-top: 1px;
+  padding: 9px 18px;
+  text-shadow: none;
+  transition: border 0.218s ease 0s;
 }