source: branches/3.18-stable/www/views/jobs/view_job.jsp @ 7932

Last change on this file since 7932 was 7932, checked in by Nicklas Nordborg, 3 months ago

References #2246: Sticky table headers

Implemented for all item list pages and a few other places:

  • Extensions installation dialog
  • Administrate / Services list page
  • Batch inherit annotations
  • Manage list presets
  • List of changed item in view job dialog


  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Id
File size: 20.8 KB
Line 
1<%-- $Id: view_job.jsp 7932 2021-04-28 07:16:56Z nicklas $
2  ------------------------------------------------------------------
3  Copyright (C) 2005 Nicklas Nordborg
4  Copyright (C) 2006 Jari Häkkinen, Nicklas Nordborg, Gregory Vincic
5  Copyright (C) 2007 Nicklas Nordborg
6
7  This file is part of BASE - BioArray Software Environment.
8  Available at http://base.thep.lu.se/
9
10  BASE is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License
12  as published by the Free Software Foundation; either version 3
13  of the License, or (at your option) any later version.
14
15  BASE is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License
21  along with BASE. If not, see <http://www.gnu.org/licenses/>.
22  ------------------------------------------------------------------
23
24  @author Nicklas
25  @version 2.0
26--%>
27<%@ page pageEncoding="UTF-8" session="false"
28  import="net.sf.basedb.core.SessionControl"
29  import="net.sf.basedb.core.DbControl"
30  import="net.sf.basedb.core.SystemItems"
31  import="net.sf.basedb.core.Item"
32  import="net.sf.basedb.core.ItemContext"
33  import="net.sf.basedb.core.Permission"
34  import="net.sf.basedb.core.Job"
35  import="net.sf.basedb.core.JobAgent"
36  import="net.sf.basedb.core.Project"
37  import="net.sf.basedb.core.BasicItem"
38  import="net.sf.basedb.core.Nameable"
39  import="net.sf.basedb.core.File"
40  import="net.sf.basedb.core.Path"
41  import="net.sf.basedb.core.User"
42  import="net.sf.basedb.core.ChangeHistory"
43  import="net.sf.basedb.core.ItemResultIterator"
44  import="net.sf.basedb.core.ItemQuery"
45  import="net.sf.basedb.core.ItemResultList" 
46  import="net.sf.basedb.core.PermissionDeniedException"
47  import="net.sf.basedb.core.PluginDefinition"
48  import="net.sf.basedb.core.PluginConfiguration"
49  import="net.sf.basedb.core.PluginType"
50  import="net.sf.basedb.core.ParameterInfo"
51  import="net.sf.basedb.core.query.Orders"
52  import="net.sf.basedb.core.query.Hql"
53  import="net.sf.basedb.core.plugin.GuiContext"
54  import="net.sf.basedb.core.plugin.NonRestartable"
55  import="net.sf.basedb.core.plugin.Plugin"
56  import="net.sf.basedb.core.signal.SignalTransporter"
57  import="net.sf.basedb.core.signal.Signal"
58  import="net.sf.basedb.plugins.util.Parameters"
59  import="net.sf.basedb.clients.web.Base"
60  import="net.sf.basedb.clients.web.ChangeHistoryUtil"
61  import="net.sf.basedb.clients.web.util.HTML"
62  import="net.sf.basedb.util.Values"
63  import="net.sf.basedb.util.formatter.Formatter"
64  import="net.sf.basedb.clients.web.formatter.FormatterFactory"
65  import="java.util.Date"
66  import="java.util.Map"
67  import="java.util.Set"
68  import="java.util.List"
69  import="java.util.Collections"
70  import="java.util.Collection"
71%>
72<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
73<%@ taglib prefix="t" uri="/WEB-INF/tab.tld" %>
74<%@ taglib prefix="tbl" uri="/WEB-INF/table.tld" %>
75<%!
76  private static final Item itemType = Item.JOB;
77  private static final GuiContext guiContext = new GuiContext(itemType, GuiContext.Type.ITEM);
78
79  private String getItemName(BasicItem item)
80  {
81    String itemName = "";
82    if (item instanceof File)
83    {
84      itemName = ((File)item).getPath().toString();
85    }
86    else if (item instanceof Nameable)
87    {
88      itemName = ((Nameable)item).getName();
89    }
90    else
91    {
92      itemName = item.toString();
93    }
94    return itemName;
95  }
96%>
97<%
98final SessionControl sc = Base.getExistingSessionControl(pageContext, true);
99final String ID = sc.getId();
100final ItemContext cc = Base.getAndSetCurrentContext(sc, itemType, null, null);
101final int itemId = cc.getId();
102final String tab = Values.getString(request.getParameter("tab"), "properties");
103final float scale = Base.getScale(sc);
104final DbControl dc = sc.newDbControl();
105try
106{
107  Job job = Job.getById(dc, itemId);
108  String title = "View job -- " + HTML.encodeTags(job.getName());
109 
110  final boolean writePermission = job.hasPermission(Permission.WRITE);
111  final boolean deletePermission = job.hasPermission(Permission.DELETE);
112  final boolean isRemoved = job.isRemoved();
113  final boolean isUsed = isRemoved && job.isUsed();
114  final boolean deletePermanentlyPermission = deletePermission && !isUsed;
115 
116  boolean readPlugin = true;
117  PluginDefinition plugin = null;
118  try
119  {
120    plugin = job.getPluginDefinition();
121  }
122  catch (PermissionDeniedException ex)
123  {
124    readPlugin = false;
125  }
126  boolean readCurrentConfig = true;
127  PluginConfiguration currentConfig = null;
128  try
129  {
130    currentConfig = job.getPluginConfiguration();
131  }
132  catch (PermissionDeniedException ex)
133  {
134    readCurrentConfig = false;
135  }
136  boolean readAgent = true;
137  JobAgent agent = null;
138  try
139  {
140    agent = job.getJobAgent();
141  }
142  catch (PermissionDeniedException ex)
143  {
144    readAgent = false;
145  }
146  boolean readActiveProject = true;
147  Project activeProject = null;
148  try
149  {
150    if (job.getActiveProjectId() != 0) 
151    {
152      activeProject = Project.getById(dc, job.getActiveProjectId());
153    }
154  }
155  catch (PermissionDeniedException ex)
156  {
157    readActiveProject = false;
158  }
159  catch (Exception ex)
160  {
161    // Some other problem (for example, no longer exists)
162  }
163
164  int parameterVersion = job.getParameterVersion();
165  int latestParameterVersion = currentConfig == null ? parameterVersion : currentConfig.getParameterVersion();
166
167  final Job.Status status = job.getStatus();
168  final boolean autoUpdate = status == Job.Status.WAITING || 
169    status == Job.Status.PREPARED || status == Job.Status.EXECUTING || status == Job.Status.ABORTING;
170  Formatter<Date> dateFormatter = FormatterFactory.getDateFormatter(sc);
171  Formatter<Date> dateTimeFormatter = FormatterFactory.getDateTimeFormatter(sc);
172  Set<String> jobParameters = job.getParameterNames();
173  File logFile = null;
174  if (!autoUpdate && jobParameters != null && jobParameters.contains(Parameters.LOGFILE_PARAMETER))
175  {
176    try
177    {
178      Object temp = job.getParameterValue(Parameters.LOGFILE_PARAMETER);
179      if (temp instanceof File)
180      {
181        logFile = (File)temp;
182      }
183      else if (temp instanceof String)
184      {
185        logFile = File.getByPath(dc, new Path((String)temp, Path.Type.FILE), false);
186      }
187    }
188    catch (Throwable t)
189    {}
190  }
191 
192  // Check if the job can be aborted or paused
193  boolean supportsAbort = false; 
194  boolean supportsPause = false;
195  boolean supportsForceError = writePermission && status != Job.Status.DONE && status != Job.Status.ERROR;
196 
197  // The status must be executable or EXECUTING
198  if ((status == Job.Status.EXECUTING || status.isExecutable()) && writePermission)
199  {
200    // Check if a signal-transporter exists
201    try
202    {
203      SignalTransporter signalTransporter = job.getSignalTransporter();
204      if (signalTransporter == null)
205      {
206        // The job is only abortable if it is waiting
207        supportsAbort = status == Job.Status.WAITING;
208      }
209      else
210      {
211        // Otherwise we must check with the signal transporter
212        Collection<Signal> supportedSignals = signalTransporter.getSupportedSignals();
213        supportsAbort = supportedSignals == null || supportedSignals.contains(Signal.ABORT);
214        supportsPause = supportedSignals != null && supportedSignals.contains(Signal.PAUSE);
215      }
216    }
217    catch (Exception ex)
218    {}
219  }
220  if (autoUpdate) job.requestStatusUpdate();
221  %>
222  <base:page type="popup" title="<%=title%>" id="view-page"> 
223  <base:head scripts="tabcontrol-2.js,table.js,~jobs.js" 
224    styles="tabcontrol.css,progressbar.css,table.css">
225  <style>
226  .executecommand
227  {
228    font-size: 0.85em;
229    color: #777777;
230  }
231  </style>
232  </base:head>
233  <base:body data-read-only="1">
234    <h1><%=title%> <base:help tabcontrol="main" /></h1>
235    <div id="page-data" 
236      data-item-id="<%=itemId%>"
237      data-job-parameter-version="<%=parameterVersion %>"
238      data-latest-parameter-version="<%=latestParameterVersion %>"
239      data-breakpoint="<%=HTML.encodeTags(job.getExecuteCommand()) %>"
240      data-job-status="<%=status.name()%>"
241      data-auto-update="<%=autoUpdate ? 1 : 0 %>"
242    ></div>
243
244    <t:tabcontrol id="main" 
245      subclass="content dialogtabcontrol"
246      active="<%=tab%>" position="bottom">
247    <t:tab id="properties" title="Properties" helpid="job.view.properties">
248      <table class="fullform outlined">
249      <%
250      if (isRemoved)
251      {
252        %>
253        <tr>
254          <th></th>
255          <td colspan="2">
256          <div class="itemstatus">
257            <base:icon 
258              id="btnDeletePermanently"
259              image="deleted.png"
260              data-notify="btnDeletePermanently"
261              enabled="<%=deletePermanentlyPermission %>"
262              tooltip="<%=deletePermanentlyPermission ? "Permanently delete this item" : null%>"
263              visible="<%=isRemoved%>"> This item has been flagged for deletion<br></base:icon>
264            <base:icon
265              id="btnUsingItems"
266              image="used.png" 
267              tooltip="Show the items that are using this one"
268              visible="<%=isUsed%>"> This item is used by other items and can't be permanently deleted<br></base:icon>
269          </div>
270          </td>
271        </tr>
272        <%
273      }
274      %>
275      <tr>
276        <th>Name</th>
277        <td><%=HTML.encodeTags(job.getName())%></td>
278      </tr>
279      <tr>
280        <th>Plugin</th>
281        <td>
282          <base:propertyvalue item="<%=job%>" property="pluginDefinition.name" nulltext="<i>External</i>"/> 
283          <%=job.getPluginVersion() == null ?
284            "" : "(" + HTML.encodeTags(job.getPluginVersion()) + ")"%>
285        </td>
286      </tr>
287      <%
288      if (currentConfig != null)
289      {
290        %>
291        <tr>
292          <th class="subprompt">- configuration</th>
293          <td>
294            <base:propertyvalue item="<%=job%>" property="pluginConfiguration.name" />
295          </td>
296        </tr>
297        <%
298      }
299      %>
300      <tr>
301        <th>Type</th>
302        <td>
303          <%=plugin == null ? "" : plugin.getMainType() %>
304          <base:propertyvalue item="<%=job%>" property="itemSubtype.name" nulltext="" />
305        </td>
306      </tr>
307      <tr>
308        <th>User</th>
309        <td>
310          <base:propertyvalue item="<%=job%>" property="owner.name" />
311        </td>
312      </tr>
313      <tr>
314        <th>Active project</th>
315        <td>
316          <%=activeProject == null ? (readActiveProject ? "<i>- none -</i>" : "<i>- denied -</i>") : HTML.encodeTags(activeProject.getName()) %>
317        </td>
318      </tr>
319      <tr>
320        <th>Experiment</th>
321        <td>
322          <base:propertyvalue item="<%=job%>" property="experiment.name" />
323        </td>
324      </tr>
325      <tr>
326        <th>Status</th>
327        <td>
328          <div class="<%=status == Job.Status.ERROR ? "error messagecontainer" : ""%>" style="margin: 1px 0px;">
329          <%=status%><%=job.isDryRun() ? " (dry-run)" : "" %>:
330          <span id="message">
331            <%=(status == Job.Status.WAITING || status == Job.Status.PAUSED) && job.getExecuteCommand() != null ? 
332              "<span class=\"executecommand\">(Resume from " + job.getExecuteCommand() + ")</span><br>" : ""%>
333            <%=HTML.niceFormat(job.getStatusMessage())%></span>
334          </div>
335        </td>
336      </tr>
337      <tr>
338        <th class="subprompt">- percent complete</th>
339        <td>
340          <table class="progressbar" style="margin-bottom: 2px;">
341          <tr>
342          <td>
343            <table class="bar" style="width: 200px;">
344            <tr>
345              <%
346              int percent = job.getPercentComplete();
347              %>
348              <td id="percentDone" class="percentDone" style="width: <%=percent%>%; <%=percent <= 0 ? "display: none;" : ""%>">&nbsp;</td>
349              <td id="percentRemain" class="percentRemain" style="width: <%=100-percent%>%; <%=percent == 100 || percent == -1 ? "display: none;" : ""%>">&nbsp;</td>
350              <td id="percentUnknown" class="percentUnknown" style="width: 100%; <%=percent != -1 ? "display: none;" : "" %>">unknown</td>
351            </tr>
352            </table>
353          </td>
354          <td id="percentText" class="percentText" 
355            style="<%=percent < 0 ? "display: none;" : "" %>"><%=percent%>%</td>
356            <%
357            if (logFile != null)
358            {
359              %>
360              <td style="padding-left: 10px;"><base:button 
361                subclass="auto-init"
362                data-auto-init="view-file"
363                data-file-id="<%=logFile.getId()%>"
364                image="view.png" 
365                title="View log&hellip;"
366                tooltip="View the log file with detailed information about this job"
367                /></td>
368              <%
369            }
370            %>
371          </tr>
372          </table>
373        </td>
374      </tr>
375      <tr>
376        <th>Description</th>
377        <td><%=HTML.niceFormat(job.getDescription())%></td>
378      </tr>
379      <tr>
380        <th>Created</th>
381        <td>
382          <%=dateTimeFormatter.format(job.getCreated())%>
383        </td>
384      </tr>
385      <tr>
386        <th class="subprompt">- scheduled</th>
387        <td>
388          <%=dateTimeFormatter.format(job.getScheduled())%>
389        </td>
390      </tr>
391      <tr>
392        <th class="subprompt">- priority</th>
393        <td>
394          <%=job.getPriority()%> (1 = highest, 10 = lowest)
395        </td>
396      </tr>
397      <tr>
398        <th>Running time</th>
399        <td id="runningTime">
400          <%
401          Date started = job.getStarted();
402          if (started != null)
403          {
404            Date ended = job.getEnded();
405            if (ended == null) ended = new Date();
406            long runningTime = ended.getTime() - started.getTime();
407            %>
408            <%=Values.formatTime(runningTime / 1000)%>
409            <%
410          }
411          %>
412        </td>
413      </tr>
414      <tr>
415        <th class="subprompt">- started</th>
416        <td>
417          <%=dateTimeFormatter.format(job.getStarted())%>
418        </td>
419      </tr>
420      <tr>
421        <th class="subprompt">- ended</th>
422        <td>
423          <%=dateTimeFormatter.format(job.getEnded())%>
424        </td>
425      </tr>
426      <tr>
427        <th>Server</th>
428        <td>
429          <%=HTML.encodeTags(job.getServerAndNode())%>
430        </td>
431      </tr>
432      <tr>
433        <th>External ID</th>
434        <td>
435          <%=HTML.encodeTags(job.getExternalId())%>
436        </td>
437      </tr>
438      <tr>
439        <th>Job agent</th>
440        <td><%=Base.getEncodedName(agent, !readAgent)%></td>
441      </tr>
442      <tr class="dynamic">
443        <th></th>
444        <td></td>
445      </tr>
446      </table>
447      </t:tab>
448      <%
449      if (job.getStackTrace() != null)
450      {
451        %>
452        <t:tab id="stacktrace" title="Stack trace" helpid="job.view.stacktrace">
453          <div class="stacktrace" style="padding: 0.5em;"><%=HTML.encodeTags(job.getStackTrace().replaceAll("\t", "  "))%></div>
454        </t:tab>
455        <%
456      }
457      %>
458      <t:tab id="parameters" title="Parameters" helpid="job.view.parameters">
459        <table class="fullform outlined">
460        <tbody class="sectionheader">
461          <tr>
462            <th colspan="2">Job parameters</th>
463          </tr>
464        </tbody>
465        <tbody>
466        <%
467        List<String> names = new java.util.ArrayList<String>(jobParameters);
468        Collections.sort(names);
469        for (String name : names)
470        {
471          StringBuilder sb = new StringBuilder();
472          String displayValue = "";
473          String description = "";
474          try
475          {
476            ParameterInfo pi = job.getParameterInfo(name);
477            if (pi.getLabel() != null) name = HTML.encodeTags(pi.getLabel());
478            description = HTML.encodeTags(pi.getDescription());
479            List<?> values = pi.getValuesOrMask();
480            int i = 0;
481            for (Object value : values)
482            {
483              if (value != null)
484              {
485                if (i > 0) sb.append(", ");
486                i++;
487                if (value instanceof BasicItem)
488                {
489                  sb.append(HTML.encodeTags(getItemName((BasicItem)value)));
490                }
491                else if (value instanceof Date)
492                {
493                  sb.append(dateFormatter.format((Date)value));
494                }
495                else
496                {
497                  sb.append(HTML.encodeTags(value.toString()));
498                }
499              }
500            }
501            displayValue = sb.toString();
502          }
503          catch (Throwable ex)
504          {
505            displayValue = "<i>ERROR: "+ex.getMessage()+"</i>";
506          }
507          %>
508          <tr>
509            <th><span title="<%=description%>"><%=name%></span></th>
510            <td>
511              <%=displayValue%>
512            </td>
513          </tr>
514          <%
515        }
516        %>
517        <%
518        if (!readCurrentConfig)
519        {
520          %>
521          </tbody>
522          <tbody class="sectionheader">
523            <tr>
524              <th colspan="2">Plugin configuration parameters</th>
525            </tr>
526          </tbody>
527          <tbody>
528          <tr>
529            <th></th>
530            <td><i>- denied -</i></td>
531          </tr>
532          <%
533        }
534        else if (currentConfig != null)
535        {
536          %>
537          </tbody>
538          <tbody class="sectionheader">
539            <tr>
540              <th colspan="2">Plugin configuration parameters</th>
541            </tr>
542          </tbody>
543          <tbody>
544          <tr>
545            <th><span 
546              title="The version of the parmeters used for this job, current version in paranthesis">Parameter version</span></td>
547            <td><%=parameterVersion%> (<%=latestParameterVersion %>)</th>
548          </tr>
549          <%
550          names = new java.util.ArrayList<String>(currentConfig.getParameterNames(parameterVersion));
551          Collections.sort(names);
552          for (String name : names)
553          {
554            StringBuilder sb = new StringBuilder();
555            String displayValue = "";
556            String description = "";
557            try
558            {
559              ParameterInfo pi = currentConfig.getParameterInfo(name, parameterVersion);
560              if (pi.getLabel() != null) name = HTML.encodeTags(pi.getLabel());
561              description = HTML.encodeTags(pi.getDescription());
562              List<?> values = pi.getValuesOrMask();
563              int i = 0;
564              for (Object value : values)
565              {
566                if (value != null)
567                {
568                  if (i > 0) sb.append(", ");
569                  i++;
570                  if (value instanceof BasicItem)
571                  {
572                    sb.append(HTML.encodeTags(getItemName((BasicItem)value)));
573                  }
574                  else if (value instanceof Date)
575                  {
576                    sb.append(dateFormatter.format((Date)value));
577                  }
578                  else
579                  {
580                    sb.append(HTML.encodeTags(value.toString()));
581                  }
582                }
583              }
584              displayValue = sb.toString();
585            }
586            catch (Throwable ex)
587            {
588              displayValue = "<i>ERROR: "+ex.getMessage()+"</i>";
589            }
590            %>
591            <tr>
592              <th><span title="<%=description%>"><%=name%></span></th>
593              <td>
594                <%=displayValue%>
595              </td>
596            </tr>
597            <%
598          }
599          %>
600          <%
601        }
602        %>
603        <tr class="dynamic">
604          <th></th>
605          <td></td>
606        </tr>
607        </tbody>
608        </table>
609      </t:tab>
610     
611      <t:tab id="changes" title="Changed items"
612        tooltip="Display a log of all modifications made by this job"
613        visible="<%=!autoUpdate && ChangeHistoryUtil.showChangeHistoryTab(sc) %>">
614        <%
615        ItemQuery<ChangeHistory> query = ChangeHistory.getChangesBy(job);
616        query.order(Orders.asc(Hql.property("id")));
617        query.setMaxResults(1000);
618        query.setReturnTotalCount(true);
619        ItemResultIterator<ChangeHistory> changes = query.iterate(dc);
620        long numChanges = changes.getTotalCount();
621        %>
622        <tbl:table 
623          id="history" columns="all" 
624          subclass="fulltable sticky-headers" style="border-bottom: 0px;">
625          <tbl:columndef id="changeType" title="Change type" />
626          <tbl:columndef id="item" title="Item" />
627          <tbl:columndef id="info" title="Info" />
628         
629          <tbl:data style="top: 0px;">
630            <tbl:headers>
631              <tbl:headerrow>
632                <tbl:columnheaders />
633              </tbl:headerrow>
634            </tbl:headers>
635            <tbl:rows>
636            <%
637            if (numChanges > 1000)
638            {
639              %>
640              <tbl:panel subclass="bg-filled-100">
641                <b>NOTE! Listing 1000 of <span title="<%=numChanges %>"><%=Values.formatNumber(numChanges / 1000f, 1, "k") %></span> total changes.</b>
642              </tbl:panel>
643              <%
644            }
645            while (changes.hasNext())
646            {
647              ChangeHistory change = changes.next();
648              %>
649              <tbl:row>
650                <tbl:cell column="changeType"><%=change.getChangeType()%></tbl:cell>
651                <tbl:cell column="item"><%=ChangeHistoryUtil.getItem(dc, change, false, false)%></tbl:cell>
652                <tbl:cell column="info"><%=HTML.encodeTags(change.getChangeInfo())%></tbl:cell>
653              </tbl:row>
654              <%
655            }
656            if (numChanges == 0)
657            {
658              %>
659              <tbl:panel subclass="bg-filled-50">
660                <div class="messagecontainer note">
661                No log entries found for this job. NOTE! This job may have made
662                other changes that are not recorded by the logging mechanism.
663                </div>
664              </tbl:panel>
665              <%
666            }
667            %>
668            </tbl:rows>
669          </tbl:data>
670        </tbl:table>
671      </t:tab>
672      </t:tabcontrol>
673 
674    <base:buttongroup subclass="dialogbuttons">
675      <%
676      if (supportsPause)
677      {
678        %>
679        <base:button id="btnPause" title="Pause" image="pause.png" tooltip="Pause the job" />
680        <%
681      }
682      if (supportsAbort)
683      {
684        %>
685        <base:button id="btnAbort" title="Abort&hellip;" image="abort.png" tooltip="Abort the job" />
686        <%
687      }
688      else if (supportsForceError)
689      {
690        %>
691        <base:button id="btnForceError" title="Force error&hellip;" image="bug.png" tooltip="Force update the job status to ERROR" />
692        <%
693      }
694      %>
695      <%
696      if ((status == Job.Status.PAUSED || status == Job.Status.ERROR) && job.getJobType() == Job.Type.RUN_PLUGIN)
697      {
698        boolean restartable = !job.getPluginDefinition().supports("net.sf.basedb.core.plugin.NonRestartable");       
699        if (restartable)
700        {
701          %>
702          <base:button 
703            id="btnRestartJob" 
704            title="Restart job" 
705            image="refresh.png" 
706            tooltip="Try to run this job again with the same parameters"
707          />
708          <base:button 
709            id="btnReconfigureJob"
710            title="Re-configure job"
711            image="runplugin.png"
712            tooltip="Change the parameters for this job and try again"
713            visible="<%=job.hasContext()%>"
714          />
715          <%
716        }
717      }
718      if (status == Job.Status.DONE && job.isDryRun())
719      {
720        %>
721        <base:button 
722          id="btnRestartJob"
723          data-clear-dry-run="1"
724          title="Really run" 
725          image="refresh.png" 
726          tooltip="Run this dry-run job for real"
727        />
728        <base:button 
729          id="btnReconfigureJob"
730          title="Re-configure job"
731          image="runplugin.png"
732          tooltip="Change the parameters for this job and try again"
733          visible="<%=job.hasContext()%>"
734        />
735        <%
736      }
737      %>
738      <base:button id="close" title="Close" />
739    </base:buttongroup>
740  </base:body>
741  </base:page>
742  <%
743}
744finally
745{
746  if (dc != null) dc.close();
747}
748
749%>
Note: See TracBrowser for help on using the repository browser.