1*4882a593Smuzhiyun{% extends "base.html" %} 2*4882a593Smuzhiyun{% load projecttags %} 3*4882a593Smuzhiyun{% load project_url_tag %} 4*4882a593Smuzhiyun{% load objects_to_dictionaries_filter %} 5*4882a593Smuzhiyun{% load humanize %} 6*4882a593Smuzhiyun{% load field_values_filter %} 7*4882a593Smuzhiyun{% block pagecontent %} 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun <script> 10*4882a593Smuzhiyun var configVarUrl = "{% url 'configvars' build.id %}"; 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun $(document).ready(function(){ 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun $("#delete-build-confirm").click(function(){ 15*4882a593Smuzhiyun libtoaster.disableAjaxLoadingTimer(); 16*4882a593Smuzhiyun $(this).find('[data-role="submit-state"]').hide(); 17*4882a593Smuzhiyun $(this).find('[data-role="loading-state"]').show(); 18*4882a593Smuzhiyun $(this).attr("disabled", "disabled"); 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun /* Make the modal non cancelable while delete is in progress */ 21*4882a593Smuzhiyun $('#delete-build-modal button[data-dismiss="modal"]').hide(); 22*4882a593Smuzhiyun 23*4882a593Smuzhiyun $.ajax({ 24*4882a593Smuzhiyun type: 'DELETE', 25*4882a593Smuzhiyun url: "{% url 'xhr_build' build.id %}", 26*4882a593Smuzhiyun headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, 27*4882a593Smuzhiyun success: function (data) { 28*4882a593Smuzhiyun if (data.error !== "ok") { 29*4882a593Smuzhiyun console.warn(data.error); 30*4882a593Smuzhiyun } else { 31*4882a593Smuzhiyun libtoaster.setNotification("build-deleted", 32*4882a593Smuzhiyun $("#deleted-build-message").html()); 33*4882a593Smuzhiyun window.location.replace(data.gotoUrl); 34*4882a593Smuzhiyun } 35*4882a593Smuzhiyun }, 36*4882a593Smuzhiyun error: function (data) { 37*4882a593Smuzhiyun console.warn(data); 38*4882a593Smuzhiyun } 39*4882a593Smuzhiyun }); 40*4882a593Smuzhiyun }); 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun $('#breadcrumb > li').append('<span class="divider">→</span>'); 44*4882a593Smuzhiyun $('#breadcrumb > li:last').addClass("active"); 45*4882a593Smuzhiyun $('#breadcrumb > li:last > span').remove(); 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun $("#build-menu li a").each(function(){ 48*4882a593Smuzhiyun /* Set the page active state in the Build menu */ 49*4882a593Smuzhiyun var currentUrl = window.location.href.split('?')[0]; 50*4882a593Smuzhiyun if (currentUrl === $(this).prop("href")){ 51*4882a593Smuzhiyun $(this).parent().addClass("active"); 52*4882a593Smuzhiyun } else { 53*4882a593Smuzhiyun /* Special case the configvar as this is part of configuration 54*4882a593Smuzhiyun * page but is a separate url 55*4882a593Smuzhiyun */ 56*4882a593Smuzhiyun if (window.location.pathname === configVarUrl){ 57*4882a593Smuzhiyun $("#menu-configuration").addClass("active"); 58*4882a593Smuzhiyun } else { 59*4882a593Smuzhiyun $(this).parent().removeClass("active"); 60*4882a593Smuzhiyun } 61*4882a593Smuzhiyun } 62*4882a593Smuzhiyun }); 63*4882a593Smuzhiyun }); 64*4882a593Smuzhiyun </script> 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun<span style="display:none" id="deleted-build-message"> 67*4882a593Smuzhiyun You have deleted 1 build: <strong>{{build.get_sorted_target_list|field_values:"target"|join:", "}} {{build.machine}}</strong> completed on <strong>{{build.completed_on|date:"d/m/y H:i"}}</strong> 68*4882a593Smuzhiyun</span> 69*4882a593Smuzhiyun 70*4882a593Smuzhiyun<div class="modal fade" tabindex="-1" role="dialog" id="delete-build-modal" style="display: none;" data-backdrop="static" data-keyboard="false"> 71*4882a593Smuzhiyun <div class="modal-dialog"> 72*4882a593Smuzhiyun <div class="modal-content"> 73*4882a593Smuzhiyun <div class="modal-body"> 74*4882a593Smuzhiyun <p>Are you sure you want to delete the build <strong>{{build.get_sorted_target_list|field_values:"target"|join:", "}} {{build.machine}}</strong> completed on <strong>{{build.completed_on|date:"d/m/y H:i"}}</strong>?</p> 75*4882a593Smuzhiyun </div> 76*4882a593Smuzhiyun <div class="modal-footer"> 77*4882a593Smuzhiyun <button id="delete-build-confirm" class="btn btn-primary btn-large"> 78*4882a593Smuzhiyun <span data-role="submit-state">Delete build</span> 79*4882a593Smuzhiyun <span data-role="loading-state" style="display:none"> 80*4882a593Smuzhiyun <span class="fa-pulse"> 81*4882a593Smuzhiyun <i class="icon-spinner"></i> 82*4882a593Smuzhiyun </span> 83*4882a593Smuzhiyun Deleting build... 84*4882a593Smuzhiyun </span> 85*4882a593Smuzhiyun </button> 86*4882a593Smuzhiyun <button type="button" class="btn btn-link" data-dismiss="modal">Cancel</button> 87*4882a593Smuzhiyun </div> 88*4882a593Smuzhiyun </div><!-- /.modal-content --> 89*4882a593Smuzhiyun </div><!-- /.modal-dialog --> 90*4882a593Smuzhiyun</div> <!-- / modal --> 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun<div class="row"> 93*4882a593Smuzhiyun <!-- breadcrumbs --> 94*4882a593Smuzhiyun <div class="col-md-12"> 95*4882a593Smuzhiyun <ul class="breadcrumb" id="breadcrumb"> 96*4882a593Smuzhiyun <li><a href="{% project_url build.project %}">{{build.project.name}}</a></li> 97*4882a593Smuzhiyun {% if not build.project.is_default %} 98*4882a593Smuzhiyun <li><a href="{% url 'projectbuilds' build.project.id %}">Builds</a></li> 99*4882a593Smuzhiyun {% endif %} 100*4882a593Smuzhiyun <li> 101*4882a593Smuzhiyun {% block parentbreadcrumb %} 102*4882a593Smuzhiyun <a href="{%url 'builddashboard' build.pk%}"> 103*4882a593Smuzhiyun {{build.get_sorted_target_list.0.target}} {% if build.target_set.all.count > 1 %}(+{{build.target_set.all.count|add:"-1"}}){% endif %} {{build.machine}} ({{build.completed_on|date:"d/m/y H:i"}}) 104*4882a593Smuzhiyun </a> 105*4882a593Smuzhiyun {% endblock %} 106*4882a593Smuzhiyun </li> 107*4882a593Smuzhiyun {% block localbreadcrumb %}{% endblock %} 108*4882a593Smuzhiyun </ul> 109*4882a593Smuzhiyun </div> 110*4882a593Smuzhiyun</div> 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun <!-- begin left sidebar container for builds which started properly --> 113*4882a593Smuzhiyun {% if build.started %} 114*4882a593Smuzhiyun <div class="row"> 115*4882a593Smuzhiyun <div id="nav" class="col-md-2"> 116*4882a593Smuzhiyun <ul class="nav nav-pills nav-stacked" id="build-menu"> 117*4882a593Smuzhiyun <li id="menu-dashboard" 118*4882a593Smuzhiyun {% if request.resolver_match.url_name == 'builddashboard' %} 119*4882a593Smuzhiyun class="active" 120*4882a593Smuzhiyun {% endif %} > 121*4882a593Smuzhiyun <a href="{% url 'builddashboard' build.pk %}">Build summary</a> 122*4882a593Smuzhiyun </li> 123*4882a593Smuzhiyun {% if build.has_images and build.outcome == build.SUCCEEDED %} 124*4882a593Smuzhiyun <li class="nav-header" data-menu-heading="images">Images</li> 125*4882a593Smuzhiyun {% block nav-target %} 126*4882a593Smuzhiyun {% for t in build.get_sorted_target_list %} 127*4882a593Smuzhiyun {% if t.has_images %} 128*4882a593Smuzhiyun <li id="menu-{{t.target}}"><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li> 129*4882a593Smuzhiyun {% endif %} 130*4882a593Smuzhiyun {% endfor %} 131*4882a593Smuzhiyun {% endblock %} 132*4882a593Smuzhiyun {% endif %} 133*4882a593Smuzhiyun <li class="nav-header">Build</li> 134*4882a593Smuzhiyun <li id="menu-configuration"><a href="{% url 'configuration' build.pk %}">Configuration</a></li> 135*4882a593Smuzhiyun <li id="menu-tasks"><a href="{% url 'tasks' build.pk %}">Tasks</a></li> 136*4882a593Smuzhiyun <li id="menu-recipes"><a href="{% url 'recipes' build.pk %}">Recipes</a></li> 137*4882a593Smuzhiyun <li id="menu-packages"><a href="{% url 'packages' build.pk %}">Packages</a></li> 138*4882a593Smuzhiyun <li class="nav-header">Performance</li> 139*4882a593Smuzhiyun <li id="menu-time"><a href="{% url 'buildtime' build.pk %}">Time</a></li> 140*4882a593Smuzhiyun <li id="menu-cpu-time"><a href="{% url 'cputime' build.pk %}">CPU usage</a></li> 141*4882a593Smuzhiyun <li id="menu-disk-io"><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li> 142*4882a593Smuzhiyun 143*4882a593Smuzhiyun <li class="nav-header">Actions</li> 144*4882a593Smuzhiyun <li id="menu-download-build-log"> 145*4882a593Smuzhiyun <a href="{% url 'build_artifact' build.id 'cookerlog' build.id %}"> 146*4882a593Smuzhiyun <span class="glyphicon glyphicon-download-alt"></span> 147*4882a593Smuzhiyun Download build log 148*4882a593Smuzhiyun </a> 149*4882a593Smuzhiyun </li> 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun {% with build.get_custom_image_recipes as custom_image_recipes %} 152*4882a593Smuzhiyun {% if custom_image_recipes.count > 0 %} 153*4882a593Smuzhiyun <!-- edit custom image built during this build --> 154*4882a593Smuzhiyun <li id="menu-edit-custom-image"> 155*4882a593Smuzhiyun <a href="#" data-role="edit-custom-image-trigger"> 156*4882a593Smuzhiyun <span class="glyphicon glyphicon-edit"></span> 157*4882a593Smuzhiyun Edit custom image 158*4882a593Smuzhiyun </a> 159*4882a593Smuzhiyun {% include 'editcustomimage_modal.html' %} 160*4882a593Smuzhiyun <script> 161*4882a593Smuzhiyun var editableCustomImageRecipes = {{ custom_image_recipes | objects_to_dictionaries:"id,name" | json }}; 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun $(document).ready(function () { 164*4882a593Smuzhiyun var editCustomImageTrigger = $('[data-role="edit-custom-image-trigger"]'); 165*4882a593Smuzhiyun var editCustomImageModal = $('#edit-custom-image-modal'); 166*4882a593Smuzhiyun 167*4882a593Smuzhiyun // edit custom image which was built during this build 168*4882a593Smuzhiyun editCustomImageTrigger.click(function () { 169*4882a593Smuzhiyun // single editable custom image: redirect to the edit page 170*4882a593Smuzhiyun // for that image 171*4882a593Smuzhiyun if (editableCustomImageRecipes.length === 1) { 172*4882a593Smuzhiyun var url = '{% url "customrecipe" build.project.id custom_image_recipes.first.id %}'; 173*4882a593Smuzhiyun document.location.href = url; 174*4882a593Smuzhiyun } 175*4882a593Smuzhiyun // multiple editable custom images: show modal to select 176*4882a593Smuzhiyun // one of them for editing 177*4882a593Smuzhiyun else { 178*4882a593Smuzhiyun editCustomImageModal.modal('show'); 179*4882a593Smuzhiyun } 180*4882a593Smuzhiyun }); 181*4882a593Smuzhiyun }); 182*4882a593Smuzhiyun </script> 183*4882a593Smuzhiyun </li> 184*4882a593Smuzhiyun {% endif %} 185*4882a593Smuzhiyun {% endwith %} 186*4882a593Smuzhiyun 187*4882a593Smuzhiyun <!-- new custom image from image recipe in this build --> 188*4882a593Smuzhiyun {% if build.has_image_recipes %} 189*4882a593Smuzhiyun <li id="menu-new-custom-image"> 190*4882a593Smuzhiyun <a href="#" data-role="new-custom-image-trigger"> 191*4882a593Smuzhiyun <span class="glyphicon glyphicon-plus"></span> 192*4882a593Smuzhiyun New custom image 193*4882a593Smuzhiyun </a> 194*4882a593Smuzhiyun {% include 'newcustomimage_modal.html' %} 195*4882a593Smuzhiyun <script> 196*4882a593Smuzhiyun // imageRecipes includes both custom image recipes and built-in 197*4882a593Smuzhiyun // image recipes, any of which can be used as the basis for a 198*4882a593Smuzhiyun // new custom image 199*4882a593Smuzhiyun var imageRecipes = {{ build.get_image_recipes | objects_to_dictionaries:"id,name" | json }}; 200*4882a593Smuzhiyun 201*4882a593Smuzhiyun $(document).ready(function () { 202*4882a593Smuzhiyun var newCustomImageModal = $('#new-custom-image-modal'); 203*4882a593Smuzhiyun var newCustomImageTrigger = $('[data-role="new-custom-image-trigger"]'); 204*4882a593Smuzhiyun 205*4882a593Smuzhiyun // show create new custom image modal to select an image built 206*4882a593Smuzhiyun // during this build as the basis for the custom recipe 207*4882a593Smuzhiyun newCustomImageTrigger.click(function () { 208*4882a593Smuzhiyun if (!imageRecipes.length) { 209*4882a593Smuzhiyun return; 210*4882a593Smuzhiyun } 211*4882a593Smuzhiyun 212*4882a593Smuzhiyun newCustomImageModalSetRecipes(imageRecipes); 213*4882a593Smuzhiyun newCustomImageModal.modal('show'); 214*4882a593Smuzhiyun }); 215*4882a593Smuzhiyun }); 216*4882a593Smuzhiyun </script> 217*4882a593Smuzhiyun {% endif %} 218*4882a593Smuzhiyun 219*4882a593Smuzhiyun <li id="menu-delete-build"> 220*4882a593Smuzhiyun <a href="#delete-build-modal" id="delete-build" data-toggle="modal" data-target="#delete-build-modal" class="text-danger"> 221*4882a593Smuzhiyun <span class="glyphicon glyphicon-trash"></span> 222*4882a593Smuzhiyun Delete build 223*4882a593Smuzhiyun </a> 224*4882a593Smuzhiyun </ul> 225*4882a593Smuzhiyun </div> 226*4882a593Smuzhiyun <!-- end left sidebar container --> 227*4882a593Smuzhiyun {% endif %} 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun <!-- right container; need class="row" for builds without left-hand menu --> 230*4882a593Smuzhiyun <div{% if not build.started %} class="row"{% endif %}> 231*4882a593Smuzhiyun {% block buildinfomain %}{% endblock %} 232*4882a593Smuzhiyun </div> 233*4882a593Smuzhiyun </div> 234*4882a593Smuzhiyun{% endblock %} 235