1 package autotest.afe; 2 3 import autotest.common.JsonRpcCallback; 4 import autotest.common.SimpleCallback; 5 import autotest.common.StaticDataRepository; 6 import autotest.common.Utils; 7 import autotest.common.table.DataTable; 8 import autotest.common.table.DataTable.DataTableListener; 9 import autotest.common.table.DynamicTable; 10 import autotest.common.table.ListFilter; 11 import autotest.common.table.RpcDataSource; 12 import autotest.common.table.SearchFilter; 13 import autotest.common.table.SelectionManager; 14 import autotest.common.table.SimpleFilter; 15 import autotest.common.table.TableDecorator; 16 import autotest.common.table.DataTable.TableWidgetFactory; 17 import autotest.common.table.DynamicTable.DynamicTableListener; 18 import autotest.common.ui.ContextMenu; 19 import autotest.common.ui.DetailView; 20 import autotest.common.ui.NotifyManager; 21 import autotest.common.ui.TableActionsPanel.TableActionsListener; 22 23 import com.google.gwt.dom.client.Element; 24 import com.google.gwt.event.dom.client.ClickEvent; 25 import com.google.gwt.event.dom.client.ClickHandler; 26 import com.google.gwt.json.client.JSONArray; 27 import com.google.gwt.json.client.JSONBoolean; 28 import com.google.gwt.json.client.JSONNumber; 29 import com.google.gwt.json.client.JSONObject; 30 import com.google.gwt.json.client.JSONString; 31 import com.google.gwt.json.client.JSONValue; 32 import com.google.gwt.user.client.Command; 33 import com.google.gwt.user.client.ui.Button; 34 import com.google.gwt.user.client.ui.DisclosurePanel; 35 import com.google.gwt.user.client.ui.Frame; 36 import com.google.gwt.user.client.ui.HTML; 37 import com.google.gwt.user.client.ui.Label; 38 import com.google.gwt.user.client.ui.Widget; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.Set; 43 44 public class JobDetailView extends DetailView implements TableWidgetFactory { 45 private static final String[][] JOB_HOSTS_COLUMNS = { 46 {DataTable.CLICKABLE_WIDGET_COLUMN, ""}, // selection checkbox 47 {"hostname", "Host"}, {"full_status", "Status"}, 48 {"host_status", "Host Status"}, {"host_locked", "Host Locked"}, 49 // columns for all logs and debug log links 50 {DataTable.CLICKABLE_WIDGET_COLUMN, ""}, {DataTable.CLICKABLE_WIDGET_COLUMN, ""} 51 }; 52 private static final String[][] CHILD_JOBS_COLUMNS = { 53 { "id", "ID" }, { "name", "Name" }, { "priority", "Priority" }, 54 { "control_type", "Client/Server" }, { JobTable.HOSTS_SUMMARY, "Status" }, 55 { JobTable.RESULTS_SUMMARY, "Passed Tests" } 56 }; 57 private static final String[][] JOB_HISTORY_COLUMNS = { 58 { "id", "ID" }, { "hostname", "Host" }, { "name", "Name" }, 59 { "start_time", "Start Time" }, { "end_time", "End Time" }, 60 { "time_used", "Time Used (seconds)" }, { "status", "Status" } 61 }; 62 public static final String NO_URL = "about:blank"; 63 public static final int NO_JOB_ID = -1; 64 public static final int HOSTS_PER_PAGE = 30; 65 public static final int CHILD_JOBS_PER_PAGE = 30; 66 public static final String RESULTS_MAX_WIDTH = "700px"; 67 public static final String RESULTS_MAX_HEIGHT = "500px"; 68 69 public interface JobDetailListener { onHostSelected(String hostId)70 public void onHostSelected(String hostId); onCloneJob(JSONValue result)71 public void onCloneJob(JSONValue result); 72 } 73 74 protected class ChildJobsListener { onJobSelected(int id)75 public void onJobSelected(int id) { 76 fetchById(Integer.toString(id)); 77 } 78 } 79 80 protected class JobHistoryListener { onJobSelected(String url)81 public void onJobSelected(String url) { 82 Utils.openUrlInNewWindow(url); 83 } 84 } 85 86 protected int jobId = NO_JOB_ID; 87 88 private JobStatusDataSource jobStatusDataSource = new JobStatusDataSource(); 89 protected JobTable childJobsTable = new JobTable(CHILD_JOBS_COLUMNS); 90 protected TableDecorator childJobsTableDecorator = new TableDecorator(childJobsTable); 91 protected SimpleFilter parentJobIdFliter = new SimpleFilter(); 92 protected DynamicTable hostsTable = new DynamicTable(JOB_HOSTS_COLUMNS, jobStatusDataSource); 93 protected TableDecorator hostsTableDecorator = new TableDecorator(hostsTable); 94 protected SimpleFilter jobFilter = new SimpleFilter(); 95 protected Button abortButton = new Button("Abort job"); 96 protected Button cloneButton = new Button("Clone job"); 97 protected Frame tkoResultsFrame = new Frame(); 98 99 protected JobDetailListener listener; 100 protected ChildJobsListener childJobsListener = new ChildJobsListener(); 101 private SelectionManager hostsSelectionManager; 102 private SelectionManager childJobsSelectionManager; 103 104 private Label controlFile = new Label(); 105 private DisclosurePanel controlFilePanel = new DisclosurePanel(""); 106 107 protected StaticDataRepository staticData = StaticDataRepository.getRepository(); 108 109 protected Button getJobHistoryButton = new Button("Get Job History"); 110 protected JobHistoryListener jobHistoryListener = new JobHistoryListener(); 111 protected DataTable jobHistoryTable = new DataTable(JOB_HISTORY_COLUMNS); 112 JobDetailView(JobDetailListener listener)113 public JobDetailView(JobDetailListener listener) { 114 this.listener = listener; 115 setupSpreadsheetListener(Utils.getBaseUrl()); 116 } 117 setupSpreadsheetListener(String baseUrl)118 private native void setupSpreadsheetListener(String baseUrl) /*-{ 119 var ins = this; 120 $wnd.onSpreadsheetLoad = function(event) { 121 if (event.origin !== baseUrl) { 122 return; 123 } 124 ins.@autotest.afe.JobDetailView::resizeResultsFrame(Ljava/lang/String;)(event.data); 125 } 126 127 $wnd.addEventListener("message", $wnd.onSpreadsheetLoad, false); 128 }-*/; 129 130 @SuppressWarnings("unused") // called from native resizeResultsFrame(String message)131 private void resizeResultsFrame(String message) { 132 String[] parts = message.split(" "); 133 tkoResultsFrame.setSize(parts[0], parts[1]); 134 } 135 136 @Override fetchData()137 protected void fetchData() { 138 pointToResults(NO_URL, NO_URL, NO_URL, NO_URL, NO_URL); 139 JSONObject params = new JSONObject(); 140 params.put("id", new JSONNumber(jobId)); 141 rpcProxy.rpcCall("get_jobs_summary", params, new JsonRpcCallback() { 142 @Override 143 public void onSuccess(JSONValue result) { 144 JSONObject jobObject; 145 try { 146 jobObject = Utils.getSingleObjectFromArray(result.isArray()); 147 } 148 catch (IllegalArgumentException exc) { 149 NotifyManager.getInstance().showError("No such job found"); 150 resetPage(); 151 return; 152 } 153 String name = Utils.jsonToString(jobObject.get("name")); 154 String runVerify = Utils.jsonToString(jobObject.get("run_verify")); 155 156 showText(name, "view_label"); 157 showField(jobObject, "owner", "view_owner"); 158 String parent_job_url = Utils.jsonToString(jobObject.get("parent_job")).trim(); 159 if (parent_job_url.equals("<null>")){ 160 parent_job_url = "http://www.youtube.com/watch?v=oHg5SJYRHA0"; 161 } else { 162 parent_job_url = "#tab_id=view_job&object_id=" + parent_job_url; 163 } 164 showField(jobObject, "parent_job", "view_parent"); 165 getElementById("view_parent").setAttribute("href", parent_job_url); 166 showField(jobObject, "test_retry", "view_test_retry"); 167 double priorityValue = jobObject.get("priority").isNumber().getValue(); 168 String priorityName = staticData.getPriorityName(priorityValue); 169 showText(priorityName, "view_priority"); 170 showField(jobObject, "created_on", "view_created"); 171 showField(jobObject, "timeout_mins", "view_timeout"); 172 String imageUrlString = ""; 173 if (jobObject.containsKey("image")) { 174 imageUrlString = Utils.jsonToString(jobObject.get("image")).trim(); 175 } 176 showText(imageUrlString, "view_image_url"); 177 showField(jobObject, "max_runtime_mins", "view_max_runtime"); 178 showField(jobObject, "email_list", "view_email_list"); 179 showText(runVerify, "view_run_verify"); 180 showField(jobObject, "reboot_before", "view_reboot_before"); 181 showField(jobObject, "reboot_after", "view_reboot_after"); 182 showField(jobObject, "parse_failed_repair", "view_parse_failed_repair"); 183 showField(jobObject, "synch_count", "view_synch_count"); 184 if (jobObject.get("require_ssp").isNull() != null) 185 showText("false", "view_require_ssp"); 186 else { 187 String require_ssp = Utils.jsonToString(jobObject.get("require_ssp")); 188 showText(require_ssp, "view_require_ssp"); 189 } 190 showField(jobObject, "dependencies", "view_dependencies"); 191 192 if (staticData.getData("drone_sets_enabled").isBoolean().booleanValue()) { 193 showField(jobObject, "drone_set", "view_drone_set"); 194 } 195 196 String header = Utils.jsonToString(jobObject.get("control_type")) + " control file"; 197 controlFilePanel.getHeaderTextAccessor().setText(header); 198 controlFile.setText(Utils.jsonToString(jobObject.get("control_file"))); 199 200 JSONObject counts = jobObject.get("status_counts").isObject(); 201 String countString = AfeUtils.formatStatusCounts(counts, ", "); 202 showText(countString, "view_status"); 203 abortButton.setVisible(isAnyEntryAbortable(counts)); 204 205 String shard_url = Utils.jsonToString(jobObject.get("shard")).trim(); 206 String job_id = Utils.jsonToString(jobObject.get("id")).trim(); 207 if (shard_url.equals("<null>")){ 208 shard_url = ""; 209 } else { 210 shard_url = "http://" + shard_url; 211 } 212 shard_url = shard_url + "/afe/#tab_id=view_job&object_id=" + job_id; 213 showField(jobObject, "shard", "view_job_on_shard"); 214 getElementById("view_job_on_shard").setAttribute("href", shard_url); 215 getElementById("view_job_on_shard").setInnerHTML(shard_url); 216 217 String jobTag = AfeUtils.getJobTag(jobObject); 218 pointToResults(getResultsURL(jobId), getLogsURL(jobTag), 219 getOldResultsUrl(jobId), getTriageUrl(jobId), 220 getEmbeddedUrl(jobId)); 221 222 String jobTitle = "Job: " + name + " (" + jobTag + ")"; 223 displayObjectData(jobTitle); 224 225 jobFilter.setParameter("job", new JSONNumber(jobId)); 226 hostsTable.refresh(); 227 228 parentJobIdFliter.setParameter("parent_job", new JSONNumber(jobId)); 229 childJobsTable.refresh(); 230 231 jobHistoryTable.clear(); 232 233 getSpongeUrl(jobObject); 234 } 235 236 237 @Override 238 public void onError(JSONObject errorObject) { 239 super.onError(errorObject); 240 resetPage(); 241 } 242 }); 243 } 244 isAnyEntryAbortable(JSONObject statusCounts)245 protected boolean isAnyEntryAbortable(JSONObject statusCounts) { 246 Set<String> statuses = statusCounts.keySet(); 247 for (String status : statuses) { 248 if (!(status.equals("Completed") || 249 status.equals("Failed") || 250 status.equals("Stopped") || 251 status.startsWith("Aborted"))) { 252 return true; 253 } 254 } 255 return false; 256 } 257 258 @Override initialize()259 public void initialize() { 260 super.initialize(); 261 262 idInput.setVisibleLength(5); 263 264 childJobsTable.setRowsPerPage(CHILD_JOBS_PER_PAGE); 265 childJobsTable.setClickable(true); 266 childJobsTable.addListener(new DynamicTableListener() { 267 public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick) { 268 int jobId = (int) row.get("id").isNumber().doubleValue(); 269 childJobsListener.onJobSelected(jobId); 270 } 271 272 public void onTableRefreshed() {} 273 }); 274 275 childJobsTableDecorator.addPaginators(); 276 childJobsSelectionManager = childJobsTableDecorator.addSelectionManager(false); 277 childJobsTable.setWidgetFactory(childJobsSelectionManager); 278 addWidget(childJobsTableDecorator, "child_jobs_table"); 279 280 hostsTable.setRowsPerPage(HOSTS_PER_PAGE); 281 hostsTable.setClickable(true); 282 hostsTable.addListener(new DynamicTableListener() { 283 public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick) { 284 JSONObject host = row.get("host").isObject(); 285 String id = host.get("id").toString(); 286 listener.onHostSelected(id); 287 } 288 289 public void onTableRefreshed() {} 290 }); 291 hostsTable.setWidgetFactory(this); 292 293 hostsTableDecorator.addPaginators(); 294 addTableFilters(); 295 hostsSelectionManager = hostsTableDecorator.addSelectionManager(false); 296 hostsTableDecorator.addTableActionsPanel(new TableActionsListener() { 297 public ContextMenu getActionMenu() { 298 ContextMenu menu = new ContextMenu(); 299 300 menu.addItem("Abort hosts", new Command() { 301 public void execute() { 302 abortSelectedHosts(); 303 } 304 }); 305 306 menu.addItem("Clone job on selected hosts", new Command() { 307 public void execute() { 308 cloneJobOnSelectedHosts(); 309 } 310 }); 311 312 if (hostsSelectionManager.isEmpty()) 313 menu.setEnabled(false); 314 return menu; 315 } 316 }, true); 317 addWidget(hostsTableDecorator, "job_hosts_table"); 318 319 abortButton.addClickHandler(new ClickHandler() { 320 public void onClick(ClickEvent event) { 321 abortJob(); 322 } 323 }); 324 addWidget(abortButton, "view_abort"); 325 326 cloneButton.addClickHandler(new ClickHandler() { 327 public void onClick(ClickEvent event) { 328 cloneJob(); 329 } 330 }); 331 addWidget(cloneButton, "view_clone"); 332 333 tkoResultsFrame.getElement().setAttribute("scrolling", "no"); 334 addWidget(tkoResultsFrame, "tko_results"); 335 336 controlFile.addStyleName("code"); 337 controlFilePanel.setContent(controlFile); 338 addWidget(controlFilePanel, "view_control_file"); 339 340 if (!staticData.getData("drone_sets_enabled").isBoolean().booleanValue()) { 341 AfeUtils.removeElement("view_drone_set_wrapper"); 342 } 343 344 getJobHistoryButton.addClickHandler(new ClickHandler() { 345 public void onClick(ClickEvent event) { 346 getJobHistory(); 347 } 348 }); 349 addWidget(getJobHistoryButton, "view_get_job_history"); 350 351 jobHistoryTable.setClickable(true); 352 jobHistoryTable.addListener(new DataTableListener() { 353 public void onRowClicked(int rowIndex, JSONObject row, boolean isRightClick) { 354 String log_url= row.get("log_url").isString().stringValue(); 355 jobHistoryListener.onJobSelected(log_url); 356 } 357 358 public void onTableRefreshed() {} 359 }); 360 addWidget(jobHistoryTable, "job_history_table"); 361 } 362 addTableFilters()363 protected void addTableFilters() { 364 hostsTable.addFilter(jobFilter); 365 childJobsTable.addFilter(parentJobIdFliter); 366 367 SearchFilter hostnameFilter = new SearchFilter("host__hostname", true); 368 ListFilter statusFilter = new ListFilter("status"); 369 StaticDataRepository staticData = StaticDataRepository.getRepository(); 370 JSONArray statuses = staticData.getData("job_statuses").isArray(); 371 statusFilter.setChoices(Utils.JSONtoStrings(statuses)); 372 373 hostsTableDecorator.addFilter("Hostname", hostnameFilter); 374 hostsTableDecorator.addFilter("Status", statusFilter); 375 } 376 abortJob()377 private void abortJob() { 378 JSONObject params = new JSONObject(); 379 params.put("job__id", new JSONNumber(jobId)); 380 AfeUtils.callAbort(params, new SimpleCallback() { 381 public void doCallback(Object source) { 382 refresh(); 383 } 384 }); 385 } 386 abortSelectedHosts()387 private void abortSelectedHosts() { 388 AfeUtils.abortHostQueueEntries(hostsSelectionManager.getSelectedObjects(), 389 new SimpleCallback() { 390 public void doCallback(Object source) { 391 refresh(); 392 } 393 }); 394 } 395 cloneJob()396 protected void cloneJob() { 397 ContextMenu menu = new ContextMenu(); 398 menu.addItem("Reuse any similar hosts (default)", new Command() { 399 public void execute() { 400 cloneJob(false); 401 } 402 }); 403 menu.addItem("Reuse same specific hosts", new Command() { 404 public void execute() { 405 cloneJob(true); 406 } 407 }); 408 menu.addItem("Use failed and aborted hosts", new Command() { 409 public void execute() { 410 JSONObject queueEntryFilterData = new JSONObject(); 411 String sql = "(status = 'Failed' OR aborted = TRUE OR " + 412 "(host_id IS NULL AND meta_host IS NULL))"; 413 414 queueEntryFilterData.put("extra_where", new JSONString(sql)); 415 cloneJob(true, queueEntryFilterData); 416 } 417 }); 418 419 menu.showAt(cloneButton.getAbsoluteLeft(), 420 cloneButton.getAbsoluteTop() + cloneButton.getOffsetHeight()); 421 } 422 cloneJobOnSelectedHosts()423 private void cloneJobOnSelectedHosts() { 424 Set<JSONObject> hostsQueueEntries = hostsSelectionManager.getSelectedObjects(); 425 JSONArray queueEntryIds = new JSONArray(); 426 for (JSONObject queueEntry : hostsQueueEntries) { 427 queueEntryIds.set(queueEntryIds.size(), queueEntry.get("id")); 428 } 429 430 JSONObject queueEntryFilterData = new JSONObject(); 431 queueEntryFilterData.put("id__in", queueEntryIds); 432 cloneJob(true, queueEntryFilterData); 433 } 434 cloneJob(boolean preserveMetahosts)435 private void cloneJob(boolean preserveMetahosts) { 436 cloneJob(preserveMetahosts, new JSONObject()); 437 } 438 cloneJob(boolean preserveMetahosts, JSONObject queueEntryFilterData)439 private void cloneJob(boolean preserveMetahosts, JSONObject queueEntryFilterData) { 440 JSONObject params = new JSONObject(); 441 params.put("id", new JSONNumber(jobId)); 442 params.put("preserve_metahosts", JSONBoolean.getInstance(preserveMetahosts)); 443 params.put("queue_entry_filter_data", queueEntryFilterData); 444 445 rpcProxy.rpcCall("get_info_for_clone", params, new JsonRpcCallback() { 446 @Override 447 public void onSuccess(JSONValue result) { 448 listener.onCloneJob(result); 449 } 450 }); 451 } 452 getResultsURL(int jobId)453 private String getResultsURL(int jobId) { 454 return "/new_tko/#tab_id=spreadsheet_view&row=hostname&column=test_name&" + 455 "condition=afe_job_id+%253d+" + Integer.toString(jobId) + "&" + 456 "show_incomplete=true"; 457 } 458 getOldResultsUrl(int jobId)459 private String getOldResultsUrl(int jobId) { 460 return "/tko/compose_query.cgi?" + 461 "columns=test&rows=hostname&condition=tag%7E%27" + 462 Integer.toString(jobId) + "-%25%27&title=Report"; 463 } 464 getTriageUrl(int jobId)465 private String getTriageUrl(int jobId) { 466 /* 467 * Having a hard-coded path like this is very unfortunate, but there's no simple way 468 * in the current design to generate this link by code. 469 * 470 * TODO: Redesign the system so that we can generate these links by code. 471 * 472 * Idea: Be able to instantiate a TableView object, ask it to set up to triage this job ID, 473 * and then ask it for the history URL. 474 */ 475 476 return "/new_tko/#tab_id=table_view&columns=test_name%252Cstatus%252Cgroup_count%252C" + 477 "reason&sort=test_name%252Cstatus%252Creason&condition=afe_job_id+%253D+" + jobId + 478 "+AND+status+%253C%253E+%2527GOOD%2527&show_invalid=false"; 479 } 480 getEmbeddedUrl(int jobId)481 private String getEmbeddedUrl(int jobId) { 482 return "/embedded_spreadsheet/EmbeddedSpreadsheetClient.html?afe_job_id=" + jobId; 483 } 484 485 /** 486 * Get the path for a job's raw result files. 487 * @param jobLogsId id-owner, e.g. "172-showard" 488 */ getLogsURL(String jobLogsId)489 protected String getLogsURL(String jobLogsId) { 490 return Utils.getRetrieveLogsUrl(jobLogsId); 491 } 492 pointToResults(String resultsUrl, String logsUrl, String oldResultsUrl, String triageUrl, String embeddedUrl)493 protected void pointToResults(String resultsUrl, String logsUrl, 494 String oldResultsUrl, String triageUrl, 495 String embeddedUrl) { 496 getElementById("results_link").setAttribute("href", resultsUrl); 497 getElementById("old_results_link").setAttribute("href", oldResultsUrl); 498 getElementById("raw_results_link").setAttribute("href", logsUrl); 499 getElementById("triage_failures_link").setAttribute("href", triageUrl); 500 501 tkoResultsFrame.setSize(RESULTS_MAX_WIDTH, RESULTS_MAX_HEIGHT); 502 if (!resultsUrl.equals(NO_URL)) { 503 updateResultsFrame(tkoResultsFrame.getElement(), embeddedUrl); 504 } 505 } 506 updateResultsFrame(Element frame, String embeddedUrl)507 private native void updateResultsFrame(Element frame, String embeddedUrl) /*-{ 508 // Use location.replace() here so that the frame's URL changes don't show up in the browser 509 // window's history 510 frame.contentWindow.location.replace(embeddedUrl); 511 }-*/; 512 513 @Override getNoObjectText()514 protected String getNoObjectText() { 515 return "No job selected"; 516 } 517 518 @Override getFetchControlsElementId()519 protected String getFetchControlsElementId() { 520 return "job_id_fetch_controls"; 521 } 522 523 @Override getDataElementId()524 protected String getDataElementId() { 525 return "view_data"; 526 } 527 528 @Override getTitleElementId()529 protected String getTitleElementId() { 530 return "view_title"; 531 } 532 533 @Override getObjectId()534 protected String getObjectId() { 535 if (jobId == NO_JOB_ID) { 536 return NO_OBJECT; 537 } 538 return Integer.toString(jobId); 539 } 540 541 @Override getElementId()542 public String getElementId() { 543 return "view_job"; 544 } 545 546 @Override setObjectId(String id)547 protected void setObjectId(String id) { 548 int newJobId; 549 try { 550 newJobId = Integer.parseInt(id); 551 } 552 catch (NumberFormatException exc) { 553 throw new IllegalArgumentException(); 554 } 555 this.jobId = newJobId; 556 } 557 createWidget(int row, int cell, JSONObject hostQueueEntry)558 public Widget createWidget(int row, int cell, JSONObject hostQueueEntry) { 559 if (cell == 0) { 560 return hostsSelectionManager.createWidget(row, cell, hostQueueEntry); 561 } 562 563 String executionSubdir = Utils.jsonToString(hostQueueEntry.get("execution_subdir")); 564 if (executionSubdir.equals("")) { 565 // when executionSubdir == "", it's a job that hasn't yet run. 566 return null; 567 } 568 569 JSONObject jobObject = hostQueueEntry.get("job").isObject(); 570 String owner = Utils.jsonToString(jobObject.get("owner")); 571 String basePath = jobId + "-" + owner + "/" + executionSubdir + "/"; 572 573 if (cell == JOB_HOSTS_COLUMNS.length - 1) { 574 return new HTML(getLogsLinkHtml(basePath + "debug", "Debug logs")); 575 } else { 576 return new HTML(getLogsLinkHtml(basePath, "All logs")); 577 } 578 } 579 getLogsLinkHtml(String url, String text)580 private String getLogsLinkHtml(String url, String text) { 581 url = Utils.getRetrieveLogsUrl(url); 582 return "<a target=\"_blank\" href=\"" + url + "\">" + text + "</a>"; 583 } 584 getJobHistory()585 private void getJobHistory() { 586 JSONObject params = new JSONObject(); 587 params.put("job_id", new JSONNumber(jobId)); 588 AfeUtils.callGetJobHistory(params, new SimpleCallback() { 589 public void doCallback(Object result) { 590 jobHistoryTable.clear(); 591 List<JSONObject> rows = new ArrayList<JSONObject>(); 592 JSONArray history = (JSONArray)result; 593 for (int i = 0; i < history.size(); i++) 594 rows.add((JSONObject)history.get(i)); 595 jobHistoryTable.addRows(rows); 596 } 597 }, true); 598 } 599 getSpongeUrl(JSONObject jobObject)600 private void getSpongeUrl(JSONObject jobObject) { 601 getElementById("view_sponge_invocation").setInnerHTML(""); 602 getElementById("view_sponge_invocation_wrapper").getStyle().setProperty("display", "none"); 603 JSONObject params = new JSONObject(); 604 params.put("afe_job_id", new JSONNumber(jobId)); 605 AfeUtils.callGetSpongeUrl(params, new SimpleCallback() { 606 public void doCallback(Object spongeUrl) { 607 if (spongeUrl != null){ 608 getElementById("view_sponge_invocation_wrapper").getStyle().setProperty("display", ""); 609 getElementById("view_sponge_invocation").setAttribute("href", spongeUrl.toString()); 610 getElementById("view_sponge_invocation").setInnerHTML(spongeUrl.toString()); 611 } 612 } 613 }); 614 } 615 } 616