1%{-- 2 - Copyright 2016 SimplifyOps, Inc. (http://simplifyops.com) 3 - 4 - Licensed under the Apache License, Version 2.0 (the "License"); 5 - you may not use this file except in compliance with the License. 6 - You may obtain a copy of the License at 7 - 8 - http://www.apache.org/licenses/LICENSE-2.0 9 - 10 - Unless required by applicable law or agreed to in writing, software 11 - distributed under the License is distributed on an "AS IS" BASIS, 12 - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 - See the License for the specific language governing permissions and 14 - limitations under the License. 15 --}% 16 17<%@ page import="grails.util.Environment" %> 18<html> 19<head> 20 <g:set var="rkey" value="${g.rkey()}" /> 21 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> 22 <meta name="layout" content="base"/> 23 <meta name="tabpage" content="jobs"/> 24 <g:set var="projectName" value="${params.project ?: request.project}"></g:set> 25 <g:set var="projectLabel" value="${session.frameworkLabels?session.frameworkLabels[projectName]:projectName}"/> 26 <title><g:message code="gui.menu.Workflows"/> - <g:enc>${projectLabel}</g:enc></title> 27 28 <asset:javascript src="util/yellowfade.js"/> 29 <g:javascript library="pagehistory"/> 30 <g:javascript library="prototype/effects"/> 31 <asset:javascript src="menu/jobs.js"/> 32 <g:if test="${grails.util.Environment.current==grails.util.Environment.DEVELOPMENT}"> 33 <asset:javascript src="menu/joboptionsTest.js"/> 34 <asset:javascript src="menu/job-remote-optionsTest.js"/> 35 </g:if> 36 <g:embedJSON data="${projectNames ?: []}" id="projectNamesData"/> 37 <g:embedJSON data="${nextSchedListIds ?: []}" id="nextScheduled"/> 38 <g:embedJSON id="pageParams" data="${[project: params.project?:request.project,]}"/> 39 <g:jsMessages code="Node,Node.plural,job.starting.execution,job.scheduling.execution,option.value.required,options.remote.dependency.missing.required,,option.default.button.title,option.default.button.text,option.select.choose.text"/> 40 <!--[if (gt IE 8)|!(IE)]><!--> <g:javascript library="ace/ace"/><!--<![endif]--> 41 <script type="text/javascript"> 42 /** knockout binding for activity */ 43 var pageActivity; 44 function showError(message){ 45 appendText($('error'),message); 46 $("error").show(); 47 } 48 var _jobExecUnloadHandlers=new Array(); 49 function _registerJobExecUnloadHandler(handler){ 50 _jobExecUnloadHandlers.push(handler); 51 } 52 function unloadExec(){ 53 if(_jobExecUnloadHandlers.length>0){ 54 for(var i =0;i<_jobExecUnloadHandlers.length;i++){ 55 _jobExecUnloadHandlers[i].call(); 56 } 57 _jobExecUnloadHandlers.clear(); 58 } 59 60 jQuery('#execDiv').modal('hide'); 61 clearHtml('execDivContent'); 62 63 $('busy').hide(); 64 } 65 function requestError(item,message){ 66 unloadExec(); 67 showError("Failed request: "+item+". Result: "+message); 68 } 69 function loadExec(id,eparams) { 70 $("error").hide(); 71 var params=eparams; 72 if(!params){ 73 params={id:id}; 74 } 75 jQuery('#execDivContent').load(_genUrl(appLinks.scheduledExecutionExecuteFragment, params), 76 function(response,status,xhr){ 77 if (status == "success") { 78 loadedFormSuccess(!!id,id); 79 } else { 80 requestError("executeFragment for [" + id + "]",xhr.statusText); 81 } 82 }); 83 } 84 function execSubmit(elem, target) { 85 var data = new FormData(jQuery('#' + elem + ' form')[0]); 86 jQuery.ajax({ 87 url: target, 88 type: 'POST', 89 data: data, 90 contentType: false, 91 dataType: 'json', 92 processData: false, 93 success: function (result) { 94 if (result.id) { 95 if (result.follow && result.href) { 96 document.location = result.href; 97 } else { 98 if (!pageActivity.selected()) { 99 pageActivity.activateNowRunningTab(); 100 } 101 unloadExec(); 102 } 103 } else if (result.error === 'invalid') { 104 // reload form for validation 105 loadExec(null, Form.serialize(elem) + "&dovalidate=true"); 106 } else { 107 unloadExec(); 108 showError(result.message ? result.message : result.error ? result.error : "Failed request"); 109 } 110 }, 111 error: function (data, jqxhr, err) { 112 requestError("runJobInline", err); 113 } 114 }); 115 } 116 function loadedFormSuccess(doShow,id){ 117 if ($('execFormCancelButton')) { 118 Event.observe($('execFormCancelButton'),'click',function(evt) { 119 Event.stop(evt); 120 unloadExec(); 121 return false; 122 },false); 123 $('execFormCancelButton').name = "_x"; 124 } 125 if ($('execFormRunButton')) { 126 Event.observe($('execFormRunButton'),'click', function(evt) { 127 Event.stop(evt); 128 execSubmit('execDivContent', appLinks.scheduledExecutionRunJobInline); 129 $('formbuttons').loading(message('job.starting.execution')); 130 return false; 131 },false); 132 } 133 jQuery('#showScheduler').on('shown.bs.popover', function() { 134 if ($('scheduleAjaxButton')) { 135 Event.observe($('scheduleAjaxButton'), 'click', function(evt) { 136 Event.stop(evt); 137 if (isValidDate()) { 138 toggleAlert(true); 139 execSubmit('execDivContent', 140 appLinks.scheduledExecutionScheduleJobInline); 141 $('formbuttons').loading(message('job.scheduling.execution')); 142 } else { 143 toggleAlert(false); 144 } 145 return false; 146 }, false); 147 } 148 }); 149 150 //setup option handling 151 //setup option edit 152 var joboptiondata = loadJsonData('jobOptionData'); 153 var joboptions = new JobOptions(joboptiondata); 154 155 if (document.getElementById('optionSelect')) { 156 ko.applyBindings(joboptions, document.getElementById('optionSelect')); 157 } 158 159 var remoteoptionloader = new RemoteOptionLoader({ 160 url: "${createLink(controller:'scheduledExecution',action:'loadRemoteOptionValues',params:[format:'json'])}", 161 id:id, 162 fieldPrefix: "extra.option." 163 }); 164 var remotecontroller = new RemoteOptionController({ 165 loader: remoteoptionloader, 166 }); 167 remotecontroller.setupOptions(joboptions); 168 169 remotecontroller.loadData(loadJsonData('remoteOptionData')); 170 if (typeof(_registerJobExecUnloadHandler) == 'function') { 171 _registerJobExecUnloadHandler(remotecontroller.unsubscribeAll); 172 } 173 joboptions.remoteoptions = remotecontroller; 174 remotecontroller.begin(); 175 176 jQuery('input').on('keydown', function (evt) { 177 return noenter(evt); 178 }); 179 if(doShow){ 180 jQuery('#execDiv').modal('show'); 181 } 182 $('busy').hide(); 183 } 184 185 186 187 188 //set box filterselections 189 190 function _setFilterSuccess(data,name){ 191 if(data){ 192 var bfilters=data.filterpref; 193 //reload page 194 document.location=_genUrl(appLinks.menuJobs , bfilters[name] ? {filterName:bfilters[name]} : {}); 195 } 196 } 197 198 199 /** now running section update */ 200 function _pageUpdateNowRunning(count){ 201 } 202 var lastRunExec=0; 203 /** 204 * Handle embedded content updates 205 */ 206 function _updateBoxInfo(name,data){ 207 if(name==='events' && data.lastDate){ 208 histControl.setHiliteSince(data.lastDate); 209 } 210 if (name == 'nowrunning' && data.lastExecId && data.lastExecId != lastRunExec) { 211 lastRunExec = data.lastExecId; 212 } 213 } 214 215 ///////////// 216 // Job context detail popup code 217 ///////////// 218 219 var doshow=false; 220 var popvis=false; 221 var lastHref; 222 var targetLink; 223 function popJobDetails(elem){ 224 if(doshow && $('jobIdDetailHolder')){ 225 new MenuController().showRelativeTo(elem,$('jobIdDetailHolder')); 226 popvis=true; 227 if(targetLink){ 228 $(targetLink).removeClassName('glow'); 229 targetLink=null; 230 } 231 $(elem).addClassName('glow'); 232 targetLink=elem; 233 } 234 } 235 var motimer; 236 var mltimer; 237 function bubbleMouseover(evt){ 238 if(mltimer){ 239 clearTimeout(mltimer); 240 mltimer=null; 241 } 242 } 243 function jobLinkMouseover(elem,evt){ 244 if(mltimer){ 245 clearTimeout(mltimer); 246 mltimer=null; 247 } 248 if(motimer){ 249 clearTimeout(motimer); 250 motimer=null; 251 } 252 if(popvis && lastHref===elem.href){ 253 return; 254 } 255 var delay=1500; 256 if(popvis){ 257 delay=0; 258 } 259 motimer=setTimeout(showJobDetails.curry(elem),delay); 260 } 261 function doMouseout(){ 262 if(popvis && $('jobIdDetailHolder')){ 263 popvis=false; 264 Try.these( 265 function(){ 266 jQuery('#jobIdDetailHolder').fadeOut('fast'); 267 }, 268 function(){$('jobIdDetailHolder').hide();} 269 ); 270 } 271 if(targetLink){ 272 $(targetLink).removeClassName('glow'); 273 targetLink=null; 274 } 275 } 276 function jobLinkMouseout(elem,evt){ 277 //hide job details 278 if(motimer){ 279 clearTimeout(motimer); 280 motimer=null; 281 } 282 doshow=false; 283 mltimer=setTimeout(doMouseout,0); 284 } 285 function showJobDetails(elem){ 286 //get url 287 var href=elem.href || elem.getAttribute('data-href'); 288 lastHref=href; 289 doshow=true; 290 //match is id 291 var matchId = jQuery(elem).data('jobId'); 292 if(!matchId){ 293 return; 294 } 295 var viewdom=$('jobIdDetailHolder'); 296 var bcontent=$('jobIdDetailContent'); 297 if(viewdom){ 298 viewdom.parentNode.removeChild(viewdom); 299 viewdom=null; 300 } 301 if(!viewdom){ 302 viewdom = $(document.createElement('div')); 303 viewdom.addClassName('bubblewrap'); 304 viewdom.setAttribute('id','jobIdDetailHolder'); 305 viewdom.setAttribute('style','display:none;width:600px;height:250px;'); 306 307 Event.observe(viewdom,'click',function(evt){ 308 evt.stopPropagation(); 309 },false); 310 311 var btop = new Element('div'); 312 btop.addClassName('bubbletop'); 313 viewdom.appendChild(btop); 314 bcontent = new Element('div'); 315 bcontent.addClassName('bubblecontent'); 316 bcontent.setAttribute('id','jobIdDetailContent'); 317 viewdom.appendChild(bcontent); 318 document.body.appendChild(viewdom); 319 Event.observe(viewdom,'mouseover',bubbleMouseover); 320 Event.observe(viewdom,'mouseout',jobLinkMouseout.curry(viewdom)); 321 } 322 bcontent.loading(); 323 var jobNodeFilters; 324 jQuery.ajax({ 325 dataType:'json', 326 url:_genUrl(appLinks.scheduledExecutionDetailFragmentAjax, {id: matchId}), 327 success:function(data,status,xhr){ 328 var params={}; 329 if(data.job && data.job.doNodeDispatch) { 330 if (data.job.filter) { 331 params.filter = data.job.filter; 332 } 333 }else{ 334 params.localNodeOnly=true; 335 params.emptyMode='localnode'; 336 } 337 jobNodeFilters=initJobNodeFilters(params); 338 } 339 }).done( 340 function(){ 341 jQuery('#jobIdDetailContent').load(_genUrl(appLinks.scheduledExecutionDetailFragment, {id: matchId}), 342 function(response,status,xhr){ 343 if (status=='success') { 344 var wrapDiv = jQuery('#jobIdDetailHolder').find('.ko-wrap')[0]; 345 if(wrapDiv) { 346 ko.applyBindings(jobNodeFilters, wrapDiv); 347 } 348 popJobDetails(elem); 349 $('jobIdDetailContent').select('.apply_ace').each(function (t) { 350 _applyAce(t); 351 }); 352 }else{ 353 clearHtml(bcontent); 354 viewdom.hide(); 355 } 356 }); 357 } 358 ); 359 360 } 361 362 function initJobIdLinks(){ 363 $$('.hover_show_job_info').each(function(e){ 364 Event.observe(e,'mouseover',jobLinkMouseover.curry(e)); 365 Event.observe(e,'mouseout',jobLinkMouseout.curry(e)); 366 }); 367 368 jQuery('.act_job_action_dropdown').click(function(){ 369 var id=jQuery(this).data('jobId'); 370 var el=jQuery(this).parent().find('.dropdown-menu'); 371 el.load( 372 _genUrl(appLinks.scheduledExecutionActionMenuFragment,{id:id}) 373 ); 374 }); 375 } 376 function filterToggle(evt) { 377 ['${enc(js:rkey)}filter','${enc(js:rkey)}filter-toggle'].each(Element.toggle); 378 } 379 function filterToggleSave(evt) { 380 ['${enc(js:rkey)}filter','${enc(js:rkey)}fsave'].each(Element.show); 381 ['${enc(js:rkey)}filter-toggle','${enc(js:rkey)}fsavebtn'].each(Element.hide); 382 } 383 function init(){ 384 <g:if test="${!(grailsApplication.config.rundeck?.gui?.enableJobHoverInfo in ['false',false])}"> 385 initJobIdLinks(); 386 </g:if> 387 388 PageActionHandlers.registerHandler('job_delete_single',function(el){ 389 bulkeditor.activateActionForJob(bulkeditor.DELETE,el.data('jobId')); 390 }); 391 PageActionHandlers.registerHandler('enable_job_execution_single',function(el){ 392 bulkeditor.activateActionForJob(bulkeditor.ENABLE_EXECUTION,el.data('jobId')); 393 }); 394 PageActionHandlers.registerHandler('disable_job_execution_single',function(el){ 395 bulkeditor.activateActionForJob(bulkeditor.DISABLE_EXECUTION,el.data('jobId')); 396 }); 397 PageActionHandlers.registerHandler('disable_job_schedule_single',function(el){ 398 bulkeditor.activateActionForJob(bulkeditor.DISABLE_SCHEDULE,el.data('jobId')); 399 }); 400 PageActionHandlers.registerHandler('enable_job_schedule_single',function(el){ 401 bulkeditor.activateActionForJob(bulkeditor.ENABLE_SCHEDULE,el.data('jobId')); 402 }); 403 404 PageActionHandlers.registerHandler('copy_other_project',function(el){ 405 jQuery('#jobid').val(el.data('jobId')); 406 jQuery('#selectProject').modal(); 407 }); 408 409 410 Event.observe(document.body,'click',function(evt){ 411 //click outside of popup bubble hides it 412 doMouseout(); 413 },false); 414 Event.observe(document,'keydown',function(evt){ 415 //escape key hides popup bubble 416 if(evt.keyCode===27 ){ 417 doMouseout(); 418 } 419 return true; 420 },false); 421 422 $$('.obs_filtertoggle').each(function(e) { 423 Event.observe(e, 'click', filterToggle); 424 }); 425 $$('.obs_filtersave').each(function(e) { 426 Event.observe(e, 'click', filterToggleSave); 427 }); 428 } 429 /** 430 * Possible actions for bulk edit jobs, to present in modal dialog 431 * @constructor 432 */ 433 function BulkEditor(){ 434 var self=this; 435 self.DISABLE_SCHEDULE = 'disable_schedule'; 436 self.ENABLE_SCHEDULE = 'enable_schedule'; 437 self.ENABLE_EXECUTION= 'enable_execution'; 438 self.DISABLE_EXECUTION= 'disable_execution'; 439 self.DELETE= 'delete'; 440 self.action=ko.observable(null); 441 self.enabled=ko.observable(false); 442 self.beginEdit=function(){ 443 self.expandAllComponents(); 444 self.enabled(true); 445 }; 446 self.cancelEdit=function(){ 447 self.enabled(false); 448 self.selectNone(); 449 }; 450 self.disableSchedule=function(){ 451 452 self.action(self.DISABLE_SCHEDULE); 453 }; 454 self.isDisableSchedule=ko.pureComputed(function(){ 455 return self.action()===self.DISABLE_SCHEDULE; 456 }); 457 self.enableSchedule=function(){ 458 self.action(self.ENABLE_SCHEDULE); 459 }; 460 self.isEnableSchedule=ko.pureComputed(function(){ 461 return self.action()===self.ENABLE_SCHEDULE; 462 }); 463 self.enableExecution=function(){ 464 self.action(self.ENABLE_EXECUTION); 465 }; 466 self.isEnableExecution=ko.pureComputed(function(){ 467 return self.action()===self.ENABLE_EXECUTION; 468 }); 469 self.disableExecution=function(){ 470 self.action(self.DISABLE_EXECUTION); 471 }; 472 self.isDisableExecution=ko.pureComputed(function(){ 473 return self.action()===self.DISABLE_EXECUTION; 474 }); 475 self.actionDelete=function(){ 476 self.action(self.DELETE); 477 }; 478 self.isDelete=ko.pureComputed(function(){ 479 return self.action()===self.DELETE; 480 }); 481 self.cancel=function(){ 482 self.action(null); 483 }; 484 485 self.setCheckboxValues=function(ids){ 486 //check only the checkbox with this job id by passing an array 487 jQuery('.jobbulkeditfield :input[name=ids]').val(ids); 488 }; 489 self.checkboxesForGroup=function(group){ 490 return jQuery('.jobbulkeditfield input[type=checkbox][data-job-group="'+group+'"]'); 491 }; 492 self.allCheckboxes=function(group){ 493 return jQuery('.jobbulkeditfield input[type=checkbox]'); 494 }; 495 self.jobGroupSelectAll=function(e){ 496 var jgroup=jQuery(e).data('job-group'); 497 if(jgroup){ 498 self.checkboxesForGroup(jgroup).prop('checked', true); 499 } 500 }; 501 502 self.jobGroupSelectNone=function(e){ 503 var jgroup=jQuery(e).data('job-group'); 504 if(jgroup){ 505 self.checkboxesForGroup(jgroup).prop('checked', false); 506 } 507 }; 508 self.expandAllComponents=function(){ 509 jQuery('.expandComponent').show(); 510 }; 511 self.collapseAllComponents=function(){ 512 jQuery('.topgroup .expandComponent').hide(); 513 }; 514 self.selectAll=function(){ 515 self.expandAllComponents(); 516 self.allCheckboxes().prop('checked', true); 517 }; 518 self.selectNone=function(){ 519 self.expandAllComponents(); 520 self.allCheckboxes().prop('checked', false); 521 }; 522 self.toggleModal=function(){ 523 jQuery('#bulk_del_confirm').modal('toggle'); 524 }; 525 self.activateActionForJob=function(action,jobid){ 526 self.setCheckboxValues([jobid]); 527 self.beginEdit(); 528 self.action(action); 529 self.toggleModal(); 530 }; 531 532 self.scmExportEnabled = ko.observable(false); 533 self.scmImportEnabled = ko.observable(false); 534 self.scmStatus = ko.observable(null); 535 self.scmImportJobStatus = ko.observable(null); 536 self.scmExportStatus = ko.observable(null); 537 self.scmImportStatus = ko.observable(null); 538 self.scmExportActions = ko.observable(null); 539 self.scmImportActions = ko.observable(null); 540 self.scmExportRenamed = ko.observable(null); 541 self.isExportEnabled=ko.pureComputed(function(){ 542 return self.scmExportEnabled(); 543 }); 544 545 self.jobSynchState = function(jobid){ 546 var exportStatus = null; 547 var importStatus = null; 548 if(self.scmStatus() && self.scmStatus()[jobid]){ 549 exportStatus = self.scmStatus()[jobid].synchState.name; 550 } 551 if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){ 552 importStatus = self.scmImportJobStatus()[jobid].synchState.name; 553 } 554 if(!exportStatus || exportStatus == "CLEAN"){ 555 return importStatus; 556 }else{ 557 return exportStatus 558 } 559 }; 560 561 self.displayBadge = function(jobid){ 562 var displayExport = false; 563 var displayImport = false; 564 if(self.scmExportEnabled() || self.scmImportEnabled()){ 565 if(self.scmStatus() && self.scmStatus()[jobid]){ 566 displayExport = self.scmStatus()[jobid].synchState.name != "CLEAN"; 567 } 568 if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){ 569 displayImport = self.scmImportJobStatus()[jobid].synchState.name != "CLEAN"; 570 } 571 } 572 return (displayExport || displayImport); 573 }; 574 575 self.jobText = function(jobid){ 576 var exportStatus = null; 577 var importStatus = null; 578 var text = null; 579 if(self.scmStatus() && self.scmStatus()[jobid]){ 580 exportStatus = self.scmStatus()[jobid].synchState.name; 581 switch(exportStatus) { 582 case "EXPORT_NEEDED": 583 text = "${message(code: "scm.export.status.EXPORT_NEEDED.description")}"; 584 break; 585 case "CREATE_NEEDED": 586 text = "${message(code: "scm.export.status.CREATE_NEEDED.description")}"; 587 break; 588 case "CLEAN": 589 text = "${message(code: "scm.export.status.CLEAN.description")}"; 590 break; 591 default: 592 text = exportStatus; 593 } 594 } 595 if(self.scmImportJobStatus() && self.scmImportJobStatus()[jobid]){ 596 if(text){ 597 text +=', '; 598 }else{ 599 text = ''; 600 } 601 importStatus = self.scmImportJobStatus()[jobid].synchState.name; 602 switch(importStatus) { 603 case "IMPORT_NEEDED": 604 text += "${message(code: "scm.import.status.IMPORT_NEEDED.description")}"; 605 break; 606 case "DELETE_NEEDED": 607 text += "${message(code: "scm.import.status.DELETE_NEEDED.description")}"; 608 break; 609 case "CLEAN": 610 text += "${message(code: "scm.import.status.CLEAN.description")}"; 611 break; 612 case "REFRESH_NEEDED": 613 text += "${message(code: "scm.import.status.REFRESH_NEEDED.description")}"; 614 break; 615 case "UNKNOWN": 616 text += "${message(code: "scm.import.status.UNKNOWN.description")}"; 617 break; 618 default: 619 text += importStatus; 620 } 621 622 } 623 return text; 624 }; 625 626 self.jobClass = function(jobid){ 627 switch(self.jobSynchState(jobid)) { 628 case "EXPORT_NEEDED": 629 return "text-info"; 630 break; 631 case "CREATE_NEEDED": 632 return "text-success"; 633 break; 634 case "UNKNOWN": 635 return "text-muted"; 636 break; 637 case "IMPORT_NEEDED": 638 return "text-warning"; 639 break; 640 case "REFRESH_NEEDED": 641 return "text-warning"; 642 break; 643 case "DELETED": 644 return "text-danger"; 645 break; 646 case "CLEAN": 647 return "text-muted"; 648 break; 649 } 650 return 'text-muted'; 651 }; 652 653 self.jobIcon = function(jobid){ 654 switch(self.jobSynchState(jobid)) { 655 case "EXPORT_NEEDED": 656 return "glyphicon-exclamation-sign"; 657 break; 658 case "CREATE_NEEDED": 659 return "glyphicon-exclamation-sign"; 660 break; 661 case "UNKNOWN": 662 return "glyphicon-question-sign"; 663 break; 664 case "IMPORT_NEEDED": 665 return "glyphicon-exclamation-sign"; 666 break; 667 case "REFRESH_NEEDED": 668 return "glyphicon-exclamation-sign"; 669 break; 670 case "DELETED": 671 return "glyphicon-minus-sign"; 672 break; 673 case "CLEAN": 674 return "glyphicon-ok"; 675 break; 676 } 677 return 'glyphicon-plus'; 678 }; 679 680 self.exportMessage = function(){ 681 if(self.scmExportStatus()){ 682 return self.scmExportStatus().message; 683 } 684 return null; 685 }; 686 self.importMessage = function(){ 687 if(self.scmImportStatus()){ 688 return self.scmImportStatus().message; 689 } 690 return null; 691 }; 692 693 self.exportState = function(){ 694 if(self.scmExportStatus()){ 695 return self.scmExportStatus().state.name; 696 } 697 return null; 698 }; 699 self.importState = function(){ 700 if(self.scmImportStatus()){ 701 return self.scmImportStatus().state.name; 702 } 703 return null; 704 }; 705 706 self.jobCommit = function(jobid){ 707 return self.scmExportEnabled(); 708 }; 709 710 self.defaultExportText = function(){ 711 if(self.exportState()) { 712 var text = null; 713 switch(self.exportState()) { 714 case "EXPORT_NEEDED": 715 text = "${message(code: "scm.export.status.EXPORT_NEEDED.display.text")}"; 716 break; 717 case "CREATE_NEEDED": 718 text = "${message(code: "scm.export.status.CREATE_NEEDED.display.text")}"; 719 break; 720 case "REFRESH_NEEDED": 721 text = "${message(code: "scm.export.status.REFRESH_NEEDED.display.text")}"; 722 break; 723 case "DELETED": 724 text = "${message(code: "scm.export.status.DELETED.display.text")}"; 725 break; 726 case "CLEAN": 727 text = "${message(code: "scm.export.status.CLEAN.display.text")}"; 728 break; 729 } 730 if(!text){ 731 text = self.exportState(); 732 } 733 return text; 734 } 735 return null; 736 }; 737 738 self.defaultImportText = function(){ 739 if(self.importState()) { 740 var text = null; 741 switch(self.importState()) { 742 case "IMPORT_NEEDED": 743 text = "${message(code: "scm.import.status.IMPORT_NEEDED.display.text")}"; 744 break; 745 case "REFRESH_NEEDED": 746 text = "${message(code: "scm.import.status.REFRESH_NEEDED.display.text")}"; 747 break; 748 case "UNKNOWN": 749 text = "${message(code: "scm.import.status.UNKNOWN.display.text")}"; 750 break; 751 case "CLEAN": 752 text = "${message(code: "scm.import.status.CLEAN.display.text")}"; 753 break; 754 } 755 if(!text){ 756 text = self.importState(); 757 } 758 return text; 759 } 760 return null; 761 }; 762 763 self.defaultDisplayText = function(){ 764 if(self.exportState() != 'CLEAN'){ 765 return self.defaultExportText(); 766 }else{ 767 return self.defaultImportText(); 768 } 769 }; 770 771 772 self.displayExport = function(){ 773 return (self.exportState() && self.exportState() != 'CLEAN'); 774 }; 775 776 self.displayImport = function(){ 777 return (self.importState() && self.importState() != 'CLEAN'); 778 }; 779 780 self.displaySCMMEssage = function(){ 781 return (self.displayExport() || self.displayImport()); 782 }; 783 784 } 785 786 787 788 789 790 791 var bulkeditor; 792 jQuery(document).ready(function () { 793 init(); 794 if (jQuery('#activity_section')) { 795 pageActivity = new History(appLinks.reportsEventsAjax, appLinks.menuNowrunningAjax); 796 ko.applyBindings(pageActivity, document.getElementById('activity_section')); 797 setupActivityLinks('activity_section', pageActivity); 798 } 799 jQuery(document).on('click','.act_execute_job',function(evt){ 800 evt.preventDefault(); 801 loadExec(jQuery(this).data('jobId')); 802 }); 803 $$('#wffilterform input').each(function(elem){ 804 if(elem.type=='text'){ 805 elem.observe('keypress',noenter); 806 } 807 }); 808 bulkeditor=new BulkEditor(); 809 ko.applyBindings(bulkeditor,document.getElementById('bulk_del_confirm')); 810 ko.applyBindings(bulkeditor,document.getElementById('bulk_edit_panel')); 811 ko.applyBindings(bulkeditor,document.getElementById('job_action_menu')); 812 ko.applyBindings(bulkeditor,document.getElementById('job_group_tree')); 813 ko.applyBindings(bulkeditor,document.getElementById('group_controls')); 814 ko.applyBindings(bulkeditor,document.getElementById('scm_message')); 815 ko.applyBindings(bulkeditor,document.getElementById('scmStatusPopoverOK')); 816 817 818 819 820 jQuery(document).on('click','#togglescm',function(evt){ 821 evt.preventDefault(); 822 jQuery.ajax({ 823 dataType:'json', 824 method: "POST", 825 url:_genUrl(appLinks.togglescm), 826 params:nextScheduled, 827 success:function(data,status,xhr){ 828 console.log(data); 829 } 830 }); 831 }); 832 833 var pageParams = loadJsonData('pageParams'); 834 var nextScheduled = loadJsonData('nextScheduled'); 835 var nextSchedList=""; 836 for(var i=0; i< nextScheduled.length; i++){ 837 nextSchedList = nextSchedList+nextScheduled[i]+","; 838 } 839 840 jQuery.ajax({ 841 dataType:'json', 842 method: "POST", 843 url:_genUrl(appLinks.scmjobs, {nextScheduled:nextSchedList}), 844 params:nextScheduled, 845 success:function(data,status,xhr){ 846 bulkeditor.scmExportEnabled(data.scmExportEnabled); 847 bulkeditor.scmStatus(data.scmStatus); 848 bulkeditor.scmExportStatus(data.scmExportStatus); 849 bulkeditor.scmExportActions(data.scmExportActions); 850 bulkeditor.scmExportRenamed(data.scmExportRenamed); 851 852 bulkeditor.scmImportEnabled(data.scmImportEnabled); 853 bulkeditor.scmImportJobStatus(data.scmImportJobStatus); 854 bulkeditor.scmImportStatus(data.scmImportStatus); 855 bulkeditor.scmImportActions(data.scmImportActions); 856 } 857 }); 858 }); 859 860 861 </script> 862 863 <asset:javascript src="util/yellowfade.js"/> 864 <asset:javascript src="menu/joboptions.js"/> 865 <style type="text/css"> 866 .error{ 867 color:red; 868 } 869 870 #histcontent table{ 871 width:100%; 872 } 873 </style> 874</head> 875<body> 876 877 878<g:if test="${flash.bulkJobResult?.errors}"> 879 <div class="alert alert-dismissable alert-warning"> 880 <a class="close" data-dismiss="alert" href="#" aria-hidden="true">×</a> 881 <ul> 882 <g:if test="${flash.bulkJobResult.errors instanceof org.springframework.validation.Errors}"> 883 <g:renderErrors bean="${flash.bulkJobResult.errors}" as="list"/> 884 </g:if> 885 <g:else> 886 <g:each in="${flash.bulkJobResult.errors*.message}" var="message"> 887 <li><g:autoLink>${message}</g:autoLink></li> 888 </g:each> 889 </g:else> 890 </ul> 891 </div> 892</g:if> 893<g:if test="${flash.bulkJobResult?.success}"> 894 <div class="alert alert-dismissable alert-info"> 895 <a class="close" data-dismiss="alert" href="#" aria-hidden="true">×</a> 896 <ul> 897 <g:each in="${flash.bulkJobResult.success*.message}" var="message"> 898 <li><g:autoLink>${message}</g:autoLink></li> 899 </g:each> 900 </ul> 901 </div> 902</g:if> 903<div class="runbox primary jobs" id="indexMain"> 904 <div id="error" class="alert alert-danger" style="display:none;"></div> 905 <g:render template="workflowsFull" model="${[jobExpandLevel:jobExpandLevel,jobgroups:jobgroups,wasfiltered:wasfiltered?true:false, clusterMap: clusterMap,nextExecutions:nextExecutions,jobauthorizations:jobauthorizations,authMap:authMap,nowrunningtotal:nowrunningtotal,max:max,offset:offset,paginateParams:paginateParams,sortEnabled:true,rkey:rkey, clusterModeEnabled:clusterModeEnabled]}"/> 906</div> 907<div class="modal fade" id="execDiv" role="dialog" aria-labelledby="deleteFilterModalLabel" aria-hidden="true"> 908 <div class="modal-dialog modal-lg"> 909 <div class="modal-content"> 910 <div class="modal-header"> 911 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 912 <h4 class="modal-title" id="deleteFilterModalLabel"><g:message code="job.execute.action.button" /></h4> 913 </div> 914 915 <div class="" id="execDivContent"> 916 917 918 </div> 919</div> 920</div> 921</div> 922 923<g:render template="/menu/copyModal" 924 model="[projectNames: projectNames]"/> 925 926<div class="row row-space" id="activity_section"> 927 <div class="col-sm-12 "> 928 <h4 class="text-muted "><g:message code="page.section.Activity.for.jobs" /></h4> 929 <g:render template="/reports/activityLinks" 930 model="[filter: [projFilter: params.project ?: request.project, jobIdFilter: '!null',], knockoutBinding: true, showTitle:true]"/> 931 </div> 932</div> 933</body> 934</html> 935