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