diff options
author | Dave Cobbley <david.j.cobbley@linux.intel.com> | 2018-08-14 20:05:37 +0300 |
---|---|---|
committer | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2018-08-23 04:26:31 +0300 |
commit | eb8dc40360f0cfef56fb6947cc817a547d6d9bc6 (patch) | |
tree | de291a73dc37168da6370e2cf16c347d1eba9df8 /poky/bitbake/lib/toaster/toastergui/templates | |
parent | 9c3cf826d853102535ead04cebc2d6023eff3032 (diff) | |
download | openbmc-eb8dc40360f0cfef56fb6947cc817a547d6d9bc6.tar.xz |
[Subtree] Removing import-layers directory
As part of the move to subtrees, need to bring all the import layers
content to the top level.
Change-Id: I4a163d10898cbc6e11c27f776f60e1a470049d8f
Signed-off-by: Dave Cobbley <david.j.cobbley@linux.intel.com>
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
Diffstat (limited to 'poky/bitbake/lib/toaster/toastergui/templates')
67 files changed, 7209 insertions, 0 deletions
diff --git a/poky/bitbake/lib/toaster/toastergui/templates/base.html b/poky/bitbake/lib/toaster/toastergui/templates/base.html new file mode 100644 index 0000000000..4f7206489b --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/base.html @@ -0,0 +1,144 @@ +<!DOCTYPE html> +{% load static %} +{% load projecttags %} +{% load project_url_tag %} +<html lang="en"> + <head> + <title> + {% block title %} Toaster {% endblock %} + </title> + <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type="text/css"/> + <!--link rel="stylesheet" href="{% static 'css/bootstrap-theme.css' %}" type="text/css"/--> + <link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}" type='text/css'/> + <link rel="stylesheet" href="{% static 'css/default.css' %}" type='text/css'/> + + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> + <script src="{% static 'js/jquery-2.0.3.min.js' %}"> + </script> + <script src="{% static 'js/jquery.cookie.js' %}"> + </script> + <script src="{% static 'js/bootstrap.min.js' %}"> + </script> + <script src="{% static 'js/typeahead.jquery.js' %}"> + </script> + <script src="{% static 'js/jsrender.min.js' %}"> + </script> + <script src="{% static 'js/highlight.pack.js' %}"> + </script> + <script src="{% static 'js/libtoaster.js' %}"> + </script> + {% if DEBUG %} + <script> + libtoaster.debug = true; + </script> + {% endif %} + <script> + $.views.settings.delimiters("<%", "%>"); + + libtoaster.ctx = { + jsUrl : "{% static 'js/' %}", + htmlUrl : "{% static 'html/' %}", + projectsUrl : "{% url 'all-projects' %}", + projectsTypeAheadUrl: {% url 'xhr_projectstypeahead' as prjurl%}{{prjurl|json}}, + {% if project.id %} + projectId : {{project.id}}, + projectPageUrl : {% url 'project' project.id as purl %}{{purl|json}}, + xhrProjectUrl : {% url 'xhr_project' project.id as pxurl %}{{pxurl|json}}, + projectName : {{project.name|json}}, + recipesTypeAheadUrl: {% url 'xhr_recipestypeahead' project.id as paturl%}{{paturl|json}}, + layersTypeAheadUrl: {% url 'xhr_layerstypeahead' project.id as paturl%}{{paturl|json}}, + machinesTypeAheadUrl: {% url 'xhr_machinestypeahead' project.id as paturl%}{{paturl|json}}, + distrosTypeAheadUrl: {% url 'xhr_distrostypeahead' project.id as paturl%}{{paturl|json}}, + projectBuildsUrl: {% url 'projectbuilds' project.id as pburl %}{{pburl|json}}, + xhrCustomRecipeUrl : "{% url 'xhr_customrecipe' %}", + projectId : {{project.id}}, + xhrBuildRequestUrl: "{% url 'xhr_buildrequest' project.id %}", + mostRecentBuildsUrl: "{% url 'most_recent_builds' %}?project_id={{project.id}}", + {% else %} + mostRecentBuildsUrl: "{% url 'most_recent_builds' %}", + projectId : undefined, + projectPageUrl : undefined, + projectName : undefined, + {% endif %} + }; + </script> + {% block extraheadcontent %} + {% endblock %} + </head> + + <body> + + {% csrf_token %} + <div id="loading-notification" class="alert alert-warning lead text-center" style="display:none"> + Loading <i class="fa-pulse icon-spinner"></i> + </div> + + <div id="change-notification" class="alert alert-info alert-dismissible change-notification" style="display:none"> + <button type="button" class="close" id="hide-alert" data-toggle="alert">×</button> + <span id="change-notification-msg"></span> + </div> + + <nav class="navbar navbar-default navbar-fixed-top"> + <div class="container-fluid"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#global-nav" aria-expanded="false"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <div class="toaster-navbar-brand"> + <a href="/"> + <img class="logo" src="{% static 'img/logo.png' %}" class="" alt="Yocto logo project"/> + </a> + <a class="brand" href="/">Toaster</a> + {% if DEBUG %} + <span class="glyphicon glyphicon-info-sign" title="<strong>Toaster version information</strong>" data-content="<dl><dt>Git branch</dt><dd>{{TOASTER_BRANCH}}</dd><dt>Git revision</dt><dd>{{TOASTER_REVISION}}</dd></dl>"></i> + {% endif %} + </div> + </div> + <div class="collapse navbar-collapse" id="global-nav"> + <ul class="nav navbar-nav"> + {% if request.resolver_match.url_name != 'landing' and request.resolver_match.url_name != 'newproject' %} + <li id="navbar-all-builds" + {% if request.resolver_match.url_name == 'all-builds' %} + class="active" + {% endif %}> + <a href="{% url 'all-builds' %}"> + <i class="glyphicon glyphicon-tasks"></i> + All builds + </a> + </li> + {% if project_enable %} + <li id="navbar-all-projects" + {% if request.resolver_match.url_name == 'all-projects' %} + class="active" + {% endif %}> + <a href="{% url 'all-projects' %}"> + <i class="icon-folder-open"></i> + All projects + </a> + </li> + {% endif %} + {% endif %} + <li id="navbar-docs"> + <a target="_blank" href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html"> + <i class="glyphicon glyphicon-book"></i> + Documentation + </a> + </li> + </ul> + {% if project_enable %} + <a class="btn btn-default navbar-btn navbar-right" id="new-project-button" href="{% url 'newproject' %}">New project</a> + {% endif %} + </div> + </div> + </nav> + + <div class="container-fluid"> + {% block pagecontent %} + {% endblock %} + </div> + </body> +</html> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/basebuilddetailpage.html b/poky/bitbake/lib/toaster/toastergui/templates/basebuilddetailpage.html new file mode 100644 index 0000000000..4d50667322 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/basebuilddetailpage.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} +{% load project_url_tag %} +{% load humanize %} +{% block pagecontent %} + +<div class="row"> + <!-- Breadcrumbs --> + <div class="col-md-12"> + <ul class="breadcrumb" id="breadcrumb"> + <li><a href="{% project_url build.project %}">{{build.project.name}}</a></li> + {% if not build.project.is_default %} + <li><a href="{% url 'projectbuilds' build.project.id %}">Builds</a></li> + {% endif %} + <li><a href="{%url 'builddashboard' build.pk%}">{{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"}})</a></li> + {% block localbreadcrumb %}{% endblock %} + </ul> + <script> +$( function () { + $('#breadcrumb > li').append('<span class="divider">→</span>'); + $('#breadcrumb > li:last').addClass("active"); + $('#breadcrumb > li:last > span').remove(); + }); + </script> + </div> +</div> + +<!-- Begin container --> +{% block pagedetailinfomain %}{% endblock %} +<!-- End container --> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/basebuildpage.html b/poky/bitbake/lib/toaster/toastergui/templates/basebuildpage.html new file mode 100644 index 0000000000..a41911f52a --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/basebuildpage.html @@ -0,0 +1,234 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load project_url_tag %} +{% load objects_to_dictionaries_filter %} +{% load humanize %} +{% load field_values_filter %} +{% block pagecontent %} + + <script> + var configVarUrl = "{% url 'configvars' build.id %}"; + + $(document).ready(function(){ + + $("#delete-build-confirm").click(function(){ + libtoaster.disableAjaxLoadingTimer(); + $(this).find('[data-role="submit-state"]').hide(); + $(this).find('[data-role="loading-state"]').show(); + $(this).attr("disabled", "disabled"); + + /* Make the modal non cancelable while delete is in progress */ + $('#delete-build-modal button[data-dismiss="modal"]').hide(); + + $.ajax({ + type: 'DELETE', + url: "{% url 'xhr_build' build.id %}", + headers: { 'X-CSRFToken' : $.cookie('csrftoken')}, + success: function (data) { + if (data.error !== "ok") { + console.warn(data.error); + } else { + libtoaster.setNotification("build-deleted", + $("#deleted-build-message").html()); + window.location.replace(data.gotoUrl); + } + }, + error: function (data) { + console.warn(data); + } + }); + }); + + + $('#breadcrumb > li').append('<span class="divider">→</span>'); + $('#breadcrumb > li:last').addClass("active"); + $('#breadcrumb > li:last > span').remove(); + + $("#build-menu li a").each(function(){ + /* Set the page active state in the Build menu */ + var currentUrl = window.location.href.split('?')[0]; + if (currentUrl === $(this).prop("href")){ + $(this).parent().addClass("active"); + } else { + /* Special case the configvar as this is part of configuration + * page but is a separate url + */ + if (window.location.pathname === configVarUrl){ + $("#menu-configuration").addClass("active"); + } else { + $(this).parent().removeClass("active"); + } + } + }); + }); + </script> + +<span style="display:none" id="deleted-build-message"> + 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> +</span> + +<div class="modal fade" tabindex="-1" role="dialog" id="delete-build-modal" style="display: none;" data-backdrop="static" data-keyboard="false"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-body"> + <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> + </div> + <div class="modal-footer"> + <button id="delete-build-confirm" class="btn btn-primary btn-large"> + <span data-role="submit-state">Delete build</span> + <span data-role="loading-state" style="display:none"> + <span class="fa-pulse"> + <i class="icon-spinner"></i> + </span> + Deleting build... + </span> + </button> + <button type="button" class="btn btn-link" data-dismiss="modal">Cancel</button> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div> <!-- / modal --> + +<div class="row"> + <!-- breadcrumbs --> + <div class="col-md-12"> + <ul class="breadcrumb" id="breadcrumb"> + <li><a href="{% project_url build.project %}">{{build.project.name}}</a></li> + {% if not build.project.is_default %} + <li><a href="{% url 'projectbuilds' build.project.id %}">Builds</a></li> + {% endif %} + <li> + {% block parentbreadcrumb %} + <a href="{%url 'builddashboard' build.pk%}"> + {{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"}}) + </a> + {% endblock %} + </li> + {% block localbreadcrumb %}{% endblock %} + </ul> + </div> +</div> + + <!-- begin left sidebar container for builds which started properly --> + {% if build.started %} + <div class="row"> + <div id="nav" class="col-md-2"> + <ul class="nav nav-pills nav-stacked" id="build-menu"> + <li id="menu-dashboard" + {% if request.resolver_match.url_name == 'builddashboard' %} + class="active" + {% endif %} > + <a href="{% url 'builddashboard' build.pk %}">Build summary</a> + </li> + {% if build.has_images and build.outcome == build.SUCCEEDED %} + <li class="nav-header" data-menu-heading="images">Images</li> + {% block nav-target %} + {% for t in build.get_sorted_target_list %} + {% if t.has_images %} + <li id="menu-{{t.target}}"><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li> + {% endif %} + {% endfor %} + {% endblock %} + {% endif %} + <li class="nav-header">Build</li> + <li id="menu-configuration"><a href="{% url 'configuration' build.pk %}">Configuration</a></li> + <li id="menu-tasks"><a href="{% url 'tasks' build.pk %}">Tasks</a></li> + <li id="menu-recipes"><a href="{% url 'recipes' build.pk %}">Recipes</a></li> + <li id="menu-packages"><a href="{% url 'packages' build.pk %}">Packages</a></li> + <li class="nav-header">Performance</li> + <li id="menu-time"><a href="{% url 'buildtime' build.pk %}">Time</a></li> + <li id="menu-cpu-time"><a href="{% url 'cputime' build.pk %}">CPU usage</a></li> + <li id="menu-disk-io"><a href="{% url 'diskio' build.pk %}">Disk I/O</a></li> + + <li class="nav-header">Actions</li> + <li id="menu-download-build-log"> + <a href="{% url 'build_artifact' build.id 'cookerlog' build.id %}"> + <span class="glyphicon glyphicon-download-alt"></span> + Download build log + </a> + </li> + + {% with build.get_custom_image_recipes as custom_image_recipes %} + {% if custom_image_recipes.count > 0 %} + <!-- edit custom image built during this build --> + <li id="menu-edit-custom-image"> + <a href="#" data-role="edit-custom-image-trigger"> + <span class="glyphicon glyphicon-edit"></span> + Edit custom image + </a> + {% include 'editcustomimage_modal.html' %} + <script> + var editableCustomImageRecipes = {{ custom_image_recipes | objects_to_dictionaries:"id,name" | json }}; + + $(document).ready(function () { + var editCustomImageTrigger = $('[data-role="edit-custom-image-trigger"]'); + var editCustomImageModal = $('#edit-custom-image-modal'); + + // edit custom image which was built during this build + editCustomImageTrigger.click(function () { + // single editable custom image: redirect to the edit page + // for that image + if (editableCustomImageRecipes.length === 1) { + var url = '{% url "customrecipe" build.project.id custom_image_recipes.first.id %}'; + document.location.href = url; + } + // multiple editable custom images: show modal to select + // one of them for editing + else { + editCustomImageModal.modal('show'); + } + }); + }); + </script> + </li> + {% endif %} + {% endwith %} + + <!-- new custom image from image recipe in this build --> + {% if build.has_image_recipes %} + <li id="menu-new-custom-image"> + <a href="#" data-role="new-custom-image-trigger"> + <span class="glyphicon glyphicon-plus"></span> + New custom image + </a> + {% include 'newcustomimage_modal.html' %} + <script> + // imageRecipes includes both custom image recipes and built-in + // image recipes, any of which can be used as the basis for a + // new custom image + var imageRecipes = {{ build.get_image_recipes | objects_to_dictionaries:"id,name" | json }}; + + $(document).ready(function () { + var newCustomImageModal = $('#new-custom-image-modal'); + var newCustomImageTrigger = $('[data-role="new-custom-image-trigger"]'); + + // show create new custom image modal to select an image built + // during this build as the basis for the custom recipe + newCustomImageTrigger.click(function () { + if (!imageRecipes.length) { + return; + } + + newCustomImageModalSetRecipes(imageRecipes); + newCustomImageModal.modal('show'); + }); + }); + </script> + {% endif %} + + <li id="menu-delete-build"> + <a href="#delete-build-modal" id="delete-build" data-toggle="modal" data-target="#delete-build-modal" class="text-danger"> + <span class="glyphicon glyphicon-trash"></span> + Delete build + </a> + </ul> + </div> + <!-- end left sidebar container --> + {% endif %} + + <!-- right container; need class="row" for builds without left-hand menu --> + <div{% if not build.started %} class="row"{% endif %}> + {% block buildinfomain %}{% endblock %} + </div> + </div> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/baseprojectbuildspage.html b/poky/bitbake/lib/toaster/toastergui/templates/baseprojectbuildspage.html new file mode 100644 index 0000000000..229cd17ba6 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/baseprojectbuildspage.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} +{% block pagecontent %} + +{% include "projecttopbar.html" %} + +<!-- Begin main page container --> +<div> + {% block projectinfomain %}{% endblock %} +</div> +<!-- End main container --> + +{% endblock %} + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html b/poky/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html new file mode 100644 index 0000000000..f2bb2ebf63 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/baseprojectpage.html @@ -0,0 +1,52 @@ +{% extends "base.html" %} + +{% load projecttags %} +{% load humanize %} + +{% block title %} {{title}} - {{project.name}} - Toaster {% endblock %} + +{% block pagecontent %} + +<div class="row"> + {% include "projecttopbar.html" %} + <script type="text/javascript"> +$(document).ready(function(){ + $("#config-nav .nav li a").each(function(){ + if (window.location.pathname === $(this).attr('href')) + $(this).parent().addClass('active'); + else + $(this).parent().removeClass('active'); + }); + + $("#topbar-configuration-tab").addClass("active") + }); + </script> + + <!-- only on config pages --> + <div id="config-nav" class="col-md-2"> + <ul class="nav nav-pills nav-stacked"> + <li><a class="nav-parent" href="{% url 'project' project.id %}">Configuration</a></li> + <li class="nav-header">Compatible metadata</li> + <li><a href="{% url 'projectcustomimages' project.id %}">Custom images</a></li> + <li><a href="{% url 'projectimagerecipes' project.id %}">Image recipes</a></li> + <li><a href="{% url 'projectsoftwarerecipes' project.id %}">Software recipes</a></li> + <li><a href="{% url 'projectmachines' project.id %}">Machines</a></li> + <li><a href="{% url 'projectlayers' project.id %}">Layers</a></li> + <li><a href="{% url 'projectdistros' project.id %}">Distros</a></li> + <li class="nav-header">Extra configuration</li> + <li><a href="{% url 'projectconf' project.id %}">BitBake variables</a></li> + + <li class="nav-header">Actions</li> + <li> + <a href="#delete-project-modal" role="button" class="text-danger" data-toggle="modal" data-target="#delete-project-modal"> + <i class="icon-trash text-danger"></i> Delete project</a> + </li> + </ul> + </div> + <div class="col-md-10"> + {% block projectinfomain %}{% endblock %} + </div> + +</div> +{% endblock %} + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html b/poky/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html new file mode 100644 index 0000000000..a2011fa902 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/basetable_bottom.html @@ -0,0 +1,94 @@ + </tbody> + </table> + +<!-- Show pagination controls --> +<div id="pagination-basetable_bottom"> + <!--span class="help-inline">Showing {{objects.start_index}} to {{objects.end_index}} out of {{objects.paginator.count}} entries.</span--> + + <ul class="pagination"> +{%if objects.has_previous %} + <li><a href="javascript:reload_params({'page':{{objects.previous_page_number}}})">«</a></li> +{%else%} + <li class="disabled"><a href="#">«</a></li> +{%endif%} +{% for i in objects.page_range %} + <li{%if i == objects.number %} class="active" {%endif%}><a href="javascript:reload_params({'page':{{i}}})">{{i}}</a></li> +{% endfor %} +{%if objects.has_next%} + <li><a href="javascript:reload_params({'page':{{objects.next_page_number}}})">»</a></li> +{%else%} + <li class="disabled"><a href="#">»</a></li> +{%endif%} + </ul> + <form class="navbar-form navbar-right"> + <div class="form-group"> + <label>Show rows:</label> + <select class="form-control pagesize"> + {% with "10 25 50 100 150" as list%} + {% for i in list.split %} + <option value="{{i}}">{{i}}</option> + {% endfor %} + {% endwith %} + </select> + </div> + </form> +</div> + +<!-- Update page display settings --> + +<script> + $(document).ready(function() { + + // we load cookies for the column display + save = $.cookie('_displaycols_{{objectname}}'); + if (save != undefined) { + setting = save.split(';'); + for ( i = 0; i < setting.length; i++) { + if (setting[i].length > 0) { + splitlist = setting[i].split(':'); + id = splitlist[0], v = splitlist[1]; + if (v == 'true') { + $('.chbxtoggle#'+id).prop('checked', true); + } + else { + $('.chbxtoggle#'+id).prop('checked', false); + } + } + } + } + + // load data for number of entries to be displayed on page + if ({{request.GET.count}} != "") { + pagesize = {{request.GET.count}}; + } + + $('.pagesize option').prop('selected', false) + .filter('[value="' + pagesize + '"]') + .attr('selected', true); + + $('.chbxtoggle').each(function () { + showhideTableColumn($(this).attr('id'), $(this).is(':checked')) + }); + + //turn edit columns dropdown into a multi-select menu + $('.dropdown-menu input, .dropdown-menu label').click(function(e) { + e.stopPropagation(); + }); + + //show tooltip with applied filter + $('#filtered').tooltip({container:'table', placement:'bottom', delay:{hide:1500}, html:true}); + + //progress bar tooltip + $('.progress, .lead span').tooltip({container:'table', placement:'top'}); + + $(".pagesize").change(function () { + reload_params({"count":$(this).val()}); + }); +}); +</script> + +<!-- modal filter boxes --> + {% for tc in tablecols %}{% if tc.filter %}{% with objectname=objectname f=tc.filter %} + {% include "filtersnippet.html" %} + {% endwith %}{% endif %} {% endfor %} +<!-- end modals --> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/basetable_top.html b/poky/bitbake/lib/toaster/toastergui/templates/basetable_top.html new file mode 100644 index 0000000000..5a9076d2aa --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/basetable_top.html @@ -0,0 +1,256 @@ +{% load projecttags %} +<!-- component to display a generic table --> + <script> + + // + // most of the following javascript is for managing the 'Edit Columns' + // pop-up dialog and actions. the idea is that there are 2 types + // of actions: immediate - performed while the dialog is still + // visible - hide/show columns, and delayed - performed when the + // dialog becomes invisible - any resorting if necessary. + // + // When the dialog is open, an interval timer is set up to + // determine if the dialog is still visible. when the dialog + // closes - goes invisible, the delayed actions are performed. + // + // the interval timer and interrupt handler is a way of simulating + // an onclose event. there is probably a simpler way to do this + // however the pop-up window id was elusive. + // + + var editColTimer; + var editColAction; + + // + // this is the target function of the interval timeout. + // check to see if the dialog is visible. if the dialog + // has gone invisible since the last check, take any delayed + // actions indicated in the action list and clear the timer. + // + + function checkVisible( ) { + editcol = document.getElementById( 'editcol' ); + if ( editcol.offsetWidth <= 0 ) { + clearInterval( editColTimer ); + editColTimer = false; + hideshowColumns( ); + editColAction = [ ]; + } + } + + function filterTableRows(test) { + if (test.length > 0) { + var r = test.split(/[ ,]+/).map(function (e) { return new RegExp(e, 'i') }); + $('tr.data').map( function (i, el) { + (! r.map(function (j) { return j.test($(el).html())}).reduce(function (c, p) { return c && p;} )) ? $(el).hide() : $(el).show(); + }); + } else + { + $('tr.data').show(); + } + } + + // + // determine the value of the indicated url arg. + // this is needed to determine whether a resort + // is necessary. it looks like a lot of gorp stuff + // but its actually pretty simple. + // + + function getURLParameter( name ) { + return decodeURIComponent((new RegExp('[?|&]' + name + '=' + + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, + '%20'))||null + } + + // + // when the dialog box goes invisible + // this function is called to interpret + // the action list and take any delayed actions necessary. + // the editColAction list is a hash table with + // the column name as the hash key, the hash value + // is a 2 element list. the first element is a flag + // indicating whether the column is on or off. the + // 2nd element is the sort order indicator for the column. + // + + function hideshowColumns( ) { + for( var k in editColAction ) { + showhideDelayedTableAction( k, editColAction[ k ][ 0 ], editColAction[ k ][ 1 ]); + } + } + + // + // this function actually performs the delayed table actions + // namely any resorting if necessary + // + + function showhideDelayedTableAction( clname, sh, orderkey ) { + if ( !sh ) { + p = getURLParameter( "orderby" ).split( ":" )[ 0 ]; + if ( p == orderkey ) { + reload_params({ 'orderby' : '{{default_orderby}}'}); + } + } + } + + // + // this function actually performs the immediate table actions + // namely any colums that need to be hidden/shown + // + + function showhideImmediateTableAction( clname, sh, orderkey ) { + if ( sh ) { + $( '.' + clname ).show( 100 ); + } + else { + $( '.' + clname ).hide( 100 ); + } + + // save cookie for all checkboxes + save = ''; + $( '.chbxtoggle' ).each(function( ) { + if ( $( this ).attr( 'id' ) != undefined ) { + save += ';' + $( this ).attr( 'id' ) +':'+ $( this ).is( ':checked' ) + } + }); + $.cookie( '_displaycols_{{objectname}}', save ); + save = ''; + } + + // + // this is the onclick handler for all of the check box + // items in edit columns dialog + // + + function showhideTableColumn( clname, sh, orderkey ) { + editcol = document.getElementById( 'editcol' ); + if ( editcol.offsetWidth <= 0 ) { + + // + // this path is taken when the page is first + // getting initialized - no dialog visible, + // perform both the immediate and delayed actions + // + + showhideImmediateTableAction( clname, sh, orderkey ); + showhideDelayedTableAction( clname, sh, orderkey ); + return; + } + if ( !editColTimer ) { + + // + // we don't have a timer active so set one up + // and clear the action list + // + + editColTimer = setInterval( checkVisible, 250 ); + editColAction = [ ]; + } + + // + // save the action to be taken when the dialog closes + // + + editColAction[ clname ] = [ sh, orderkey ]; + showhideImmediateTableAction( clname, sh, orderkey ); + } + + </script> + +<!-- control header --> +<div class="navbar navbar-default"> + <div class="container-fluid"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#table-chrome-collapse-variablehistory" aria-expanded="false"> + <span class="sr-only">Toggle table options</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + </div> + <div class="collapse navbar-collapse" id="table-chrome-collapse-variablehistory"> + <form class="navbar-form navbar-left" id="searchform"> + <div class="form-group"> + <div class="btn-group"> + <input class="form-control" id="search" name="search" type="text" placeholder="Search {%if object_search_display %}{{object_search_display}}{%else%}{{objectname}}{%endif%}" value="{%if request.GET.search %}{{request.GET.search}}{% endif %}"/> + {% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" tabindex="-1"><span class="remove-search-btn-variables glyphicon glyphicon-remove-circle"></span></a>{%endif%} + </div> + </div> + <input type="hidden" name="orderby" value="{{request.GET.orderby}}"> + <input type="hidden" name="page" value="1"> + <button class="btn btn-default" id="search-button" type="submit" value="Search">Search</button> + </form> + <form class="navbar-form navbar-right"> + <div class="form-group"> + <label>Show rows:</label> + <select class="pagesize form-control"> + {% with "10 25 50 100 150" as list%} + {% for i in list.split %} + <option value="{{i}}">{{i}}</option> + {% endfor %} + {% endwith %} + </select> + </div> + </form> + + <div class="btn-group navbar-right"> + {% if tablecols %} + <button id="edit-columns-button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown">Edit columns + <span class="caret"></span> + </button> +<!-- + {{tablecols|sortcols}} +--> + <ul id="editcol" class="dropdown-menu editcol"> + {% for i in tablecols|sortcols %} + <li> + <div class="checkbox"> + <label {% if not i.clclass %} class="muted" {%endif%}> + <input type="checkbox" class="chbxtoggle" + {% if i.clclass %} + id="{{i.clclass}}" + value="ct{{i.name}}" + {% if not i.hidden %} + checked="checked" + {%endif%} + onclick="showhideTableColumn( + $(this).attr('id'), + $(this).is(':checked'), + {% if i.ordericon %} + '{{i.orderkey}}' + {% else %} + undefined + {% endif %} + )" + {%else%} + checked disabled + {% endif %}/>{{i.name}} + </label> + </div> + </li> + {% endfor %} + </ul> + {% endif %} + </div> + </div> <!-- navbar-collapse --> + </div> <!-- container-fluid --> +</div> <!-- navbar-default --> + +<!-- the actual rows of the table --> + <table class="table table-bordered table-hover tablesorter" id="otable"> + <thead> + <!-- Table header row; generated from "tablecols" entry in the context dict --> + <tr> + {% for tc in tablecols %}<th class="{%if tc.dclass%}{{tc.dclass}}{%endif%} {% if tc.clclass %}{{tc.clclass}}{% endif %}"> + {%if tc.qhelp%}<span class="glyphicon glyphicon-question-sign get-help" title="{{tc.qhelp}}"></span>{%endif%} + {%if tc.orderfield%}<a {%if tc.ordericon%} class="sorted" {%endif%}href="javascript:reload_params({'page': 1, 'orderby' : '{{tc.orderfield}}' })">{{tc.name}}</a>{%else%}<span class="text-muted">{{tc.name}}</span>{%endif%} + {%if tc.ordericon%} <i class="icon-caret-{{tc.ordericon}}"></i>{%endif%} + {%if tc.filter%}<div class="btn-group pull-right"> + <a href="#filter_{{tc.filter.class}}" role="button" class="btn btn-xs {%if request.GET.filter%}{{tc.filter.options|filtered_icon:request.GET.filter}} {%endif%}" {%if request.GET.filter and tc.filter.options|filtered_tooltip:request.GET.filter %} title="<p>{{tc.filter.options|filtered_tooltip:request.GET.filter}}</p><p><a class='btn btn-sm btn-primary' href=javascript:reload_params({'filter':''})>Show all {% if filter_search_display %}{{filter_search_display}}{% else %}{{objectname}}{% endif %}</a></p>" {%endif%} data-toggle="modal"> <span class="glyphicon glyphicon-filter filtered"></span> </a> + </div>{%endif%} + </th>{% endfor %} + </tr> + </thead> + <tbody> + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/basetable_top_layers.html b/poky/bitbake/lib/toaster/toastergui/templates/basetable_top_layers.html new file mode 100644 index 0000000000..722091b2d3 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/basetable_top_layers.html @@ -0,0 +1,5 @@ +{% extends "basetable_top.html" %} + +{%block custombuttons %} + <a class="btn" href="{% url 'importlayer' project.id %}" style="margin-right:5px;">Import layer</a> +{%endblock%} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/bfile.html b/poky/bitbake/lib/toaster/toastergui/templates/bfile.html new file mode 100644 index 0000000000..c7f59434a5 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/bfile.html @@ -0,0 +1,24 @@ +{% extends "basebuildpage.html" %} + +{% block pagetitle %}Files for package {{objects.0.bpackage.name}} {% endblock %} +{% block pagetable %} + {% if not objects %} + <p>No files were recorded for this package!</p> + {% else %} + + <tr> + <th>Name</th> + <th>Size (Bytes)</th> + </tr> + + {% for file in objects %} + + <tr class="data"> + <td>{{file.path}}</td> + <td>{{file.size}}</td> + + {% endfor %} + + {% endif %} + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/brtargets.html b/poky/bitbake/lib/toaster/toastergui/templates/brtargets.html new file mode 100644 index 0000000000..4ebd05879a --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/brtargets.html @@ -0,0 +1,20 @@ +<span data-toggle="tooltip" + {% if buildrequest.brtarget_set.all.count > 1 %} + title="Targets: + {% for target in buildrequest.brtarget_set.all %} + {% if target.task %} + {{target.target}}:{{target.task}} + {% else %} + {{target.target}} + {% endif %} + {%endfor%}" + {%endif%}> + {% if buildrequest.brtarget_set.all.0.task %} + {{buildrequest.brtarget_set.all.0.target}}:{{buildrequest.brtarget_set.all.0.task}} + {% else %} + {{buildrequest.brtarget_set.all.0.target}} + {% endif %} + {% if buildrequest.brtarget_set.all.count > 1 %} + (+ {{buildrequest.brtarget_set.all.count|add:"-1"}}) + {% endif %} +</span> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/builddashboard.html b/poky/bitbake/lib/toaster/toastergui/templates/builddashboard.html new file mode 100644 index 0000000000..02a29816a6 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/builddashboard.html @@ -0,0 +1,319 @@ +{% extends "basebuildpage.html" %} +{% load humanize %} +{% load projecttags %} +{% load field_values_filter %} + +{% block title %} {{build.get_sorted_target_list|field_values:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %} +{% block parentbreadcrumb %} +{% if build.get_sorted_target_list.count > 0 %} + {{build.get_sorted_target_list.0.target}} +{% endif %} + +{%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"}}) +{% endblock %} + +{% block buildinfomain %} +<!-- page title --> +<div class="{% if build.started %}col-md-10{% else %}col-md-12{% endif %}"> + <div class="page-header build-data"> + <h1>{{build.get_sorted_target_list|field_values:"target"|join:", "}} {{build.machine}}</h1> + </div> + +<!-- build result bar --> + <div class="alert {%if build.outcome == build.SUCCEEDED%}alert-success{%elif build.outcome == build.FAILED%}alert-danger{%else%}alert-info{%endif%}"> + <span><strong>{%if build.outcome == build.SUCCEEDED%}Completed{%elif build.outcome == build.FAILED%}Failed{%else%}{%endif%}</strong> on {{build.completed_on|date:"d/m/y H:i"}}</span> + {% if build.warnings.count or build.errors.count %} + <span>with</span> + {% endif %} + {%if build.outcome == build.SUCCEEDED or build.outcome == build.FAILED %} + {% if build.errors.count %} + <a href="#errors" class="alert-link show-errors"> {{build.errors.count}} error{{build.errors.count|pluralize}}</a> + {% endif %} + {% if build.warnings.count %} + {% if build.errors.count %}and{% endif %} + <a href="#warnings" class="show-warnings"> {{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a> + {% endif %} + {% if build.cooker_log_path %} + <a class="pull-right log" href="{% url 'build_artifact' build.id "cookerlog" build.id %}">Download build log</a> + {% endif %} + <span class="pull-right"> + Build time: + <span data-build-field="buildtime"> + {% if build.outcome == build.SUCCEEDED %} + <a href="{% url 'buildtime' build.pk %}">{{ build.timespent_seconds|sectohms }}</a> + {% else %} + {{ build.timespent_seconds|sectohms }} + {% endif %} + </span> + </span> + + {%endif%} +</div> + +{% if build.errors.count %} + <div class="panel panel-default" id="errors"> + <div class="panel-heading"> + <h2 class="panel-title"> + <span class="glyphicon glyphicon-minus-sign"></span> + <a data-toggle="collapse" href="#error-info" id="error-toggle"> + {{build.errors.count}} error{{build.errors.count|pluralize}} + </a> + </h2> + </div> + <div class="panel-collapse collapse in" id="error-info"> + <div class="panel-body"> + <div class="{% if build.started %}col-md-10{% else %}col-md-12{% endif %}"> + {% for error in build.errors %} + <div class="alert alert-danger" data-log-message-id="{{error.pk}}"> + <pre>{{error.message}}</pre> + </div> + {% endfor %} + </div> + </div> + </div> + </div> +{% endif %} + +{%if build.outcome == build.SUCCEEDED%} +<!-- built images --> + {% if hasArtifacts %} + <h2 data-heading="build-artifacts">Build artifacts</h2> + {% for target in targets %} + {% if target.target.is_image %} + <div class="well well-transparent dashboard-section" data-artifacts-for-target="{{target.target.pk}}"> + {% if target.npkg > 0 %} + <h3> + <a href="{% url 'target' build.pk target.target.pk %}" data-link="target-packages"> + {{target.target.target}} + </a> + </h3> + <dl class="dl-horizontal"> + <dt>Packages included</dt> + <dd> + <a href="{% url 'target' build.pk target.target.pk %}"> + <span data-value="target-package-count">{{target.npkg}}</span> + </a> + </dd> + <dt>Total package size</dt> + <dd> + <span data-value="target-package-size">{{target.pkgsz|filtered_filesizeformat}}</span> + </dd> + </dl> + {% else %} + <h3>{{target.target.target}}</h3> + {% endif %} + + {% if target.targetHasImages %} + <dl class="dl-horizontal"> + <dt> + Manifests + </dt> + + <dd> + <a data-link="license-manifest" href="{% url 'build_artifact' build.pk 'licensemanifest' target.target.pk %}">License manifest</a> + </dd> + + {% if target.target.package_manifest_path %} + <dd> + <a data-link="package-manifest" href="{% url 'build_artifact' build.pk 'packagemanifest' target.target.pk %}">Package manifest</a> + </dd> + {% endif %} + </dl> + + <dl class="dl-horizontal"> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Image files are stored in <code>build/tmp/deploy/images/</code>"></span> + Image files + </dt> + <dd> + <ul class="list-unstyled" data-links="image-artifacts"> + {% for i in target.imageFiles|dictsort:"suffix" %} + <li> + <a href="{% url 'build_artifact' build.pk 'imagefile' i.id %}"> + {{i.suffix}} + </a> + ({{i.size|filtered_filesizeformat}}) + </li> + {% endfor %} + </ul> + </dd> + <dt> + Kernel artifacts + </dt> + <dd> + <ul class="list-unstyled" data-links="kernel-artifacts"> + {% for artifact in target.target_kernel_artifacts|dictsort:"basename" %} + <li> + <a href="{% url 'build_artifact' build.id 'targetkernelartifact' artifact.id %}">{{artifact.basename}}</a> + ({{artifact.file_size|filtered_filesizeformat}}) + </li> + {% endfor %} + </ul> + </dd> + </dl> + {% endif %} + {% if target.target_sdk_artifacts_count > 0 %} + <dl class="dl-horizontal"> + <dt> + SDK artifacts + </dt> + <dd> + <ul class="list-unstyled" data-links="sdk-artifacts"> + {% for artifact in target.target_sdk_artifacts|dictsort:"basename" %} + <li> + <a href="{% url 'build_artifact' build.id 'targetsdkartifact' artifact.id %}">{{artifact.basename}}</a> + ({{artifact.file_size|filtered_filesizeformat}}) + </li> + {% endfor %} + </ul> + </dd> + </dl> + {% endif %} + </div> + {% endif %} + {% endfor %} + {% endif %} + +{%else%} +<!-- error dump --> +{%endif%} + +<!-- other artifacts --> +{% if build.buildartifact_set.all.count > 0 %} +<h2>Other artifacts</h2> + + <div class="well well-transparent dashboard-section"> + <dl class="dl-horizontal"> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Build artifacts discovered in <i>tmp/deploy/images</i>. Usually kernel images and kernel modules."></span> + Other artifacts</dt> + <dd><div> + {% for ba in build.buildartifact_set.all|dictsort:"file_name" %} + <a href="{%url 'build_artifact' build.id 'buildartifact' ba.id %}"> + {{ba.get_basename}} + </a> + + ({{ba.file_size|filtered_filesizeformat}}) <br/> + {% endfor %} + </div> + </dd> + </dl> + </div> + +{% endif %} + +{% if build.started %} + <!-- build summary --> + <h2 data-role="build-summary-heading">Build summary</h2> + <div class="row"> + <div class="col-md-4 dashboard-section"> + <div class="well well-transparent"> + <h3><a href="{%url 'configuration' build.pk%}">Configuration</a></h3> + <dl> + <dt>Machine</dt><dd>{{build.machine}}</dd> + <dt>Distro</dt><dd>{{build.distro}}</dd> + <dt>Layers</dt><dd><ul class="list-unstyled">{% for i in build.layer_version_build.all|dictsort:"layer.name" %}<li>{{i.layer.name}}</li>{%endfor%}</ul></dd> + </dl> + </div> + </div> + <div class="col-md-4 dashboard-section"> + <div class="well well-transparent"> + <h3><a href="{%url 'tasks' build.pk%}">Tasks</a></h3> + <dl> + {% query build.task_build outcome=4 order__gt=0 as exectask%} + {% if exectask.count > 0 %} + <dt>Failed tasks</dt> + <dd> + {% if exectask.count == 1 %} + <a class="text-danger" href="{% url "task" build.id exectask.0.id %}"> + {{exectask.0.recipe.name}} + <span class="task-name">{{exectask.0.task_name}}</span> + </a> + + <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}"> + <span class="glyphicon glyphicon-download-alt get-help" title="Download task log file"></i> + </a> + + {% elif exectask.count > 1%} + <a class="text-danger" href="{% url "tasks" build.id %}?limit=25&page=1&orderby=order&filter=task_outcome:failed&default_orderby=order&filter_value=on&">{{exectask.count}}</a> + {% endif %} + </dd> + {% endif %} + <dt>Total number of tasks</dt><dd><a href="{% url 'tasks' build.pk %}">{% query build.task_build order__gt=0 as alltasks %}{{alltasks.count}}</a></dd> + <dt> + Tasks executed + <span class="glyphicon glyphicon-question-sign get-help" title="'Executed' tasks are those that need to be run in order to generate the task output"></span> + </dt> + <dd><a href="{% url 'tasks' build.pk %}?limit=25&page=1&orderby=order&filter=execution_outcome:executed&default_orderby=order&filter_value=on&">{% query build.task_build task_executed=1 order__gt=0 as exectask%}{{exectask.count}}</a></dd> + <dt> + Tasks not executed + <span class="glyphicon glyphicon-question-sign get-help" title="'Not executed' tasks don't need to run because their outcome is provided by another task"></span> + </dt> + <dd><a href="{% url 'tasks' build.pk %}?limit=25&page=1&orderby=order&filter=execution_outcome:not_executed&default_orderby=order&filter_value=on&">{% query build.task_build task_executed=0 order__gt=0 as noexectask%}{{noexectask.count}}</a></dd> + <dt> + Reuse + <span class="glyphicon glyphicon-question-sign get-help" title="The percentage of 'not executed' tasks over the total number of tasks, which is a measure of the efficiency of your build"></span> + </dt> + <dd> + {% query build.task_build order__gt=0 as texec %} + {% if noexectask.count|multiply:100|divide:texec.count < 0 %} + 0 + {% else %} + {{noexectask.count|multiply:100|divide:texec.count}} + {% endif %} + % + </dd> + </dl> + </div> + </div> + <div class="col-md-4 dashboard-section"> + <div class="well well-transparent"> + <h3><a href="{% url 'recipes' build.pk %}">Recipes</a> & <a href="{% url 'packages' build.pk %}">Packages</a></h3> + <dl> + <dt>Recipes built</dt><dd><a href="{% url 'recipes' build.pk %}">{{recipecount}}</a></dd> + <dt>Packages built</dt><dd><a href="{% url 'packages' build.pk %}">{{packagecount}}</a></dd> + </dl> + </div> + </div> + </div> +{% endif %} <!-- end build summary --> + +{% if build.warnings.count %} + <div class="panel panel-default" id="warnings"> + <div class="panel-heading"> + <h2 class="panel-title"> + <span class="glyphicon glyphicon-warning-sign"></span> + <a id="warning-toggle" href="#warning-info" data-toggle="collapse">{{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a> + </h2> + </div> + <div class="panel-collapse collapse" id="warning-info"> + <div class="panel-body"> + <div class="{% if build.started %}col-md-10{% else %}col-md-12{% endif %}"> + {% for warning in logmessages %}{% if warning.level == 1 %} + <div class="alert alert-warning" data-log-message-id="{{warning.pk}}"> + <pre>{{warning.message}}</pre> + </div> + {% endif %}{% endfor %} + </div> + </div> + </div> + </div> +{% endif %} + +</div> <!-- end 10 column row --> + +<script type="text/javascript"> + $(document).ready(function() { + //show warnings section when requested from the previous page + if (location.href.search('#warnings') > -1) { + $('#warning-info').addClass('in'); + } + + //show warnings section when requested from the build outcome + $(".show-warnings").click(function() { + $('#warning-info').addClass('in'); + }); + }); +</script> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/buildinfo-toastertable.html b/poky/bitbake/lib/toaster/toastergui/templates/buildinfo-toastertable.html new file mode 100644 index 0000000000..eb4c656901 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/buildinfo-toastertable.html @@ -0,0 +1,25 @@ +{% extends "basebuildpage.html" %} + +{% load projecttags %} + +{% block title %} {{title}} - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %} +{% block localbreadcrumb %} +<li>{{title}}</li> +{% endblock %} + +{% block nav-packages %} +{% endblock %} + +{% block buildinfomain %} +<div class="col-md-10"> +{# xhr_table_url is just the current url so leave it blank #} +{% with xhr_table_url='' %} + <div class="page-header build-data"> + <h1> + {{title}} (<span class="table-count-{{table_name}}">0</span>) </h2> + </h1> + </div> + {% include "toastertable.html" %} +{% endwith %} +</div> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/builds-toastertable.html b/poky/bitbake/lib/toaster/toastergui/templates/builds-toastertable.html new file mode 100644 index 0000000000..0afe0a3115 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/builds-toastertable.html @@ -0,0 +1,52 @@ +{% extends 'base.html' %} +{% load static %} + +{% block extraheadcontent %} + <link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" type='text/css'> + <link rel="stylesheet" href="{% static 'css/jquery-ui.structure.min.css' %}" type='text/css'> + <link rel="stylesheet" href="{% static 'css/jquery-ui.theme.min.css' %}" type='text/css'> + <script src="{% static 'js/jquery-ui.min.js' %}"> + </script> +{% endblock %} + +{% block title %} All builds - Toaster {% endblock %} + +{% block pagecontent %} + +<div class="row"> + <div class="col-md-12"> + {% with mru=mru mrb_type=mrb_type %} + {% include 'mrb_section.html' %} + {% endwith %} + + <div class="page-header"> + <h1 class="top-air" data-role="page-title"></h1> + </div> + + {% url 'builds' as xhr_table_url %} + {% include 'toastertable.html' %} + </div> +</div> + + <script> + $(document).ready(function () { + var tableElt = $("#{{table_name}}"); + var titleElt = $("[data-role='page-title']"); + + tableElt.on("table-done", function (e, total, tableParams) { + var title = "All builds"; + + if (tableParams.search || tableParams.filter) { + if (total === 0) { + title = "No builds found"; + } + else if (total > 0) { + title = total + " build" + (total > 1 ? 's' : '') + " found"; + } + } + + titleElt.text(title); + }); + }); + </script> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/configuration.html b/poky/bitbake/lib/toaster/toastergui/templates/configuration.html new file mode 100644 index 0000000000..58989f865c --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/configuration.html @@ -0,0 +1,85 @@ +{% extends "basebuildpage.html" %} +{% load projecttags %} + +{% block title %} Configuration summary - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %} +{% block localbreadcrumb %} +<li>Configuration</li> +{% endblock %} + +{% block buildinfomain %} +<!-- page title --> +<div class="col-md-10"> + + <div class="page-header build-data"> + <h1>Configuration</h1> + </div> + +<!-- configuration table --> +<div id="navTab"> +<ul class="nav nav-tabs"> + <li class="active"><a href="#">Summary</a></li> + <li class=""><a href="{% url 'configvars' build.id %}">BitBake variables</a></li> +</ul> + + <!-- summary --> + <div id="summary" class="tab-pane active"> + <h3>Build configuration</h3> + <dl class="dl-horizontal"> + {%if BB_VERSION %}<dt>BitBake version</dt><dd>{{BB_VERSION}}</dd> {% endif %} + {%if BUILD_SYS %}<dt>Build system</dt><dd>{{BUILD_SYS}}</dd> {% endif %} + {%if NATIVELSBSTRING %}<dt>Host distribution</dt><dd>{{NATIVELSBSTRING}}</dd> {% endif %} + {%if TARGET_SYS %}<dt>Target system</dt><dd>{{TARGET_SYS}}</dd> {% endif %} + {%if MACHINE %}<dt>Machine</dt><dd>{{MACHINE}}</dd> {% endif %} + {%if DISTRO %}<dt>Distro</dt><dd>{{DISTRO}}</dd> {% endif %} + {%if DISTRO_VERSION %}<dt>Distro version</dt><dd>{{DISTRO_VERSION}}</dd> {% endif %} + {%if TUNE_FEATURES %}<dt>Tune features</dt><dd>{{TUNE_FEATURES}}</dd> {% endif %} + {%if TARGET_FPU %}<dt>Target FPU</dt><dd>{{TARGET_FPU}}</dd> {% endif %} + {%if targets.all %}<dt>Target(s)</dt> + <dd> <ul class="list-unstyled"> {% for target in targets.all %} + <li>{{target.target}}{%if forloop.counter > 1 %}<br>{% endif %}</li> + {% endfor %} </ul> </dd> {% endif %} + </dl> + <h3>Layers</h3> + <div class="row"> + <div class="col-md-9 table-responsive"> + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th>Layer</th> + <th>Layer branch</th> + <th>Layer commit</th> + </tr> + </thead> + <tbody>{% for lv in build.layer_version_build.all|dictsort:"layer.name" %} + <tr> + <td>{{lv.layer.name}}</td> + {% if lv.layer.local_source_dir %} + <td> + <span class="text-muted">Not applicable</span> + <span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{lv.layer.name}} is not in a Git repository, so there is no branch associated with it"> </span> + </td> + {% else %} + <td>{{lv.branch}}</td> + {% endif %} + {% if lv.layer.local_source_dir %} + <td> + <span class="text-muted">Not applicable</span> + <span class="glyphicon glyphicon-question-sign get-help" data-original-title="" title="The source code of {{lv.layer.name}} is not in a Git repository, so there is no commit associated with it"> </span> + </td> + {% else %} + <td> <a class="btn btn-default" data-content="<ul class='list-unstyled'> + <li>{{lv.commit}}</li> </ul>"> + {{lv.commit|truncatechars:13}} + </a></td> + {% endif %} + </tr>{% endfor %} + </tbody> + </table> + </div> + </div> + </div> + +</div> + +</div> <!-- end of 10-column section --> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/configvars.html b/poky/bitbake/lib/toaster/toastergui/templates/configvars.html new file mode 100644 index 0000000000..ca2e1eab39 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/configvars.html @@ -0,0 +1,145 @@ +{% extends "basebuildpage.html" %} +{% load projecttags %} + +{% block title %} BitBake variables - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %} +{% block localbreadcrumb %} +<li>Configuration</li> +{% endblock %} + +{% block buildinfomain %} +<!-- page title --> +<div class="col-md-10"> + <div class="page-header build-data"> + <h1> + {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %} + {{objects.paginator.count}} variable{{objects.paginator.count|pluralize}} found + {%elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %} + No variables found + {%else%} + Configuration + {%endif%} + </h1> + </div> + +<!-- configuration table --> +<div id="navTab"> + <ul class="nav nav-tabs"> + <li class=""><a href="{% url 'configuration' build.id %}">Summary</a></li> + <li class="active"><a href="#" >BitBake variables</a></li> + </ul> + + <!-- variables --> + <div id="variables" class="tab-pane"> + + {% if objects.paginator.count == 0 %} + <div class="alert alert-warning"> + <form class="no-results form-inline" id="searchform"> + <div class="form-group"> + <div class="btn-group"> + <input class="form-control" id="search" name="search" type="text" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/> + {% if request.GET.search %} + <a href="javascript:$('#search').val('');searchform.submit()" tabindex="-1"> + <span class="remove-search-btn-variables glyphicon glyphicon-remove-circle"></span> + </a> + {% endif %} + </div> + </div> + <button class="btn btn-default" type="submit" value="Search">Search</button> + <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all variables</button> + </form> + </div> + + {% else %} + {% include "basetable_top.html" %} + + {% for variable in objects %} + <tr class="data"> + <td class="variable_name"><a data-toggle="modal" href="#variable-{{variable.pk}}">{{variable.variable_name}}</a></td> + <td class="variable_value">{{variable.variable_value|truncatechars:153}}</td> + <td class="file"> + {% if variable.vhistory.all %} + {% for path in variable.vhistory.all|filter_setin_files:file_filter %} + {{path}}<br/> + {% endfor %} + {% endif %} + </td> + <td class="description"> + {% if variable.description %} + {{variable.description}} + <a href="http://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-{{variable.variable_name|variable_parent_name}}" target="_blank"> + <span class="glyphicon glyphicon-new-window get-info"></span></a> + {% endif %} + </td> + </tr> +{% endfor %} +</tbody> +</table> +</div> <!-- table-responsive --> +{% include "basetable_bottom.html" %} +{% endif %} +</div> <!-- endvariables --> + +<!-- file list popups --> +{% for variable in objects %} +{% if variable.vhistory.count %} +<div id="variable-{{variable.pk}}" class="modal fade" tabindex="-1" role="dialog"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> + <h3>History of {{variable.variable_name}}</h3> + </div> + <div class="modal-body"> + {% if variable.variable_value %} + {% if variable.variable_value|length < 570 %} + <h4>{{variable.variable_name}} value is:</h4> + <p> + {{variable.variable_value}} + </p> + {% else %} + <h4>{{variable.variable_name}} value is:</h4> + <p> + <span>{{variable.variable_value|string_slice:':570'}} + <span class="full"> {{variable.variable_value|string_slice:'570:'}} + </span> + <a href="#" class="full-show">...</a> + </span> + </p> + <a href="#" class="full-hide">Collapse variable value <i class="icon-caret-up"></i> + </a> + {% endif %} + {% else %} + <div class="alert alert-info">The value of <strong>{{variable.variable_name}}</strong> is an empty string</div> + {% endif %} + <h4>The value was set in the following configuration files:</h4> + <div class="table-responsive"> + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th>Order</th> + <th>Configuration file</th> + <th>Operation</th> + <th>Line</th> + </tr> + </thead> + <tbody> + {% for vh in variable.vhistory.all %} + <tr> + <td>{{forloop.counter}}</td><td class="file">{{vh.file_name}}</td><td>{{vh.operation}}</td><td>{{vh.line_number}}</td> + </tr> + {%endfor%} + </tbody> + </table> + </div> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div><!-- /.modal --> +{% endif %} +{% endfor %} + +</div> <!-- buildinfomain --> + +</div> <!-- end 10-column section --> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/cpuusage.html b/poky/bitbake/lib/toaster/toastergui/templates/cpuusage.html new file mode 100644 index 0000000000..02f07b7605 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/cpuusage.html @@ -0,0 +1,4 @@ +{% extends "basebuildpage.html" %} +{% block localbreadcrumb %} +<li>Cpu Usage</li> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/customise_btn.html b/poky/bitbake/lib/toaster/toastergui/templates/customise_btn.html new file mode 100644 index 0000000000..38c258ac32 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/customise_btn.html @@ -0,0 +1,15 @@ +<button class="btn btn-default btn-block layer-exists-{{data.layer_version.pk}} customise-btn" data-recipe="{{data.pk}}" + {% if data.layer_version.pk not in extra.current_layers %} + style="display:none;" + {% endif %} + > + Customise +</button> +<button class="btn btn-default btn-block layer-add-{{data.layer_version.pk}} layerbtn" data-layer='{ "id": {{data.layer_version.pk}}, "name": "{{data.layer_version.layer.name}}", "layerdetailurl": "{%url 'layerdetails' extra.pid data.layer_version.pk%}"}' data-directive="add" + {% if data.layer_version.pk in extra.current_layers %} + style="display:none;" + {% endif %} + > + <i class="glyphicon glyphicon-plus"></i> + Add layer +</button> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/customrecipe.html b/poky/bitbake/lib/toaster/toastergui/templates/customrecipe.html new file mode 100644 index 0000000000..945fc97977 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/customrecipe.html @@ -0,0 +1,268 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} +{% load static %} +{% block pagecontent %} + +{% with recipe.get_base_recipe_file as base_recipe_file %} + <ul class="breadcrumb"> + <li> + <a href="{% url 'project' project.id %}">{{project.name}}</a> + <span class="divider">→</span> + </li> + <li><a href="{% url 'projectcustomimages' project.id %}">Custom images</a> + <span class="divider">→</span> + </li> + <li class="active"> + {{recipe.name}} ({{recipe.layer_version.layer.name}}) + </li> + </ul> + +<script src="{% static 'js/customrecipe.js' %}"></script> +<script> + $(document).ready(function (){ + var ctx = { + recipe : { + id: {{recipe.pk}}, + name: "{{recipe.name}}", + includedPackagesCount: {{recipe.includes_set.count}}, + baseRecipeId: {{recipe.base_recipe.pk}}, + xhrPackageListUrl: "{% url 'xhr_customrecipe_packages' recipe.pk %}", + xhrCustomRecipeUrl: "{% url 'xhr_customrecipe_id' recipe.pk %}", + } + }; + + try { + customRecipePageInit(ctx); + } catch (e) { + document.write("Sorry, An error has occurred loading this page"); + console.warn(e); + } + }); +</script> + +<!-- Delete recipe modal --> +<div id="delete-recipe-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-body"> + <p>Are you sure you want to delete the <strong>{{recipe.name}}</strong> + custom image?</p> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-primary" id="delete-custom-recipe-confirmed"> + <span data-role="submit-state">Delete custom image</span> + <span data-role="loading-state" style="display:none"> + <span class="fa-pulse"> + <i class="fa-pulse icon-spinner"></i> + </span> + Deleting custom image... + </span> + </button> + <button type="button" class="btn btn-link" data-dismiss="modal">Cancel</button> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div><!-- /.modal --> +<!-- end delete recipe modal --> + +<!-- package dependencies modal --> +<div id="package-deps-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> + <h3><span class="package-to-add-name"></span> dependencies</h3> + </div> + <div class="modal-body"> + <p>Based on information from a previous build it is likely that adding <strong class="package-to-add-name"></strong> will also add the following packages to your custom image: + </p> + <ul id="package-add-dep-list"> + </ul> + </div> + <div class="modal-footer"> + <p class="help-block text-left">Total package size: <strong id="package-deps-total-size"></strong></p> + <button id="add-package-deps-modal-btn" type="submit" class="btn btn-primary" data-dismiss="modal">Add packages</button> + <button class="btn btn-link" data-dismiss="modal">Cancel</button> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div><!-- /.modal --> +<!-- end package dependencies modal --> + +<!-- package reverse dependencies modal --> +<div style="display:none" id="package-reverse-deps-modal" class="modal fade in" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> + <h3><span class="package-to-rm-name"></span> reverse dependencies</h3> + </div> + <div class="modal-body"> + <p> <strong class="reverse-deps-count"></strong> <span class="reverse-deps-package"></span> in your image <span class="reverse-deps-depends"></span> on <strong class="package-to-rm-name"></strong>:</p> + <ul id="package-reverse-dep-list"> + </ul> + <p>In order to remove <strong class="package-to-rm-name"></strong>, you must remove <span class="reverse-deps-this"></span> <strong class="reverse-deps-count"></strong> <span class="reverse-deps-package"></span> as well.</p> + </div> + <div class="modal-footer"> + <p class="help-block text-left">Total package size: <strong id="package-reverse-deps-total-size"></strong></p> + <button id="rm-package-reverse-deps-modal-btn" type="submit" class="btn btn-primary" data-dismiss="modal">Remove all <span class="reverse-deps-count-plus1"></button> + <button class="btn btn-link" data-dismiss="modal">Cancel</button> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div><!-- /.modal --> +<!-- end package dependencies modal --> + +<div class="alert alert-success alert-dismissible change-notification" id="image-created-notification" style="display: none"> + <button type="button" data-dismiss="alert" class="close">×</button> + <p>Your custom image <strong>{{recipe.name}}</strong> has been created. You can now add or remove packages as needed.</p> +</div> +<div class="page-header"> + <h1> + {{recipe.name}} + <small>({{recipe.layer_version.layer.name}})</small> + </h1> +</div> + +<div class="row"> + <div class="col-md-8"> + <div class="button-place btn-group" style="width: 100%"> + <a class="btn btn-default btn-lg build-custom-image" href="#" style="width: 50%"> + Build {{recipe.name}} + </a> + <a href="{% url 'customrecipedownload' project.id recipe.id %}" class="btn btn-default btn-lg" style="width: 50%" + {% if not base_recipe_file %} + disabled="disabled" + {% endif %}> + Download recipe file + {% if not base_recipe_file %} + <i class="icon-question-sign get-help" + data-original-title="The recipe file doesn't exist yet, so you cannot download it. You need to build your custom image first"></i> + {% endif %} + </a> + </div> + <div id="no-results-special-{{table_name}}" class="top-air" style="display:none;"> + <div class="alert alert-warning"> + <h3>No packages found</h3> + <p>You might consider <a href={% url 'projectsoftwarerecipes' project.id %}>searching the list of recipes</a> instead.</p> + <p>If you find a recipe that matches the name of the package you want:</p> + <ol> + <li>Add the layer providing the recipe to your project</li> + <li>Build the recipe</li> + <li>Once the build completes, come back to this page and search for the package</li> + </ol> + <form class="form-inline no-results"> + <div class="form-group"> + <div class="btn-group"> + <input type="text" class="form-control no-results-search-input" id="no-results-search-input-{{table_name}}" name="search" placeholder="Search {{title|lower}}" /> + <span class="remove-search-btn-{{table_name}} glyphicon glyphicon-remove-circle" id="no-results-remove-search-btn" tabindex="-1"></span> + </div> + </div> + <button class="btn btn-default search-submit-{{table_name}}">Search</button> + <button class="btn btn-link" id="no-results-show-all-packages">Show all packages</button> + </form> + </div> + </div> + <div id="results-found-{{table_name}}"> + <div id="packages-table"> + {% if recipe.get_all_packages.count == 0 and last_build == None %} + <h2> Add | Remove packages </h2> + <div class="alert alert-info"> + <p class="lead">Toaster has no package information for {{recipe.name}}. To generate package information, build {{recipe.name}}</p> + <button class="btn btn-info btn-lg build-custom-image" style="margin:20px 0 10px 0;">Build {{recipe.name}}</button> + </div> + {% else %} + {# ToasterTable for Adding remove packages #} + {% url 'recipeselectpackages' project.id recipe.id as xhr_table_url %} + <h2>{{title}} (<span class="table-count-{{table_name}}">0</span>) </h2> + {% include "toastertable.html" %} + {% endif %} + </div> + </div> + </div> + <div class="col-md-4"> + <div class="well"> + <h2>About {{recipe.name}}</h2> + + <dl class="item-info"> + <dt> + Approx. packages included + <span class="glyphicon glyphicon-question-sign get-help" title="" data-original-title="The number of packages included is based on information from previous builds and from parsing layers, so we can never be sure it is 100% accurate"></span> + </dt> + <dd id="total-num-packages">{{recipe.get_all_packages.count}}</dd> + <dt> + Approx. package size + <span class="glyphicon glyphicon-question-sign get-help" title="Package size is based on information from previous builds, so we can never be sure it is 100% accurate"></span> + </dt> + <dd id="total-size-packages">{{approx_pkg_size.size__sum|filtered_filesizeformat}}</dd> + {% if last_build %} + <dt>Last build</dt> + <dd> + <span class="glyphicon glyphicon-ok-circle"></span> + <a href="{% url 'projectbuilds' project.id%}">{{last_build.completed_on|date:"d/m/y H:i"}}</a> + </dd> + {% endif %} + <dt>Based on</dt> + <dd><a href="{% url 'recipedetails' project.id recipe.base_recipe.pk %}">{{recipe.base_recipe.name}}</a></dd> + {% if recipe.get_last_successful_built_target %} + {% with recipe.get_last_successful_built_target as last_build_target %} + <dt>Last build</dt> + <dd> + <span class="glyphicon glyphicon-ok-circle"></span> + <a href="{% url 'builddashboard' last_build_target.build.pk %}"> + {{last_build_target.build.completed_on|date:"d/m/y H:i"}}</a> + </dd> + {% endwith %} + {% endif %} + {% if base_recipe_file %} + <dt>Recipe file</dt> + <dd> + <code>{{recipe.name}}_{{recipe.version}}.bb</code> + <a href="{% url 'customrecipedownload' project.pk recipe.pk %}"><span class="glyphicon glyphicon-download-alt" data-toggle="tooltip" title="Download recipe file"></span></a> + </dd> + {% endif %} + <dt>Layer</dt> + <dd><a href="{% url 'layerdetails' project.id recipe.layer_version.pk %}">{{recipe.layer_version.layer.name}}</a></dd> + {% if recipe.summary %} + <dt> + Summary + </dt> + <dd> + {{recipe.summary}} + </dd> + {% endif %} + {% if recipe.description %} + <dt> + Description + </dt> + <dd> + {{recipe.description}} + </dd> + {% endif %} + <dt>Version</dt> + <dd> + {{recipe.version}} + </dd> + {% if recipe.section %} + <dt>Section</dt> + <dd> + {{recipe.section}} + </dd> + {% endif %} + <dt>License</dt> + <dd> + {{recipe.license}} + <span class="glyphicon glyphicon-question-sign get-help" title="All custom images have their license set to MIT. This is because the license applies only to the recipe (.bb) file, and not to the image itself. To see which licenses apply to the image you must check the license manifest generated with each build"></i> + </dd> + </dl> + <i class="icon-trash text-danger"></i> + <a href="#delete-recipe-modal" data-target="#delete-recipe-modal" data-toggle="modal" class="text-danger" id="delete-recipe"> + Delete custom image + </a> + </div> + </div> +</div> + +{% endwith %}{# end base_recipe_file #} +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html b/poky/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html new file mode 100644 index 0000000000..15adfbc914 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/detail_pagination_bottom.html @@ -0,0 +1,57 @@ +{% comment %} + Show pagination controls as per search/pagination table detail spec. + Input: objects, setup for pagination using the standard method in views. + object_count, count for complete list of objects, (all pages, no pattern) +{% endcomment %} + +{# only paginate if 10 or more rows unfiltered, all pages #} +{% if object_count >= 10 %} +<div id="pagination-detail"> + <ul class="pagination"> +{%if objects.has_previous %} + <li><a href="javascript:reload_params({'page':{{objects.previous_page_number}}})">«</a></li> +{%else%} + <li class="disabled"><a href="#">«</a></li> +{%endif%} +{% for i in objects.page_range %} + <li{%if i == objects.number %} class="active" {%endif%}><a href="javascript:reload_params({'page':{{i}}})">{{i}}</a></li> +{% endfor %} +{%if objects.has_next%} + <li><a href="javascript:reload_params({'page':{{objects.next_page_number}}})">»</a></li> +{%else%} + <li class="disabled"><a href="#">»</a></li> +{%endif%} + </ul> + + <form class="navbar-form navbar-right"> + <div class=form-group"> + <label>Show rows:</label> + <select class="pagesize form-control"> + {% with "10 25 50 100 150" as list%} + {% for i in list.split %} + <option value="{{i}}">{{i}}</option> + {% endfor %} + {% endwith %} + </select> + </div> + </form> +</div> + +<!-- Update page display settings --> +<script> + $(document).ready(function() { + // load data for number of entries to be displayed on page + if ({{request.GET.count}} != "") { + pagesize = {{request.GET.count}}; + } + $('.pagesize option').prop('selected', false) + .filter('[value="' + pagesize + '"]') + .attr('selected', true); + + $(".pagesize").change(function () { + reload_params({"count":$(this).val()}); + }); +}); +</script> +{% endif %} + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/detail_search_header.html b/poky/bitbake/lib/toaster/toastergui/templates/detail_search_header.html new file mode 100644 index 0000000000..7a9865908d --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/detail_search_header.html @@ -0,0 +1,72 @@ +{% comment %} + Show a detail table Search field and Rows per page. + Input: + objects, our boilerplated paginated with search fields set. + object_count, count of full, unfiltered, objects list + search_what, fills in "Search ___" + Only show the search form if we have more than 10 results, + or if return from a previous search. +{% endcomment %} + + +<script> +$(document).ready(function() { + /* Clear the current search selection and reload the results */ + $(".search-clear").click(function(){ + $("#search").val(""); + $(this).parents("form").submit(); + }); +}); +</script> + +{% if objects.paginator.count > 10 or request.GET.search %} + {% if objects.paginator.count == 0 %} + <div class="alert alert-warning"> + <h4>No {{search_what}} found</h4> + <form id="searchform" class="form-inline"> + {% else %} + <form id="searchform" class="navbar-form navbar-left detail-page-controls"> + {% endif %} + + <div class="form-group"> + <div class="btn-group"> + <input id="search" class="form-control" type="text" placeholder="Search {{search_what}}" name="search" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"> + <input type="hidden" value="name:+" name="orderby"> + <input type="hidden" value="l" name="page"> + {% if request.GET.search %} + <span class="remove-search-btn-detail-search search-clear glyphicon glyphicon-remove-circle"></span> + {% endif %} + </div> + </div> + <button type="submit" class="btn btn-default">Search</button> + {% if objects.paginator.count == 0 %} + <button type="submit" class="btn btn-link search-clear"> + Show all {{search_what}} + </button> + {% endif %} + </form> + {% endif %} + + {% if objects.paginator.count == 0 %} + </div> {# end alert #} + {% else %} + {% if object_count > 10 %} + <form class="navbar-form navbar-right"> + <div class="form-group"> + <label>Show rows:</label> + <select class="pagesize form-control"> + {% with "10 25 50 100 150" as list%} + {% for i in list.split %} + {% if request.session.limit == i %} + <option value="{{i}}" selected>{{i}}</option> + {% else %} + <option value="{{i}}">{{i}}</option> + {% endif %} + {% endfor %} + {% endwith %} + </select> + </div> + </form> + {% endif %} +{% endif %} + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/detail_sorted_header.html b/poky/bitbake/lib/toaster/toastergui/templates/detail_sorted_header.html new file mode 100644 index 0000000000..4434df4394 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/detail_sorted_header.html @@ -0,0 +1,25 @@ +{% comment %} + Adds sorted columns to a detail table. + Must be preceded by <table class="table table-bordered table-hover tablesorter" id="otable"> + Must be followed by <tbody>...</tbody></table>. + Requires tablecols setup column fields dclass, clclass, qhelp, orderfield. +{% endcomment %} +{% load projecttags %} +{# <table class="table table-bordered table-hover tablesorter" id="otable"> #} + <thead> + <!-- Table header row; generated from "tablecols" entry in the context dict --> + <tr> + {% for tc in tablecols %}<th class="{%if tc.dclass%}{{tc.dclass}}{% endif %} {%if tc.class %}{{tc.clclass}}{% endif %}"> + {%if tc.qhelp%}<span class="glyphicon glyphicon-question-sign get-help" title="{{tc.qhelp}}"></span>{%endif%} + {%if tc.orderfield%}<a {%if tc.ordericon%} class="sorted" {%endif%}href="javascript:reload_params({'page': 1, 'orderby' : '{{tc.orderfield}}' })">{{tc.name}}</a>{%else%}<span class="text-muted">{{tc.name}}</span>{%endif%} + {%if tc.ordericon%} <span class="icon-caret-{{tc.ordericon}}"></span>{%endif%} + {% if request.GET.search and forloop.first %} + <span class="badge badge-info">{{objects.paginator.count}}</span> + {% endif %} + {%if tc.filter%}<div class="btn-group pull-right"> + <a href="#filter_{{tc.filter.class}}" role="button" class="btn btn-mini {%if request.GET.filter%}{{tc.filter.options|filtered_icon:request.GET.filter}} {%endif%}" {%if request.GET.filter and tc.filter.options|filtered_tooltip:request.GET.filter %} title="<p>{{tc.filter.options|filtered_tooltip:request.GET.filter}}</p><p><a class='btn btn-sm btn-primary' href=javascript:reload_params({'filter':''})>Show all {% if filter_search_display %}{{filter_search_display}}{% else %}{{objectname}}{% endif %}</a></p>" {%endif%} data-toggle="modal"> <i class="glyphicon glyphicon-filter filtered"></i> </a> + </div>{%endif%} + </th>{% endfor %} + </tr> + </thead> + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/dirinfo.html b/poky/bitbake/lib/toaster/toastergui/templates/dirinfo.html new file mode 100644 index 0000000000..ab89e279fa --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/dirinfo.html @@ -0,0 +1,245 @@ +{% extends "basebuildpage.html" %} +{% block title %} Directory structure - {{ target.target }} {{ build.machine }} - {{ build.project.name }} - Toaster {% endblock %} +{% block extraheadcontent %} +{% load static %} +<link rel="stylesheet" href="{% static 'css/jquery.treetable.css' %}" type="text/css"> +<link rel="stylesheet" href="{% static 'css/jquery.treetable.theme.toaster.css' %}" type="text/css"> +{% endblock extraheadcontent %} + +{% block localbreadcrumb %} +<li>{{target.target}}</li> +{% endblock localbreadcrumb%} + +{% block buildinfomain %} + +{% load static %} +<script src="{% static 'js/jquery.treetable.js' %}"> +</script> +{% load projecttags %} + +<script type='text/javascript'> + var ctx = {}; + ctx.target = "{{target.target}}"; + + $(document).ready(function(){ + $("#menu-"+ctx.target).addClass("active"); + }); + + function setupTreetable() { + $("#dirtable").treetable({ + expandable: true, + branchAttr: "ttBranch", + clickableNodeNames: true, + onNodeCollapse: function() { + /* Do nothing, keep cached */ + }, + onNodeExpand: function() { + var start = this.id; + var n = $("#dirtable").treetable("node", start); + if (this.children.length > 0) { + /* already was expanded once */ + $("#dirtable").treetable("reveal", start); + } + else { + var url = "{% url "dirinfo_ajax" build.id target.id %}"; + $.ajax({ + async: false, + type : "GET", + url : url, + data : "start=" + start, + success : function(response) { + addRows(n, response) + }, + error : function(jqXHR, textStatus, errorThrown ) {alert(textStatus + ":" + errorThrown)}, + }); + } + }, + }); + } + function td(data) { + if (data == null) { + data = ''; + } + return '<td>' + data + '</td>' + } + + function formatRow(o) { + /* setup tr-wide formatting */ + var tr = '<tr class="'; + if (o.isdir && o.childcount) { + tr += 'branch" data-tt-branch="true" '; + } + else { + tr += 'leaf" data-tt-branch="false" '; + } + tr += ' data-tt-id="' + o.fullpath +'" '; + if (o.parent != "/") { + tr += ' data-tt-parent-id="' + o.parent +'" '; + } + tr += '>'; + + /* setup td specific formatting */ + var link_to = '<td class="text-muted">' + o.link_to + '</td>'; + var size = '<td class = "sizecol">' + o.size + '</td>' + var permission = td(o.permission); + var owner = td(o.owner); + var group = td(o.group); + + /* handle the name column */ + var name = null;; + var namespan=1; + if (o.isdir) { + if (o.link_to == null) { + namespan = 2; + if (o.package == null) { + namespan = 3; + } + } + var colspan = 'colspan="' + namespan + '"'; + name = '<td class="content-directory"' + colspan + '>'; + if (o.childcount) { + name += '<a href="">'; + } + name += '<span class="glyphicon glyphicon-folder-close"></span>'; + name += ' ' + o.name; + if (o.childcount) { + name += '</a>'; + } + name += '</td>'; + } + else { + if (o.link_to == null) { + namespan = 2; + if (o.package == null) { + namespan = 3; + } + var colspan = 'colspan="' + namespan + '"'; + name = '<td ' + colspan + '><span class="glyphicon glyphicon-file"></span>'; + } + else { + name = '<td class="text-muted"><span class="glyphicon glyphicon-hand-right"></span>'; + } + name += ' ' + o.name; + name += '</td>'; + } + + /* handle the package column */ + var package = null; + if (o.package != null) { + /* add link to included package page */ + build_id = {{ build.id }}; + target_id = {{ target.id }}; + /* Create a url for a dummy package id of 0 */ + dummy = "{% url 'package_included_detail' build.id target.id 0 %}" + /* fill in the package id */ + url = dummy.substr(0, dummy.length-1) + o.package_id; + package = '<a href=' + url + '>' ; + package += o.package; + package += '</a>'; + if (o.installed_package != o.package) { + /* make class muted and add hover help */ + package += '<span class="text-muted"> as ' + o.installed_package + ' </span>'; + package += '<span class="glyphicon glyphicon-question-sign get-help hover-help" '; + package += 'title="' + o.package + ' was renamed at packaging time and was installed in your image as ' + o.installed_package + '">'; + package += '</span>'; + } + } + package = td(package); + + var cols1to3; + switch (namespan) { + case 3: + cols1to3 = name; + break; + case 2: + cols1to3 = name + package; + break; + default: + cols1to3 = name + link_to + package; + } + r = tr + cols1to3 + size + permission + owner + group + "</tr>" + return r; + } + + function addRows(n, objs) { + rows = ""; + for (i=0; i<objs.length; i++) { + rows += formatRow(objs[i]); + } + $("#dirtable").treetable("loadBranch", n, rows); + } + + $.fn.isOffScreen = function(){ + var win = $(window); + viewportBottom = win.scrollTop() + win.height(); + + var bounds = this.offset(); + bounds.bottom = bounds.top + this.outerHeight(); + + return (bounds.bottom > viewportBottom); + }; + + function selectRow(path) { + var row = $('tr[data-tt-id="' + path + '"]'); + row.addClass(" highlight"); + if (row.isOffScreen()) { + $('html, body').animate({ scrollTop: row.offset().top - 150}, 2000); + } + } +</script> + +<div class="col-md-10"> + + <div class="page-header build-data"> + <h1> {{target.target}} </h1> + </div> + + <ul class="nav nav-tabs"> + <li> + <a href="{% url 'target' build.id target.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="Of all the packages built, the subset installed in the root file system of this image"></span> + Packages included ({{target.package_count}} - {{packages_sum|filtered_filesizeformat}}) + </a> + </li> + <li class="active"> + <a href="{% url 'dirinfo' build.id target.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="The directories and files in the root file system of this image"></span> + Directory structure + </a> + </li> + </ul> + + <div id="directory-structure" class="tab-pane active"> + <table id="dirtable" class="table table-bordered table-hover treetable"> + <thead> + <tr> + <th>Directory / File</th> + <th>Symbolic link to</th> + <th>Source package</th> + <th class="narrow-col">Size</th> + <th class="medium-col">Permissions</th> + <th class="narrow-col">Owner</th> + <th class="narrow-col">Group</th> + </tr> + </thead> + <tbody> + <script type='text/javascript'> + setupTreetable(); + addRows(null, {{ objects|safe }} ); + {% if file_path %} + {% comment %} + link from package_included_detail specifies file path + {% endcomment %} + {% for dir_elem in dir_list %} + $("#dirtable").treetable("expandNode", "{{dir_elem}}"); + {% endfor %} + selectRow("{{file_path}}"); + {% endif %} + </script> + </tbody> + </table> + </div> <!-- directory-structure --> +</div> <!-- col-md-10 --> + +{% endblock buildinfomain %} + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/diskio.html b/poky/bitbake/lib/toaster/toastergui/templates/diskio.html new file mode 100644 index 0000000000..c5cef6f385 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/diskio.html @@ -0,0 +1,4 @@ +{% extends "basebuildpage.html" %} +{% block localbreadcrumb %} +<li>Disk I/O</li> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/distro_btn.html b/poky/bitbake/lib/toaster/toastergui/templates/distro_btn.html new file mode 100644 index 0000000000..fac79472cc --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/distro_btn.html @@ -0,0 +1,20 @@ +<a href="{% url 'project' extra.pid %}?setDistro={{data.name}}" class="btn btn-default btn-block layer-exists-{{data.layer_version.id}}" + {% if data.layer_version.pk not in extra.current_layers %} + style="display:none;" + {% endif %}> + Set distro</a> +<a class="btn btn-default btn-block layerbtn layer-add-{{data.layer_version.id}}" data-layer='{ + "id": {{data.layer_version.id}}, + "name": "{{data.layer_version.layer.name}}", + "xhrLayerUrl": "{% url "xhr_layer" extra.pid data.pk %}", + "layerdetailurl": "{%url 'layerdetails' extra.pid data.layer_version.id %}" + }' data-directive="add" + {% if data.layer_version.pk in extra.current_layers %} + style="display:none;" + {% endif %} +> + <span class="glyphicon glyphicon-plus"></span> + Add layer + <span class="glyphicon glyphicon-question-sign get-help" title="To select this distro, you must first add the {{data.layer_version.layer.name}} layer to your project"></i> +</a> + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/editcustomimage_modal.html b/poky/bitbake/lib/toaster/toastergui/templates/editcustomimage_modal.html new file mode 100644 index 0000000000..baa36c0e1b --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/editcustomimage_modal.html @@ -0,0 +1,88 @@ +<!-- +modal dialog shown on the build dashboard, for editing an existing custom image; +only shown if more than one custom image was built, so the user needs to +choose which one to edit + +required context: + build - a Build object +--> +<div class="modal fade" aria-hidden="false" id="edit-custom-image-modal"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3>Which image do you want to edit?</h3> + </div> + + <div class="modal-body"> + {% for recipe in build.get_custom_image_recipes %} + <div class="radio"> + <label> + <input type="radio" name="select-custom-image" + data-url="{% url 'customrecipe' build.project.id recipe.id %}"> + {{recipe.name}} + </label> + </div> + {% endfor %} + <span class="help-block text-danger" id="invalid-custom-image-help" style="display:none"> + Please select a custom image to edit. + </span> + </div> + + <div class="modal-footer"> + <button class="btn btn-primary btn-lg" data-url="#" + data-action="edit-custom-image" disabled> + Edit custom image + </button> + </div> + </div> + </div> +</div> + +<script> +$(document).ready(function () { + var editCustomImageButton = $('[data-action="edit-custom-image"]'); + var error = $('#invalid-custom-image-help'); + var radios = $('[name="select-custom-image"]'); + + // return custom image radio buttons which are selected + var getSelectedRadios = function () { + return $('[name="select-custom-image"]:checked'); + }; + + function enableSubmit() { + if (getSelectedRadios().length === 1) { + editCustomImageButton.removeAttr('disabled'); + error.hide(); + } + else { + editCustomImageButton.attr('disabled', 'disabled'); + error.show(); + } + }; + + $("#edit-custom-image-modal").on("shown.bs.modal", function() { + enableSubmit(); + }); + + radios.change(function () { + enableSubmit(); + }); + + editCustomImageButton.click(function () { + var selectedRadios = getSelectedRadios(); + + if (selectedRadios.length === 1) { + document.location.href = selectedRadios.first().attr('data-url'); + } + else { + error.show(); + } + }); + + // Select the first custom image listed. Radio button groups + // should always have an option selected by default + $("input:radio:first").attr("checked", "checked"); + +}); +</script> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/filtersnippet.html b/poky/bitbake/lib/toaster/toastergui/templates/filtersnippet.html new file mode 100644 index 0000000000..1286ca315f --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/filtersnippet.html @@ -0,0 +1,72 @@ +{% load projecttags %} +<!-- '{{f.class}}' filter --> +{% with f.class as key %} + +<div id="filter_{{f.class}}" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"> + <div class="modal-dialog"> + <div class="modal-content"> + <form> + <input type="hidden" name="search" value="{%if request.GET.search %}{{request.GET.search}}{%endif%}"/> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> + {% if search_term %} + <h3>Filter {{total_count}} {%if filter_search_display%}{{filter_search_display|title}}{%else%}{{objectname|title}}{%endif%} matching '{{search_term}}' by '{{tc.name}}'</h3> + {% else %} + <h3>Filter {%if filter_search_display%}{{filter_search_display|title}}{%else%}{{objectname|title}}{%endif%} by '{{tc.name}}'</h3> + {% endif %} + </div> + <div class="modal-body"> + <p>{{f.label}}</p> + <div class="radio"> + <label> + <input type="radio" name="filter" {%if request.GET.filter%}{{f.options|check_filter_status:request.GET.filter}} {%else%} checked {%endif%} value="" data-key="{{key}}"> All {%if filter_search_display%}{{filter_search_display|title}}{%else%}{{objectname|title}}{%endif%} + </label> + </div> + {% for option in f.options %} + <div class="radio"> + {% if option.1 == 'daterange' %} + <label> + <input type="radio" name="filter" id="filter_value_{{key}}" {%if key == daterange_selected %}checked{%endif%} value="{{option.1}}" data-key="{{key}}"> {{option.0}} + {% else %} + {% if 1 %} + <label> + <input type="radio" name="filter" {%if request.GET.filter == option.1 %}checked{%endif%} value="{{option.1}}" data-key="{{key}}"> {{option.0}} + {% comment "do not disable radio selections by count for now" %}{% else %} + <label class="text-muted"> + <input type="radio" name="filter" disabled {%if request.GET.filter == option.1 %}checked{%endif%} value="{{option.1}}" data-key="{{key}}"> {{option.0}} + {% endcomment %}{% endif %} + {% endif %} + {% if option.3 %}<i class="icon-question-sign get-help" data-placement="right" title="{{option.3}}"></i>{% endif %} + </label></div> + {% if option.1 == 'daterange' %} + <input type="text" id="date_from_{{key}}" name="date_from_{{key}}" disabled class="input-sm" /><label class="help-inline">to</label> + <input type="text" id="date_to_{{key}}" name="date_to_{{key}}" disabled class="input-sm" /> + <label class="help-inline get-help" >(dd/mm/yyyy)</label> + </div> + {% endif %} + {% endfor %} + <!-- daterange persistence --> + {% if last_date_from and last_date_to %} + <input type="hidden" id="last_date_from_{{key}}" name="last_date_from" value="{{last_date_from}}"/> + <input type="hidden" id="last_date_to_{{key}}" name="last_date_to" value="{{last_date_to}}"/> + {% endif %} + </div> + <div class="modal-footer"> + <div class="row"> + <div class="col-md-6"> + <button type="submit" class="btn btn-primary" data-key="{{key}}">Apply</button> + </div> + <div class="col-md-6"> + {% if request.GET.filter %} + {% if request.GET.filter|string_remove_regex:':.*' != f.options.0.1|string_remove_regex:':.*' %} + <p class="text-right text-muted">You can only apply one filter to the table. This filter will override the current filter.</p> + {% endif %} + {% endif %} + </div> + </div> + </div> + </form> + </div><!-- /.modal-content --> +</div><!-- /.modal-dialog --> +</div> <!--/.modal --> +{% endwith %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/generic-toastertable-page.html b/poky/bitbake/lib/toaster/toastergui/templates/generic-toastertable-page.html new file mode 100644 index 0000000000..b3eabe1a26 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/generic-toastertable-page.html @@ -0,0 +1,17 @@ +{% extends "baseprojectpage.html" %} +{% load projecttags %} +{% load humanize %} +{% load static %} + +{% block projectinfomain %} + +<h2>{{title}} (<span class="table-count-{{table_name}}"></span>) + {% if project.release %} + <i class="glyphicon glyphicon-question-sign get-help" title="This page lists {{title|lower}} compatible with the release selected for this project, which is {{project.release.description}}"></i> + {% endif %} +</h2> + +{% url table_name project.id as xhr_table_url %} +{% include "toastertable.html" %} + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/health.html b/poky/bitbake/lib/toaster/toastergui/templates/health.html new file mode 100644 index 0000000000..f17fdbc439 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/health.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<html lang="en"> + <head><title>Toaster Health</title></head> + <body>Ok</body> +</html> + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/importlayer.html b/poky/bitbake/lib/toaster/toastergui/templates/importlayer.html new file mode 100644 index 0000000000..97d52c76c1 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/importlayer.html @@ -0,0 +1,170 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} +{% load static %} +{% block title %} Import layer - {{project.name}} - Toaster {% endblock %} +{% block pagecontent %} + +<div class="row"> + {% include "projecttopbar.html" %} + {% if project and project.release %} + <script src="{% static 'js/layerDepsModal.js' %}"></script> + <script src="{% static 'js/importlayer.js' %}"></script> + <script> + $(document).ready(function (){ + var ctx = { + xhrLayerUrl : "{% url 'xhr_layer' project.id %}", + xhrGitRevTypeAheadUrl : "{% url 'xhr_gitrevtypeahead' %}", + }; + + try { + importLayerPageInit(ctx); + } catch (e) { + document.write("Sorry, An error has occurred loading this page"); + console.warn(e); + } + }); + </script> + + <form class="col-md-11"> + <span class="help-block">The layer you are importing must be compatible with <strong>{{project.release.description}}</strong>, which is the release you are using in this project.</span> + <div class="alert alert-error" id="import-error" style="display:none"> + <button type="button" class="close" data-dismiss="alert">×</button> + <h3> </h3> + <p></p> + <ul></ul> + </div> + <fieldset> + <div class="form-group" id="layer-name-ctrl"> + <label class="control-label" for="import-layer-name"> + Layer name + <span class="glyphicon glyphicon-question-sign get-help" title="Something like 'meta-mylayer'. Your layer name must be unique and can only include letters, numbers and dashes"></span> + </label> + <input class="form-control" id="import-layer-name" type="text" required autofocus data-autocomplete="off" data-provide="typeahead"> + <span class="help-block" style="display: none;" id="invalid-layer-name-hint">A valid layer name can only include letters, numbers and dashes</span> + <span class="help-inline" style="display: none;" id="duplicated-layer-name-hint"></span> + </div> + </fieldset> + <div id="duplicate-layer-info" style="display:none"> + <div class="alert alert-warning"> + <h3>A layer called <a href="" class="dup-layer-link"><span class="dup-layer-name"></span></a> already exists</h3> + <p>Layer names must be unqiue. Please use a different layer name.</p> + <dl id="git-layer-dup" style="display:none;"> + <dt> + The <span class="dup-layer-name"></span> repository url is + </dt> + <dd> + <span id="dup-layer-vcs-url"></span> + </dd> + <dt> + The <span class="dup-layer-name"></span> revision is + </dt> + <dd> + <span id="dup-layer-revision"></span> + </dd> + </dl> + <dl id="local-layer-dup" style="display:none;"> + <dt> + The <span class="dup-layer-name"></span> directory is + </dt> + <dd> + <span id="dup-local-source-dir-name"></span> + </dd> + </dl> + <p><a href="" class="dup-layer-link">View the <span class="dup-layer-name"></span> layer information</a></p> + </div> + </div> + <fieldset class="fields-apart-from-layer-name" id="repo-select"> + <legend class="radioLegend">Where is the layer source code?</legend> + <div class="radio"> + <label> + <input type="radio" id="git-repo-radio" name="repo" value="git" checked="checked"> + In a <strong>Git repository</strong> + </label> + <p class="help-block radio-help">To build the layer Toaster must be able to access the Git repository, otherwise builds will fail. Toaster will fetch and checkout your chosen Git revision every time you start a build.</p> + </div> + <div class="radio"> + <label> + <input type="radio" id="local-dir-radio" name="repo" value="local"> + In a <strong>directory</strong> + </label> + <p class="help-block radio-help">Use this option for quick layer development, by simply providing the path to the layer source code.</p> + </div> + </fieldset> + <fieldset class="fields-apart-from-layer-name" id="git-repo"> + <legend>Git repository information</legend> + <div class="form-group"> + <label for="layer-git-repo-url"> + Git repository URL + <span class="glyphicon glyphicon-question-sign get-help" title="Fetch/clone URL of the repository. Currently, Toaster only supports Git repositories." ></span> + </label> + <input type="text" id="layer-git-repo-url" class="form-control" required> + </div> + <div class="form-group"> + <label for="layer-subdir"> + Repository subdirectory + <span class="text-muted">(optional)</span> + <span class="glyphicon glyphicon-question-sign get-help" title="Subdirectory within the repository where the layer is located, if not in the root (usually only used if the repository contains more than one layer)"></span> + </label> + <input type="text" class="form-control" id="layer-subdir"> + </div> + <div class="form-group" id="layer-revision-ctrl"> + <label for="layer-git-ref"> + Git revision + <span class="glyphicon glyphicon-question-sign get-help" title="You can provide a Git branch, a tag or a commit SHA as the revision"></span> + </label> + <span style="display: block"> + <input type="text" class="form-control" id="layer-git-ref" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead" required> + </span> + <span class="help-block has-error" style="display:none;" id="invalid-layer-revision-hint">The "HEAD" branch is reserved (only allowed for the "Local Yocto Project" layers)</span> + </div> + </fieldset> + + <fieldset class="fields-apart-from-layer-name" id="local-dir" style="display:none;"> + <legend>Layer directory information</legend> + <div class="form-group"> + <label for="local-dir-path" class="control-label">Enter the absolute path to the layer directory</label> + <input type="text" class="form-control" id="local-dir-path" required/> + <p class="help-block" id="hintError-dir-path-starts-with-slash" style="display:none;">The absolute path must start with "/".</p> + <p class="help-block" id="hintError-dir-path" style="display:none;">The directory path cannot include spaces or any of these characters: \ ? % * : | " " < ></p> + </div> + </fieldset> + + <fieldset class="fields-apart-from-layer-name"> + <legend> + Layer dependencies + <small class="text-muted">(optional)</small> + <span class="glyphicon glyphicon-question-sign get-help heading-help" title="Other layers this layer depends upon"></span> + </legend> + <ul class="list-unstyled lead" id="layer-deps-list"> + </ul> + <div class="form-inline"> + <div class="form-group"> + <input type="text" autocomplete="off" data-minLength="1" data-autocomplete="off" data-provide="typeahead" placeholder="Type a layer name" id="layer-dependency" class="form-control"> + </div> + <button class="btn btn-default" id="add-layer-dependency-btn"> + Add layer + </button> + <span class="help-inline">You can only add layers Toaster knows about</span> + </fieldset> + <div class="top-air fields-apart-from-layer-name" id="form-actions"> + <button class="btn btn-primary btn-lg" data-toggle="modal" id="import-and-add-btn" data-target="#dependencies-message" disabled>Import and add to project</button> + <span class="help-inline" id="import-git-layer-and-add-hint" style="vertical-align: middle;">To import a layer you need to enter a layer name, a Git repository URL and a Git revision (branch, tag or commit)</span> + <span class="help-inline" id="import-local-dir-and-add-hint" style="vertical-align: middle;display:none;">To import a layer you need to enter a layer name and the absolute path to the layer directory</span> + </div> + </div> +</form> + + {% else %} {#project and project release#} + <div class="page-header"> + <h1>Import layer</h1> + </div> + <div class="alert alert-info" id="import-error" > + <h3>Unsupported project type</h3> + <p>This project does not support importing layers.</p> + <ul></ul> + </div> + + {% endif %} +</div> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/js-unit-tests.html b/poky/bitbake/lib/toaster/toastergui/templates/js-unit-tests.html new file mode 100644 index 0000000000..ca248962f0 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/js-unit-tests.html @@ -0,0 +1,47 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} +{% load static %} +{% block pagecontent %} + +<link rel="stylesheet" href="{% static 'css/qunit-1.18.0.css' %}" /> + +<script src="{% static 'js/qunit-1.18.0.js' %}"></script> + +<script src="{% static 'js/layerDepsModal.js' %}"></script> +<script src="{% static 'js/projectpage.js' %}"></script> + +<script src="{% static 'js/bootstrap.min.js' %}"></script> +<script src="{% static 'js/filtersnippet.js' %}"></script> +<script src="{% static 'js/importlayer.js' %}"></script> +<script src="{% static 'js/highlight.pack.js' %}"></script> +<script src="{% static 'js/layerBtn.js' %}"></script> +<script src="{% static 'js/layerDepsModal.js' %}"></script> +<script src="{% static 'js/projectpage.js' %}"></script> +<script src="{% static 'js/layerdetails.js' %}"></script> +<script src="{% static 'js/table.js' %}"></script> + +<script> + var ctx = { + tableUrl : '{% url 'projectlayers' project.pk %}', + projectId : {{project.pk}}, + } +</script> +<script src="{% static 'js/tests/test.js' %}"></script> + +<div id="qunit"></div> + +<input type="text" id="layers" placeholder="layers" ></input> +<input type="text" id="recipes" placeholder="recipes"></input> +<input type="text" id="projects" placeholder="projects"></input> +<input type="text" id="machines" placeholder="machines"></input> + +<!-- import layer dependency input typeahead --> +<input type="text" id="layer-dependency" style="display:none"></input> +<!-- project page input typeaheads --> +<input type="text" id="layer-add-input" style="display:none"></input> +<input type="text" id="machine-change-input" style="display:none"></input> +<!-- import layer dependency input typeahead on layer details edit layer --> +<input type="text" id="layer-dep-input" style="display:none"></input> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/landing.html b/poky/bitbake/lib/toaster/toastergui/templates/landing.html new file mode 100644 index 0000000000..70c7359fad --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/landing.html @@ -0,0 +1,67 @@ +{% extends "base.html" %} + +{% load static %} +{% load projecttags %} +{% load humanize %} + +{% block title %} Welcome to Toaster {% endblock %} +{% block pagecontent %} + <div class="row"> + <div class="jumbotron well-transparent"> + + <div class="col-md-6"> + <h1>This is Toaster</h1> + + <p>A web interface to <a href="http://www.openembedded.org">OpenEmbedded</a> and <a href="http://www.yoctoproject.org/tools-resources/projects/bitbake">BitBake</a>, the <a href="http://www.yoctoproject.org">Yocto Project</a> build system.</p> + + <p class="top-air"> + <a class="btn btn-info btn-lg" href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html#toaster-manual-setup-and-use"> + Toaster is ready to capture your command line builds + </a> + </p> + + {% if lvs_nos %} + {% if project_enable %} + <p class="top-air"> + <a class="btn btn-primary btn-lg" href="{% url 'newproject' %}"> + Create your first Toaster project to run manage builds + </a> + </p> + {% endif %} + {% else %} + <div class="alert alert-info lead top-air"> + Toaster has no layer information. Without layer information, you cannot run builds. To generate layer information you can: + <ul> + <li> + <a href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html#layer-source">Configure a layer source</a> + </li> + <li> + <a href="{% url 'newproject' %}">Create a project</a>, then import layers + </li> + </ul> + </div> + {% endif %} + + <ul class="list-unstyled lead"> + <li> + <a href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html"> + Read the Toaster manual + </a> + </li> + + <li> + <a href="https://wiki.yoctoproject.org/wiki/Contribute_to_Toaster"> + Contribute to Toaster + </a> + </li> + </ul> + </div> + + <div class="col-md-6"> + <img alt="Yocto Project Toaster" class="img-thumbnail" src="{% static 'img/toaster_bw.png' %}"/> + </div> + + </div> + </div> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/landing_not_managed.html b/poky/bitbake/lib/toaster/toastergui/templates/landing_not_managed.html new file mode 100644 index 0000000000..baa4b72c14 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/landing_not_managed.html @@ -0,0 +1,34 @@ +{% extends "base.html" %} + +{% load static %} +{% load projecttags %} +{% load humanize %} + +{% block title %} Welcome to Toaster {% endblock %} + +{% block pagecontent %} + + <div class="container"> + <div class="row"> + <!-- Empty - no build module --> + <div class="page-header top-air"> + <h1> + This page only works with Toaster in 'Build' mode + </h1> + </div> + <div class="alert alert-info lead"> + <p"> + The 'Build' mode allows you to configure and run your Yocto Project builds from Toaster. + <ul> + <li><a href="http://www.yoctoproject.org/docs/latest/toaster-manual/toaster-manual.html#intro-modes"> + Read about the 'Build' mode + </a></li> + <li><a href="/"> + View your builds + </a></li> + </ul> + </p> + </div> + </div> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/layer_btn.html b/poky/bitbake/lib/toaster/toastergui/templates/layer_btn.html new file mode 100644 index 0000000000..1580991a16 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/layer_btn.html @@ -0,0 +1,26 @@ +<a class="btn btn-danger btn-block layer-exists-{{data.pk}} layerbtn" data-layer='{ + "id": {{data.pk}}, + "name": "{{data.layer.name}}", + "xhrLayerUrl": "{% url "xhr_layer" extra.pid data.pk %}", + "layerdetailurl": "{% url 'layerdetails' extra.pid data.pk %}" + }' data-directive="remove" + {% if data.pk not in extra.current_layers %} + style="display:none;" + {% endif %} + > + <span class="glyphicon glyphicon-trash"></span> + Remove layer +</a> +<a class="btn btn-default btn-block layer-add-{{data.pk}} layerbtn" + data-layer='{ "id": {{data.pk}}, + "name": "{{data.layer.name}}", + "xhrLayerUrl": "{% url "xhr_layer" extra.pid data.pk %}", + "layerdetailurl": "{%url "layerdetails" extra.pid data.pk %}" + }' data-directive="add" + {% if data.pk in extra.current_layers %} + style="display:none;" + {% endif %} + > + <span class="glyphicon glyphicon-plus"></span> + Add layer +</a> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/layerdetails.html b/poky/bitbake/lib/toaster/toastergui/templates/layerdetails.html new file mode 100644 index 0000000000..e0069db80c --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/layerdetails.html @@ -0,0 +1,373 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} +{% load static %} + +{% block title %} {{layerversion.layer.name}} - {{project.name}} - Toaster {% endblock %} +{% block pagecontent %} + +<div id="delete-layer-modal" class="modal fade" tabindex="-1" role="dialog" + data-keyboard="false" data-backdrop="static"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-body"> + Are you sure you want to delete the <strong>{{layerversion.layer.name}}</strong> layer? + </div> + <div class="modal-footer"> + <button type="button" id="layer-delete-confirmed" class="btn + btn-primary">Delete layer</button> + <button type="button" class="btn btn-default btn-link" data-dismiss="modal">Cancel</button> + </div> + </div> + </div> +</div> + +<div class="row"> + <div class="col-md-12"> + <ul class="breadcrumb"> + <li> + <a href="{% url 'project' project.id %}">{{project.name}}</a> + <span class="divider">→</span> + </li> + <li><a href="{% url 'projectlayers' project.id %}">Compatible layers</a> + <span class="divider">→</span> + </li> + <li class="active"> + {{layerversion.layer.name}} ({{layerversion.get_vcs_reference|truncatechars:13}}) + </li> + </ul> + + {# If this is not an imported layer then hide the edit ui #} + {% if layerversion.layer_source != layer_source.TYPE_IMPORTED %} + <style scoped> + .glyphicon-edit { + display:none; + } + .delete-current-value{ + display: none; + } + li .glyphicon-trash { + display:none; + } + .add-deps { + display:none; + } + </style> + {% endif %} + + <script src="{% static 'js/layerdetails.js' %}"></script> + <script> + + $(document).ready(function(){ + var ctx = { + xhrUpdateLayerUrl : "{% url 'xhr_layer' project.id layerversion.pk %}", + layerVersion : { + name : "{{layerversion.layer.name}}", + id : {{layerversion.id}}, + commit: "{{layerversion.get_vcs_reference}}", + {%if layerversion.id in projectlayers %} + inCurrentPrj : true, + {% else %} + inCurrentPrj : false, + {% endif %} + layerdetailurl : "{% url 'layerdetails' project.id layerversion.id %}", + xhrLayerUrl: "{% url 'xhr_layer' project.id layerversion.id %}", + layer_source: {{layerversion.layer_source|json}}, + }, + layerSourceTypes: {{layer_source|json}}, + }; + + try { + layerDetailsPageInit(ctx); + } catch (e) { + document.write("Sorry, An error has occurred loading this page"); + console.warn(e); + } + }); + </script> + + <div class="page-header"> + {% if layerversion.layer.local_source_dir %} + <h1>{{layerversion.layer.name}} <small class="commit" style="display:none;"></small> + </h1> + {% else %} + <h1>{{layerversion.layer.name}} <small class="commit" + {% if layerversion.get_vcs_reference|length > 13 %} + data-toggle="tooltip" title="{{layerversion.get_vcs_reference}}" + {% endif %}>({{layerversion.get_vcs_reference|truncatechars:13}})</small> + </h1> + {% endif %} + </div> + <div class="row"> + <!-- container for tabs --> + <div class="col-md-8 tabbable"> + <div class="alert alert-info lead" id="alert-area" style="display:none"> + <button type="button" class="close" id="dismiss-alert">×</button> + <span id="alert-msg"></span> + </div> + + {% if layerversion.id not in projectlayers %} + <button id="add-remove-layer-btn" data-directive="add" class="btn btn-default btn-lg btn-block"> + <span class="glyphicon glyphicon-plus"></span> + Add the {{layerversion.layer.name}} layer to your project + </button> + {% else %} + <button id="add-remove-layer-btn" data-directive="remove" class="btn btn-default btn-block btn-lg btn-danger"> + <span class="glyphicon glyphicon-trash"></span> + Remove the {{layerversion.layer.name}} layer from your project + </button> + {% endif %} + + <ul class="nav nav-tabs"> + <li class="active"> + <a data-toggle="tab" href="#information" id="details-tab">Layer details</a> + </li> + <li> + <a data-toggle="tab" href="#recipes" class="text-muted" id="targets-tab">Recipes (<span class="table-count-recipestable"></span>)</a> + </li> + <li> + <a data-toggle="tab" href="#machines" class="text-muted" id="machines-tab">Machines (<span class="table-count-machinestable"></span>)</a> + </li> + </ul> + <div class="tab-content"> + + <!-- layer details pane --> + <div id="information" class="tab-pane active"> + <h3>Layer source code location</h3> + {% if layerversion.layer.local_source_dir %} + <dl class="dl-horizontal" id="directory-info"> + <dt> + Path to the layer directory + </dt> + <dd> + <code>{{layerversion.layer.local_source_dir}}</code> + </dd> + </dl> + {% else %} + <dl class="dl-horizontal" id="git-repo-info"> + <dt class=""> + <span class="glyphicon glyphicon-question-sign get-help" title="Fetch/clone URL of the repository"></span> + Repository URL + </dt> + <dd> + <span class="current-value">{{layerversion.layer.vcs_url}}</span> + {% if layerversion.get_vcs_link_url %} + <a href="{{layerversion.get_vcs_link_url}}/" class="glyphicon glyphicon-new-window" target="_blank"></a> + {% endif %} + <form id="change-repo-form" class="form-inline" style="display:none"> + <div class="form-group"> + <input type="text" class="form-control" value="{{layerversion.layer.vcs_url}}"> + </div> + </form> + </dd> + {% if layerversion.dirpath %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Subdirectory within the repository where the layer is located, if not in the root (usually only used if the repository contains more than one layer)"></span> + Repository subdirectory + </dt> + <dd> + <span class="text-muted" style="display:none">Not set</span> + <span class="current-value">{{layerversion.dirpath}}</span> + {% if layerversion.get_vcs_dirpath_link_url %} + <a href="{{layerversion.get_vcs_dirpath_link_url}}" class="glyphicon glyphicon-new-window" target="_blank"></a> + {% endif %} + <form id="change-subdir-form" class="form-inline" style="display:none;"> + <div class="form-group"> + <input type="text" class="form-control" value="{{layerversion.dirpath}}"> + </div> + </form> + </dd> + {% endif %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="The Git branch, tag or commit"></span> + Git revision + </dt> + <dd> + <span class="current-value">{{layerversion.get_vcs_reference}}</span> + <form style="display:none;" class="form-inline"> + <div class="form-group"> + <input type="text" class="form-control" value="{{layerversion.get_vcs_reference}}"> + </div> + </form> + </dd> + </dl> + {% endif %} + {% if layerversion.layer_source == layer_source.TYPE_IMPORTED %} + <button class="btn btn-default btn-lg" id="edit-layer-source" style="margin-left:220px;">Edit layer source code location</button> + {% endif %} + <form id="edit-layer-source-form" style="display:none;"> + <fieldset> + <legend class="radioLegend">Where is the layer source code?</legend> + <div class="radio"> + <label> + <input type="radio" name="source-location" id="repo" value="repo"> + In a <strong>Git repository</strong> + </label> + <p class="help-block" style="margin-left:20px;width:70%;">To build the layer Toaster must be able to access the Git repository, otherwise builds will fail. Toaster will fetch and checkout your chosen Git revision every time you start a build.</p> + </div> + <div class="radio" style="margin-top:15px;"> + <label> + <input type="radio" name="source-location" id="dir" value="dir" checked> + In a <strong>directory</strong> + </label> + <p class="help-block" style="margin-left:20px;width:70%;">Use this option for quick layer development, by simply providing the path to the layer source code.</p> + </div> + </fieldset> + + <fieldset id="layer-git"> + <legend>Git repository information</legend> + <div class="form-group"> + <label for="layer-git-repo-url"> + Git repository URL + <span class="glyphicon glyphicon-question-sign get-help" title="Fetch/clone URL of the repository. Currently, Toaster only supports Git repositories." ></span> + </label> + <input type="text" id="layer-git-repo-url" class="form-control" value="{{layerversion.layer.vcs_url|default_if_none:''}}"> + </div> + <div class="form-group"> + <label for="layer-subdir"> + Repository subdirectory + <span class="text-muted">(optional)</span> + <span class="glyphicon glyphicon-question-sign get-help" title="Subdirectory within the repository where the layer is located, if not in the root (usually only used if the repository contains more than one layer)"></span> + </label> + <input type="text" class="form-control" id="layer-subdir" value="{{layerversion.dirpath|default_if_none:''}}"> + </div> + <div class="form-group" id="layer-revision-ctrl"> + <label for="layer-git-ref">Git revision + <span class="glyphicon glyphicon-question-sign get-help" title="You can provide a Git branch, a tag or a commit SHA as the revision"></span> + </label> + <input type="text" class="form-control" id="layer-git-ref" value="{{layerversion.get_vcs_reference|default_if_none:''}}"> + <span class="help-inline" style="display:none;" id="invalid-layer-revision-hint"></span> + </div> + </fieldset> + + <fieldset id="layer-dir"> + <legend>Layer directory information</legend> + <div class="form-group"> + <label for="layer-dir-path"> + Enter the absolute path to the layer directory + </label> + <input type="text" id="layer-dir-path-in-details" class="form-control" value="{{layerversion.layer.local_source_dir}}" required> + </div> + </fieldset> + + <div style="margin-top:25px;"> + <a href="#" class="btn btn-primary btn-lg" id="save-changes-for-switch">Save changes</a> + <a href="#" class="btn btn-link btn-lg" id="cancel-changes-for-switch">Cancel</a> + </div> + </form> + + <h3 class="top-air">Layer dependencies + <span class="glyphicon glyphicon-question-sign get-help" title="Other layers this layer depends upon"></span> + </h3> + + <ul class="list-unstyled current-value lead" id="layer-deps-list"> + {% for ld in layerversion.dependencies.all %} + <li data-layer-id="{{ld.depends_on.id}}"> + <a data-toggle="tooltip" title="{{ld.depends_on.layer.vcs_url}} | {{ld.depends_on.get_vcs_reference}}" href="{% url 'layerdetails' project.id ld.depends_on.id %}">{{ld.depends_on.layer.name}}</a> + <span class="glyphicon glyphicon-trash " data-toggle="tooltip" title="Delete"></span> + </li> + {% endfor %} + </ul> + <form class="form-inline add-deps"> + <div class="form-group"> + <input class="form-control" type="text" autocomplete="off" data-minLength="1" data-autocomplete="off" placeholder="Type a layer name" id="layer-dep-input"> + </div> + <a class="btn btn-default" id="add-layer-dependency-btn" disabled="disabled"> + Add layer + </a> + <span class="help-block add-deps">You can only add layers Toaster knows about</span> + </form> + </div> + <!-- end layerdetails tab --> + <!-- targets tab --> + <div id="recipes" class="tab-pane"> + <!-- Recipe table --> + <div id="no-recipes-yet" class="alert alert-info" style="display:none"> + <p>Toaster does not have recipe information for the <strong> {{layerversion.layer.name}} </strong> layer.</p> + <p>Toaster learns about layers when you build them. If this layer provides any recipes, they will be listed here after you build the <strong> {{layerversion.layer.name}} </strong> layer.</p> + </div> + {% url 'layerrecipestable' project.id layerversion.id as xhr_table_url %} + {% with "recipestable" as table_name %} + {% with "Recipes" as title %} + {% include 'toastertable-simple.html' %} + {% endwith %} + {% endwith %} + </div> + + <div id="machines" class="tab-pane"> + + <div id="no-machines-yet" class="alert alert-info" style="display:none"> + <p>Toaster does not have machine information for the <strong> {{layerversion.layer.name}} </strong> layer.</p> + <p>Sadly, machine information cannot be obtained from builds, so this page will remain empty.</p> + </div> + + + <!-- Machines table --> + {% url 'layermachinestable' project.id layerversion.id as xhr_table_url %} + {% with "machinestable" as table_name %} + {% with "Machines" as title %} + {% include 'toastertable-simple.html' %} + {% endwith %} + {% endwith %} + </div> + </div> <!-- end tab content --> + </div> <!-- end tabable --> + + <div class="col-md-4"> <!-- info side panel --> + <div class="well"> + <h2>About {{layerversion.layer.name}}</h2> + <dl class="item-info"> + + <dt> + Summary + <span class="glyphicon glyphicon-question-sign get-help" title="One-line description of the layer"></span> + </dt> + <dd> + <span class="text-muted" style="display:none">Not set</span> + <span class="current-value">{{layerversion.layer.summary|default_if_none:''}}</span> + <form style="display:none; margin-bottom:20px; margin-top:5px;"> + <div class="form-group"> + <textarea class="form-control" rows="2">{% if layerversion.layer.summary %}{{layerversion.layer.summary}}{% endif %}</textarea> + </div> + <button class="btn btn-default change-btn" data-layer-prop="summary" type="button">Save</button> + <a href="#" class="btn btn-link cancel">Cancel</a> + </form> + <span class="glyphicon glyphicon-edit"></span> + <span class="glyphicon glyphicon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span> + </dd> + <dt> + Description + </dt> + <dd> + <span class="text-muted" style="display:none">Not set</span> + <span class="current-value">{{layerversion.layer.description|default_if_none:''}}</span> + <form style="display:none; margin-bottom:20px; margin-top:5px;"> + <div class="form-group"> + <textarea class="form-control" rows="6">{% if layerversion.layer.description %}{{layerversion.layer.description}}{% endif %}</textarea> + </div> + <button class="btn btn-default change-btn" data-layer-prop="description" type="button" >Save</button> + <a href="#" class="btn btn-link cancel">Cancel</a> + </form> + <span class="glyphicon glyphicon-edit"></span> + <span class="glyphicon glyphicon-trash delete-current-value" data-toggle="tooltip" title="Delete"></span> + </dd> + {% if layerversion.layer_source == layer_source.TYPE_LAYERINDEX %} + <dt>Layer index</dt> + <dd> + <a href="http://layers.openembedded.org/layerindex/branch/{{layerversion.release.name}}/layer/{{layerversion.layer.name}}">Layer index {{layerversion.layer.name}}</a> + </dd> + {% endif %} + </dl> + {# Only show delete link for imported layers #} + {% if layerversion.layer_source == layer_source.TYPE_IMPORTED %} + <i class="icon-trash text-danger"></i> + <a href="#delete-layer-modal" role="button" class="text-danger" + data-toggle="modal" data-target="#delete-layer-modal">Delete layer</a> + {% endif %} + </div> + </div> + </div> + </div> <!-- close column 12 div --> +</div> <!-- close top row div --> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/machine_btn.html b/poky/bitbake/lib/toaster/toastergui/templates/machine_btn.html new file mode 100644 index 0000000000..6debe65738 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/machine_btn.html @@ -0,0 +1,21 @@ +<a href="{% url 'project' extra.pid %}?setMachine={{data.name}}" class="btn btn-default btn-block layer-exists-{{data.layer_version.id}}" + {% if data.layer_version.pk not in extra.current_layers %} + style="display:none;" + {% endif %} +> + Select machine</a> +<a class="btn btn-default btn-block layerbtn +layer-add-{{data.layer_version.id}}" data-layer='{ "id": + {{data.layer_version.id}}, "name": "{{data.layer_version.layer.name}}", + "layerdetailurl": "{%url 'layerdetails' extra.pid data.layer_version.id %}", + "xhrLayerUrl": "{% url "xhr_layer" extra.pid data.layer_version.id %}" + }' data-directive="add" + {% if data.layer_version.pk in extra.current_layers %} + style="display:none;" + {% endif %} +> + <span class="glyphicon glyphicon-plus"></span> + Add layer + <span class="glyphicon glyphicon-question-sign get-help" title="To select this machine, you must first add the {{data.layer_version.layer.name}} layer to your project"></i> +</a> + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/mrb_section.html b/poky/bitbake/lib/toaster/toastergui/templates/mrb_section.html new file mode 100644 index 0000000000..c5b9fe90d3 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/mrb_section.html @@ -0,0 +1,301 @@ +{% load static %} +{% load humanize %} +{% load project_url_tag %} +<script src="{% static 'js/mrbsection.js' %}"></script> + +{% if mru %} + {% if mrb_type == 'project' %} + <h2> + Latest project builds + + {% if project.is_default %} + <span class="glyphicon glyphicon-question-sign get-help heading-help" data-original-title="Builds in this project cannot be started from Toaster: they are started from the command line"></span> + {% endif %} + </h2> + {% else %} + <div class="page-header"> + <h1>Latest builds</h1> + </div> + {% endif %} + + <div id="latest-builds"> + {% for build in mru %} + <div data-latest-build-result="{{build.id}}" class="alert build-result {% if build.outcome == build.SUCCEEDED %}alert-success{% elif build.outcome == build.FAILED %}alert-danger{% else %}alert-info{% endif %}"> + <!-- project title --> + {% if mrb_type != 'project' %} + <div class="row project-name"> + <div class="col-md-12"> + <small> + <a class="alert-link text-uppercase" href="{% project_url build.project %}"> + {{build.project.name}} + </a> + </small> + </div> + </div> + {% endif %} + + <div class="row" data-role="build-status-container"> + <div class="col-md-12"> + Loading... + </div> + </div> + </div> + {% endfor %} + </div> +{% endif %} + +<!-- build main template --> +<script id="build-template" type="text/x-jsrender"> + <div class="col-md-3"> + <!-- only show link for completed builds --> + <%if state == 'Succeeded' || state == 'Failed'%> + <a class="alert-link" href="<%:dashboard_url%>"> + <span data-toggle="tooltip" data-role="targets-text" title="Recipes: <%:targets%>"> + <%:targets_abbreviated%> + </span> + </a> + <%else targets_abbreviated !== ''%> + <span data-toggle="tooltip" data-role="targets-text" title="Recipes: <%:targets%>"> + <%:targets_abbreviated%> + </span> + <%else%> + Fetching recipe names... + <%/if%> + </div> + + <div data-build-state="<%:state%>"> + <%if state == 'Cloning'%> + <%include tmpl='#cloning-repos-build-template'/%> + <%else state == 'Parsing'%> + <%include tmpl='#parsing-recipes-build-template'/%> + <%else state == 'Queued'%> + <%include tmpl='#queued-build-template'/%> + <%else state == 'Succeeded' || state == 'Failed'%> + <%include tmpl='#succeeded-or-failed-build-template'/%> + <%else state == 'Cancelling'%> + <%include tmpl='#cancelling-build-template'/%> + <%else state == 'Starting'%> + <%include tmpl='#starting-template'/%> + <%else state == 'In Progress'%> + <%include tmpl='#in-progress-build-template'/%> + <%else state == 'Cancelled'%> + <%include tmpl='#cancelled-build-template'/%> + <%/if%> + </div> +</script> + +<!-- queued build --> +<script id="queued-build-template" type="text/x-jsrender"> + <div class="col-md-5"> + <span class="glyphicon glyphicon-question-sign get-help get-help-blue" + title="This build is waiting for the build directory to become available"> + </span> + + Build queued + </div> + + <div class="col-md-4"> + <!-- cancel button --> + <%include tmpl='#cancel-template'/%> + </div> +</script> + +<!-- cloning repos build --> +<script id="cloning-repos-build-template" type="text/x-jsrender"> + <!-- progress bar and parse completion percentage --> + <div data-role="build-status" class="col-md-4 col-md-offset-1 progress-info"> + <!-- progress bar --> + <div class="progress"> + <div id="repos-cloned-percentage-bar-<%:id%>" + style="width: <%:repos_cloned_percentage%>%;" + class="progress-bar"> + </div> + </div> + </div> + + <div class="col-md-4 progress-info"> + <!-- parse completion percentage --> + <span class="glyphicon glyphicon-question-sign get-help get-help-blue" + title="Toaster is cloning the repos required for your build"> + </span> + + Cloning <span id="repos-cloned-percentage-<%:id%>"><%:repos_cloned_percentage%></span>% complete + + <%include tmpl='#cancel-template'/%> + </div> +</script> + +<!-- parsing recipes build --> +<script id="parsing-recipes-build-template" type="text/x-jsrender"> + <!-- progress bar and parse completion percentage --> + <div data-role="build-status" class="col-md-4 col-md-offset-1 progress-info"> + <!-- progress bar --> + <div class="progress"> + <div id="recipes-parsed-percentage-bar-<%:id%>" + style="width: <%:recipes_parsed_percentage%>%;" + class="progress-bar"> + </div> + </div> + </div> + + <div class="col-md-4 progress-info"> + <!-- parse completion percentage --> + <span class="glyphicon glyphicon-question-sign get-help get-help-blue" + title="BitBake is parsing the layers required for your build"> + </span> + + Parsing <span id="recipes-parsed-percentage-<%:id%>"><%:recipes_parsed_percentage%></span>% complete + + <%include tmpl='#cancel-template'/%> + </div> +</script> + +<!-- in progress build; tasks still starting --> +<script id="starting-template" type="text/x-jsrender"> + <div class="col-md-5"> + <span class="glyphicon glyphicon-question-sign get-help get-help-blue" + title="This build is waiting for tasks to start"> + </span> + + Tasks starting... + </div> + + <div class="col-md-4"> + <!-- cancel button --> + <%include tmpl='#cancel-template'/%> + </div> +</script> + +<!-- in progress build; at least one task finished --> +<script id="in-progress-build-template" type="text/x-jsrender"> + <!-- progress bar and task completion percentage --> + <div data-role="build-status" class="col-md-4 col-md-offset-1 progress-info"> + <!-- progress bar --> + <div class="progress" id="build-pc-done-title-<%:id%>"> + <div id="build-pc-done-bar-<%:id%>" + style="width: <%:tasks_complete_percentage%>%;" + class="progress-bar"> + </div> + </div> + </div> + + <div class="col-md-4 progress-info"> + <!-- task completion percentage --> + <span id="build-pc-done-<%:id%>"><%:tasks_complete_percentage%></span>% of + tasks complete + + <!-- cancel button --> + <%include tmpl='#cancel-template'/%> + </div> +</script> + +<!-- cancelling build --> +<script id="cancelling-build-template" type="text/x-jsrender"> + <div class="col-md-9"> + Cancelling the build ... + </div> +</script> + +<!-- succeeded or failed build --> +<script id="succeeded-or-failed-build-template" type="text/x-jsrender"> + <!-- completed_on --> + <div class="col-md-2"> + <%:completed_on%> + </div> + + <!-- errors --> + <div class="col-md-2"> + <%if errors%> + <span class="glyphicon glyphicon-minus-sign"></span> + <a href="<%:dashboard_errors_url%>" class="alert-link"> + <%:errors%> error<%:errors_pluralise%> + </a> + <%/if%> + </div> + + <!-- warnings --> + <div class="col-md-2"> + <%if warnings%> + <span class="glyphicon glyphicon-warning-sign build-warnings"></span> + <a href="<%:dashboard_warnings_url%>" class="alert-link build-warnings"> + <%:warnings%> warning<%:warnings_pluralise%> + </a> + <%/if%> + </div> + + <!-- build time --> + <div class="col-md-3"> + Build time: + + <span data-role="data-recent-build-buildtime-field"> + <%if state == 'Succeeded'%> + <a class="alert-link" href="<%:buildtime_url%>"><%:buildtime%></a> + <%else%> + <%:buildtime%> + <%/if%> + </span> + + <!-- rebuild button --> + <%include tmpl='#rebuild-template'/%> + </div> +</script> + +<!-- cancelled build --> +<script id="cancelled-build-template" type="text/x-jsrender"> + <!-- build cancelled message --> + <div class="col-md-6"> + Build cancelled + </div> + + <!-- rebuild button --> + <div class="col-md-3"> + <%include tmpl='#rebuild-template'/%> + </div> +</script> + +<!-- rebuild button or no rebuild icon --> +<script id="rebuild-template" type="text/x-jsrender"> + <%if is_default_project_build%> + <!-- no rebuild info icon --> + <span class="pull-right glyphicon glyphicon-question-sign get-help <%if state == 'Succeeded'%>get-help-green<%else state == 'Failed'%>get-help-red<%else%>get-help-blue<%/if%>" + title="Builds in this project cannot be started from Toaster: they are started from the command line"> + </span> + <%else%> + <!-- rebuild button --> + <span class="rebuild-btn alert-link <%if state == 'Success'%>success<%else state == 'Failed'%>danger<%else%>info<%/if%> pull-right" + data-request-url="<%:rebuild_url%>" data-target='<%:build_targets_json%>'> + <span class="glyphicon glyphicon-repeat"></span> + Rebuild + </span> + <%/if%> +</script> + +<!-- cancel button or no cancel icon --> +<script id="cancel-template" type="text/x-jsrender"> + <%if is_default_project_build%> + <!-- no cancel icon --> + <span class="glyphicon glyphicon-question-sign get-help get-help-blue pull-right" title="Builds in this project cannot be cancelled from Toaster: they can only be cancelled from the command line"></span> + <%else%> + <!-- cancel button --> + <span class="cancel-build-btn pull-right alert-link" + data-buildrequest-id="<%:buildrequest_id%>" data-request-url="<%:cancel_url%>"> + <span class="glyphicon glyphicon-remove-circle"></span> + Cancel + </span> + <%/if%> +</script> + +<script> + $(document).ready(function () { + var ctx = { + mrbType : "{{mrb_type}}", + } + + try { + mrbSectionInit(ctx); + } catch (e) { + document.write("Sorry, An error has occurred loading this page"); + console.warn(e); + } + }); +</script> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/newcustomimage.html b/poky/bitbake/lib/toaster/toastergui/templates/newcustomimage.html new file mode 100644 index 0000000000..980179a406 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/newcustomimage.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} +{% load static %} +{% block pagecontent %} + +{% include "newcustomimage_modal.html" %} + +<div class="row"> + + {% include "projecttopbar.html" %} + + <div class="col-md-12"> + {% url table_name project.id as xhr_table_url %} + <h2>{{title}} (<span class="table-count-{{table_name}}">0</span>)</h2> + {% include "toastertable.html" %} + </div> + +</div> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html b/poky/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html new file mode 100644 index 0000000000..d448d3afc1 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/newcustomimage_modal.html @@ -0,0 +1,60 @@ +{% load static %} + +<script src="{% static 'js/newcustomimage_modal.js' %}"></script> +<script> + $(document).ready(function (){ + try { + newCustomImageModalInit(); + } catch (e) { + document.write("Sorry, An error has occurred loading this page"); + console.warn(e); + } + }); +</script> + +<div class="modal fade" id="new-custom-image-modal" aria-hidden="false"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3>New custom image</h3> + </div> + + <div class="modal-body"> + <!-- + this container is visible if there are multiple image recipes which could + be used as a basis for the new custom image; radio buttons are added to it + via newCustomImageModalSetRecipes() as required + --> + <div data-role="image-selector" style="display:none;"> + <h4>Which image do you want to customise?</h4> + <span class="help-block text-danger" id="invalid-recipe-help" style="display:none"></span> + <div data-role="image-selector-radios"></div> + <div class="air"></div> + </div> + + <h4>Name your custom image</h4> + + <div class="row"> + <div class="col-md-10"> + <p class="help-block">Image names must be unique. They should not contain spaces or capital letters, and the only allowed special character is dash (-). + </p> + <div class="form-group"> + <input type="text" class="form-control input-lg" placeholder="Type the custom image name" required> + </div> + <span class="help-block text-danger" id="invalid-name-help" style="display:none"></span> + </div> + </div> + </div> + + <div class="modal-footer"> + <button id="create-new-custom-image-btn" class="btn btn-primary btn-large" disabled> + <span data-role="submit-state">Create custom image</span> + <span data-role="loading-state" style="display:none"> + <i class="fa-pulse icon-spinner"></i> Creating custom image... + </span> + </button> + </div> + </div> + </div> +</div> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/newproject.html b/poky/bitbake/lib/toaster/toastergui/templates/newproject.html new file mode 100644 index 0000000000..acb614e9d3 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/newproject.html @@ -0,0 +1,138 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} + +{% block title %} Create a new project - Toaster {% endblock %} + +{% block pagecontent %} +<div class="row"> + <div class="col-md-12"> + <div class="page-header"> + <h1>Create a new project</h1> + </div> + {% if alert %} + <div class="alert alert-danger" role="alert">{{alert}}</div> + {% endif %} + + <form method="POST">{% csrf_token %} + <div class="form-group" id="validate-project-name"> + <label class="control-label">Project name <span class="text-muted">(required)</span></label> + <input type="text" class="form-control" required id="new-project-name" name="projectname"> + </div> + <p class="help-block text-danger" style="display: none;" id="hint-error-project-name">A project with this name exists. Project names must be unique.</p> +<!-- + <fieldset> + <label class="project-form">Project type</label> + <label class="project-form radio"><input type="radio" name="ptype" value="analysis" checked/> Analysis Project</label> + + {% if releases.count > 0 %} + <label class="project-form radio"><input type="radio" name="ptype" value="build" checked /> Build Project</label> + {% endif %} + </fieldset> --> + <input type="hidden" name="ptype" value="build" /> + + {% if releases.count > 0 %} + <div class="release form-group"> + {% if releases.count > 1 %} + <label class="control-label"> + Release + <span class="glyphicon glyphicon-question-sign get-help" title="The version of the build system you want to use"></span> + </label> + <select name="projectversion" id="projectversion" class="form-control"> + {% for release in releases %} + <option value="{{release.id}}" + {%if defaultbranch == release.name %} + selected + {%endif%} + >{{release.description}}</option> + {% endfor %} + </select> + <div class="row"> + <div class="col-md-4"> + {% for release in releases %} + <div class="helptext" id="description-{{release.id}}" style="display: none"> + <span class="help-block">{{release.helptext|safe}}</span> + </div> + {% endfor %} + {% else %} + <input type="hidden" name="projectversion" value="{{releases.0.id}}"/> + {% endif %} + </div> + </div> + </fieldset> + {% endif %} + <div class="top-air"> + <input type="submit" id="create-project-button" class="btn btn-primary btn-lg" value="Create project"/> + <span class="help-inline" style="vertical-align:middle;">To create a project, you need to enter a project name</span> + </div> + + </form> + <!-- + <div class="col-md-5 well"> + <span class="help-block"> + <h4>Toaster project types</h4> + <p>With a <strong>build project</strong> you configure and run your builds from Toaster.</p> + <p>With an <strong>analysis project</strong>, the builds are configured and run by another tool + (something like Buildbot or Jenkins), and the project only collects the information about the + builds (packages, recipes, dependencies, logs, etc). </p> + <p>You can read more on <a href="#">how to set up an analysis project</a> + in the Toaster manual.</p> + <h4>Release</h4> + <p>If you create a <strong>build project</strong>, you will need to select a <strong>release</strong>, + which is the version of the build system you want to use to run your builds.</p> + </div> --> + </div> + </div> + + <script type="text/javascript"> + $(document).ready(function () { + // hide the new project button + $("#new-project-button").hide(); + $('.btn-primary').attr('disabled', 'disabled'); + + // enable submit button when all required fields are populated + $("input#new-project-name").on('input', function() { + if ($("input#new-project-name").val().length > 0 ){ + $('.btn-primary').removeAttr('disabled'); + $(".help-inline").css('visibility','hidden'); + } + else { + $('.btn-primary').attr('disabled', 'disabled'); + $(".help-inline").css('visibility','visible'); + } + }); + + // show relevant help text for the selected release + var selected_release = $('select').val(); + $("#description-" + selected_release).show(); + + + $('select').change(function(){ + var new_release = $('select').val(); + $(".helptext").hide(); + $('#description-' + new_release).fadeIn(); + }); + + libtoaster.makeProjectNameValidation($("#new-project-name"), + $("#hint-error-project-name"), $("#validate-project-name"), + $(".btn-primary")); + + +/* // Hide the project release when you select an analysis project + function projectType() { + if ($("input[type='radio']:checked").val() == 'build') { + $('.release').fadeIn(); + } + else { + $('.release').fadeOut(); + } + } + projectType(); + + $('input:radio').change(function(){ + projectType(); + }); */ + }); + </script> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html b/poky/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html new file mode 100644 index 0000000000..a5d5893571 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/package_built_dependencies.html @@ -0,0 +1,99 @@ +{% extends "package_detail_base.html" %} +{% load projecttags %} + +{% block tabcontent %} + <ul class="nav nav-tabs"> + <li class=""> + <a href="{% url 'package_built_detail' build.id package.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="Shows the files produced by this package."></span> + Generated files ({{package.buildfilelist_package.count}}) + </a> + </li> + <li class="active"> + <a href="{% url 'package_built_dependencies' build.id package.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="Shows the runtime packages required by this package."></span> + Runtime dependencies ({{dependency_count}}) + </a> + </li> + </ul> + <div class="tab-content"> + <div class="tab-pane active" id="dependencies"> + {% ifequal runtime_deps|length 0 %} + <div class="alert alert-info"> + <strong>{{package.fullpackagespec}}</strong> has no runtime dependencies. + </div> + {% else %} + <div class="alert alert-info"> + <strong>{{package.fullpackagespec}}</strong> is <strong>not included</strong> in any image. This page shows you the projected runtime dependencies if you were to include <strong>{{package.fullpackagespec}}</strong> in an image. + </div> + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th>Package</th> + <th>Version</th> + <th class="sizecol col-md-2">Size</th> + </tr> + </thead> + <tbody> + {% for runtime_dep in runtime_deps %} + <tr {{runtime_dep.size|format_vpackage_rowclass}} > + {% if runtime_dep.size != -1 %} + <td> + <a href="{% url 'package_built_detail' build.id runtime_dep.depends_on_id %}"> + {{runtime_dep.name}} + </a> + </td> + {% else %} + <td> + {{runtime_dep.name|format_vpackage_namehelp}} + </td> + {% endif %} + <td>{{runtime_dep.version}}</td> + <td class="sizecol">{{runtime_dep.size|filtered_filesizeformat}}</td> + </tr> + {% endfor %} + </tbody> + </table> + {% endifequal %} + {% ifnotequal other_deps|length 0 %} + <h3>Other runtime relationships</h3> + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th>Package</th> + <th>Version</th> + <th class="sizecol col-md-2">Size</th> + <th> + <span class="glyphicon glyphicon-question-sign get-help" title="Five relationship types exist: recommends, suggests, provides, replaces and conflicts"></span> + Relationship type + </th> + </tr> + </thead> + <tbody> + {% for other_dep in other_deps %} + <tr {{other_dep.size|format_vpackage_rowclass}} > + {% if other_dep.size != -1 %} + <td> + <a href="{% url 'package_built_detail' build.id other_dep.depends_on_id %}"> + {{other_dep.name}} + </a> + </td> + {% else %} + <td> + {{other_dep.name|format_vpackage_namehelp}} + </td> + {% endif %} + <td>{{other_dep.version}}</td> + <td class="sizecol">{{other_dep.size|filtered_filesizeformat}}</td> + <td> + {{other_dep.dep_type_display}} + <span class="glyphicon glyphicon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></span> + </td> + </tr> + {% endfor %} + </tbody> + </table> + {% endifnotequal %} + </div> <!-- tab-pane --> + </div> <!-- tab-content --> +{% endblock tabcontent %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/package_built_detail.html b/poky/bitbake/lib/toaster/toastergui/templates/package_built_detail.html new file mode 100644 index 0000000000..0bdbc2a416 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/package_built_detail.html @@ -0,0 +1,65 @@ +{% extends "package_detail_base.html" %} +{% load projecttags %} + +{% block tabcontent %} + {% with packageFileCount=package.buildfilelist_package.count %} + <!-- Generated Files --> + {% if package.buildtargetlist_package.count == 0 %} + {# Not included case #} + <ul class="nav nav-tabs"> + <li class="active"> <a href="#"> + <span class="glyphicon glyphicon-question-sign get-help" title="Files added to a root file system when you include {{package.name}} in an image"></span> + Generated files ({{packageFileCount}}) + </a></li> + <li class=""><a href="{% url 'package_built_dependencies' build.id package.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="Projected runtime dependencies when you include {{package.name}} in an image"></span> + Runtime dependencies ({{dependency_count}}) + </a></li> + </ul> + <div class="tab-content"> + <div class="tab-pane active" id="files"> + <!-- Package file list or if empty, alert pane --> + {% if packageFileCount > 0 %} + <div class="alert alert-info"> + <strong>{{package.fullpackagespec}}</strong> is <strong>not included</strong> in any image. This page shows you the files that would be added to an image root file system with <strong>{{package.fullpackagespec}}</strong> included in it. + </div> + {% include "tablesort.html" %} + <tbody> + {% for file in objects %} + <tr> + <td class="path">{{file.path}}</td> + <td class="filesize sizecol">{{file.size|filtered_filesizeformat}}</td> + </tr> + {% endfor %} + </tbody> + </table> + + {% else %} + <div class="alert alert-info"> + <strong>{{package.fullpackagespec}}</strong> does not generate any files. + </div> + {% endif %} + + </div> <!-- tab-pane active --> + </div> <!-- tab-content --> + {% else %} + {# Included case #} + <div class="tab-content"> + <div class="tab-pane active"> + <div class="lead well"> + Package included in: + {% for itarget in package.buildtargetlist_package.all|dictsort:"target.target" %} + <a href="{% url 'package_included_detail' build.id itarget.target.id package.id %}"> + {% if forloop.counter0 > 0 %} + , + {% endif %} + {{itarget.target.target}} + </a> + {% endfor %} + </div> + </div> <!-- tab-pane active --> + </div> <!-- tab-content --> + {% endif %} + + {% endwith %} +{% endblock tabcontent %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/package_detail_base.html b/poky/bitbake/lib/toaster/toastergui/templates/package_detail_base.html new file mode 100644 index 0000000000..66f8e7f069 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/package_detail_base.html @@ -0,0 +1,169 @@ +{% extends "basebuilddetailpage.html" %} +{% load projecttags %} + +{% block title %} + {% if target %} + {{package.fullpackagespec}} - {{ target.target }} {{ build.machine }} - {{ build.project.name }} - Toaster + {% else %} + {{package.fullpackagespec}} - {{ build.target_set.all|dictsort:"target"|join:", " }} {{ build.machine }} - {{ build.project.name }} - Toaster + {% endif %} +{% endblock %} +{% block extraheadcontent %} + <!-- functions to format package 'installed_package' alias --> + <script> + function fmtAliasHelp(package_name, alias, hover) { + var r = null; + if (alias != null && alias != '') { + r = '<span class="text-muted"> as ' + alias + ' '; + r += '<span class="glyphicon glyphicon-question-sign get-help'; + if (hover) { + r+= ' hover-help'; + } + else { + r+= ' heading-help'; + } + r += '"'; + title = '<code>' + package_name + '</code> was renamed at packaging time and was installed on your system as <code>' + alias + '</code>'; + r += ' title="' + title + '">'; + r += '</span>'; + r += '</span>'; + document.write(r); + } + } + </script> +{% endblock extraheadcontent %} +{% block localbreadcrumb %} + {% if target %} + <li><a href="{% url "target" build.id target.id %}">{{target.target}}</a></li> + <li>{{package.fullpackagespec}} {% if package.alias %} as {{package.alias}}{% endif %}</li> + {% else %} + <li><a href="{% url "packages" build.id %}"> Packages </a></li> + <li>{{package.fullpackagespec}}</li> + {% endif %} +{% endblock localbreadcrumb %} + +{% block pagedetailinfomain %} + <div class="row"> + <div class="col-md-12"> + <div class="page-header build-data"> + {% block mainheading %} + <h1>{{package.fullpackagespec}}</h1> + {% endblock %} + </div> <!-- page-header --> + </div> <!-- col-md-12 page-header --> + </div> <!-- end row --> + + {% block twocolumns %} + <div class="row"> + <div class="col-md-8 tabbable"> + {% block tabcontent %} + {% endblock tabcontent %} + </div> <!-- row col-md-8 --> + + <div class="col-md-4"> + <div class="well"> + <h2>Package information</h2> + + <!-- info presented as definition list --> + <dl class="item-info"> + <dt> + Size + <span class="glyphicon glyphicon-question-sign get-help" title="The size of the package"></span> + </dt> + <dd> + {% comment %} + if recipe is absent, filesize is not 0 + {% endcomment %} + {% if package.recipe_id > 0 %} + {{package.size|filtered_filesizeformat}} + {% if target.file_size %} + ({{package.size|multiply:100|divide:target.file_size}}% of included package size) + {% endif %} + + {% endif %} + </dd> + + <dt> + License + <span class="glyphicon glyphicon-question-sign get-help" title="The license under which this package is distributed"></span> + </dt> + <dd>{{package.license}}</dd> + + {% comment %} + # Removed per review on 1/18/2014 until license data population + # problemse are resolved. + <dt> + License files + <i class="icon-question-sign get-help" title="Path to the license files that apply to the package"></i> + </dt> + <dd></dd> + {% endcomment %} + + <dt> + Recipe + <span class="glyphicon glyphicon-question-sign get-help" title="The name of the recipe building this package"></span> + </dt> + <dd> + {% if package.recipe_id > 0 %} + <a href="{% url "recipe" build.id package.recipe_id %}"> {{package.recipe.name}} </a> + {% else %} + {{package.recipe.name}} + {% endif %} + </dd> + + <dt> + Recipe version + <span class="glyphicon glyphicon-question-sign get-help" title="The version of the recipe building this package"></span> + </dt> + <dd>{{package.recipe.version}}</dd> + + <dt> + Layer + <span class="glyphicon glyphicon-question-sign get-help" title="The name of the layer providing the recipe that builds this package"></span> + </dt> + <dd> + {{package.recipe.layer_version.layer.name}} + {% if package.recipe.layer_version.layer.name|format_none_and_zero != "" %} + {% comment %} + # Removed per team meeting of 1/29/2014 until + # decision on index search algorithm + <a href="http://layers.openembedded.org" target="_blank"> + <i class="glyphicon glyphicon-share get-info"></i> + </a> + {% endcomment %} + {% endif %} + </dd> + <dt> + Layer branch + <span class="glyphicon glyphicon-question-sign get-help" title="The Git branch of the layer providing the recipe that builds this package"></span> + {%if package.recipe.layer_version.layer.local_source_dir %} + <dd> + <span class="text-muted">Not applicable</span> + <span class="glyphicon glyphicon-question-sign get-help" title="The source code of {{package.recipe.layer_version.layer.name}} is not in a Git repository, so there is no branch associated with it"></span> + </dd> + {% endif %} + </dt> + {% if not package.recipe.layer_version.layer.local_source_dir %} + <dd>{{package.recipe.layer_version.branch}}</dd> + {% endif %} + <dt> + Layer commit + <span class="glyphicon glyphicon-question-sign get-help" title="The Git commit of the layer providing the recipe that builds this package"></span> + {%if package.recipe.layer_version.layer.local_source_dir %} + <dd> + <span class="text-muted">Not applicable</span> + <span class="glyphicon glyphicon-question-sign get-help" title="The source code of {{package.recipe.layer_version.layer.name}} is not in a Git repository, so there is no commit associated with it"></span> + </dd> + {% endif %} + </dt> + + {% if not package.recipe.layer_version.layer.local_source_dir %} + <dd class="iscommit">{{package.recipe.layer_version.commit}}</dd> + {% endif %} + + </dl> + <div> <!-- end well --> + </div> <!-- end 4-column section --> + {% endblock twocolumns %} + </div> <!-- end row --> +{% endblock pagedetailinfomain %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html b/poky/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html new file mode 100644 index 0000000000..95e56ded26 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/package_included_dependencies.html @@ -0,0 +1,110 @@ +{% extends "package_detail_base.html" %} +{% load projecttags %} + +{% block mainheading %} + <h1> + {{package.fullpackagespec}} + <script> fmtAliasHelp("{{package.name}}", "{{package.alias}}", false) </script> + <small>({{target.target}})</small> + </h1> +{% endblock %} + +{% block tabcontent %} + {% with packageFileCount=package.buildfilelist_package.count %} + {% include "package_included_tabs.html" with active_tab="dependencies" %} + <div class="tab-content"> + <div class="tab-pane active" id="dependencies"> + {% ifnotequal runtime_deps|length 0 %} + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th>Package</th> + <th>Version</th> + <th class='sizecol col-md-2'>Size</th> + </tr> + </thead> + <tbody> + {% for runtime_dep in runtime_deps %} + <tr {{runtime_dep.size|format_vpackage_rowclass}} > + {% if runtime_dep.size != -1 %} + <td> + <a href="{% url 'package_included_detail' build.id target.id runtime_dep.depends_on_id %}"> + {{runtime_dep.name}} + </a> + <script>fmtAliasHelp("{{runtime_dep.name}}", "{{runtime_dep.alias}}", true)</script> + </td> + {% else %} + <td> + {{runtime_dep.name|format_vpackage_namehelp}} + </td> + {% endif %} + <td>{{runtime_dep.version}} </td> + <td class='sizecol'>{{runtime_dep.size|filtered_filesizeformat}} </td> + </tr> + {% endfor %} + </tbody> + </table> + {% else %} + <div class="alert alert-info"> + <strong>{{package.fullpackagespec}}</strong> has no runtime dependencies. + </div> + {% endifnotequal %} + + {% ifnotequal other_deps|length 0 %} + <h3>Other runtime relationships</h3> + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th>Package</th> + <th>Version</th> + <th class='sizecol col-md-2'>Size</th> + <th> + <span class="glyphicon glyphicon-question-sign get-help" title="Five relationship types exist: recommends, suggests, provides, replaces and conflicts"></span> + Relationship type + </th> + </tr> + </thead> + <tbody> + {% for other_dep in other_deps %} + {% if other_dep.installed %} + <tr {{other_dep.size|format_vpackage_rowclass}}> + {% if other_dep.size != -1 %} + <td> + <a href="{% url 'package_included_detail' build.id target.id other_dep.depends_on_id %}"> + {{other_dep.name}} + <script> + fmtAliasHelp("{{other_dep.name}}","{{other_dep.alias}}", true) + </script> + </a> + </td> + {% else %} + <td> + {{other_dep.name|format_vpackage_namehelp}} + </td> + {% endif %} + <td>{{other_dep.version}} </td> + <td class='sizecol'>{{other_dep.size|filtered_filesizeformat}} </td> + <td> + {{other_dep.dep_type_display}} + <span class="glyphicon glyphicon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></span> + </td> + </tr> + {% else %} + <tr class="text-muted"> + <td>{{other_dep.name}}</td> + <td>{{other_dep.version}}</td> + <td></td> + <td> + {{other_dep.dep_type_display}} + <span class="glyphicon glyphicon-question-sign get-help hover-help" title="{{other_dep.dep_type_help}}" ></span> + </td> + </tr> + {% endif %} + {% endfor %} + </tbody> + </table> + {% endifnotequal %} + </div> <!-- end tab-pane --> + </div> <!-- end tab content --> + {% endwith %} +{% endblock tabcontent %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/package_included_detail.html b/poky/bitbake/lib/toaster/toastergui/templates/package_included_detail.html new file mode 100644 index 0000000000..568e2f235b --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/package_included_detail.html @@ -0,0 +1,44 @@ +{% extends "package_detail_base.html" %} +{% load projecttags %} + +{% block mainheading %} + <h1> + {{package.fullpackagespec}} + <script> + fmtAliasHelp("{{package.name}}", "{{package.alias}}", false) + </script> + <small>({{target.target}})</small> + </h1> +{% endblock %} + +{% block tabcontent %} +{% with packageFileCount=package.buildfilelist_package.count %} + {% include "package_included_tabs.html" with active_tab="detail" %} + <div class="tab-content"> + <div class="tab-pane active" id="files"> + {% if packageFileCount > 0 %} + {% include "tablesort.html" %} + <tbody> + {% for file in objects %} + <tr> + <td class="path"> + <a href="{% url 'dirinfo_filepath' build.id target.id file.path %}"> + {{file.path}} + </a> + </td> + <td class="filesize sizecol" >{{file.size|filtered_filesizeformat}}</td> + </tr> + {% endfor %} + </tbody> + </table> + + {% else %} + <div class="alert alert-info"> + <strong>{{package.fullpackagespec}}</strong> does not generate any files. + </div> + {% endif %} + </div> <!-- end tab-pane --> + </div> <!-- end tab content --> + +{% endwith %} +{% endblock tabcontent %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html b/poky/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html new file mode 100644 index 0000000000..fb310c7fc7 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/package_included_reverse_dependencies.html @@ -0,0 +1,50 @@ +{% extends "package_detail_base.html" %} +{% load projecttags %} + +{% block mainheading %} + <h1> + {{package.fullpackagespec}} + <script> fmtAliasHelp("{{package.name}}", "{{package.alias}}", false) </script> + <small>({{target.target}})</small> + </h1> +{% endblock %} + +{% block tabcontent %} + {% with packageFileCount=package.buildfilelist_package.count %} + {% include "package_included_tabs.html" with active_tab="reverse" %} + <div class="tab-content"> + <div class="tab-pane active" id="brought-in-by"> + + {% ifequal reverse_count 0 %} + <div class="alert alert-info"> + <strong>{{package.fullpackagespec}}</strong> has no reverse runtime dependencies. + </div> + {% else %} + {% include "tablesort.html" %} + <tbody> + {% for reverse_dep in objects %} + <tr {% if reverse_dep.size %}{{reverse_dep.size|format_vpackage_rowclass}}{%endif%} > + {% if reverse_dep.size != -1 %} + <td> + <a href="{% url 'package_included_detail' build.id target.id reverse_dep.package_id %}"> + {{reverse_dep.package.name}} + </a> + <script>fmtAliasHelp("{{reverse_dep.package.name}}", "{{reverse_dep.alias}}", true)</script> + </td> + {% else %} + <td> + {{reverse_dep.name|format_vpackage_namehelp}} + </td> + {% endif %} + + <td>{{reverse_dep.package.version}} </td> + <td class='sizecol'>{{reverse_dep.package.size|filtered_filesizeformat}} </td> + </tr> + {% endfor %} + </tbody> + </table> + {% endifequal %} + </div> <!-- end tab-pane --> + </div> <!-- end tab content --> + {% endwith %} +{% endblock tabcontent %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/package_included_tabs.html b/poky/bitbake/lib/toaster/toastergui/templates/package_included_tabs.html new file mode 100644 index 0000000000..e89fa211c8 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/package_included_tabs.html @@ -0,0 +1,33 @@ + + <ul class="nav nav-tabs"> + {% if active_tab == "detail" %} + <li class="active"> + {% else %} + <li class=""> + {% endif %} + <a href="{% url 'package_included_detail' build.id target.id package.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="The files this package adds to the image root file system"></span> + Files in root file system ({{packageFileCount}}) + </a> + </li> + {% if active_tab == "dependencies" %} + <li class="active"> + {% else %} + <li class=""> + {% endif %} + <a href="{% url 'package_included_dependencies' build.id target.id package.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="Package runtime dependencies"></span> + Runtime dependencies ({{dependency_count}}) + </a> + </li> + {% if active_tab == "reverse" %} + <li class="active"> + {% else %} + <li class=""> + {% endif %} + <a href="{% url 'package_included_reverse_dependencies' build.id target.id package.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="The package runtime reverse dependencies (i.e. the packages in this image that depend on this package). Reverse dependencies reflect only the 'depends' dependency type"></span> + Reverse runtime dependencies ({{reverse_count}}) + </a> + </li> + </ul> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/pkg_add_rm_btn.html b/poky/bitbake/lib/toaster/toastergui/templates/pkg_add_rm_btn.html new file mode 100644 index 0000000000..303faecbd4 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/pkg_add_rm_btn.html @@ -0,0 +1,34 @@ +{# TODO move to snippets dir #} +{% if data.is_locale_package %} +<p class="text-center"> + <span class="text-muted">Locale package</span> + <span class="glyphicon glyphicon-question-sign get-help hover-help" + title="This package is included in your image + based on the locale specified in the IMAGE_LINGUAS variable" + style="visibility: hidden;"> + </span> +</p> + +{% else %} + +<div id="package-btn-cell-{{data.pk}}"> + <div style="display: none; font-size: 11px; line-height: 1.3;" class="tooltip-inner inline-notification"></div> + <button class="btn btn-block btn-danger add-rm-package-btn" data-directive="remove" data-id="{{data.pk}}" data-package-url="{% url 'xhr_customrecipe_packages' extra.recipe_id data.pk %}" data-name="{{data.name}}" style=" + {% if data.pk not in extra.current_packages %} + display:none + {% endif %} + "> + <i class="icon-trash no-tooltip"></i> + Remove package + </button> + <button class="btn btn-default btn-block add-rm-package-btn" data-directive="add" data-id="{{data.pk}}" data-package-url="{% url 'xhr_customrecipe_packages' extra.recipe_id data.pk %}" data-name="{{data.name}}" style=" + {% if data.pk in extra.current_packages %} + display:none + {% endif %} + "> + <i class="glyphicon glyphicon-plus"></i> + Add package + </button> +</div> + +{% endif %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/project.html b/poky/bitbake/lib/toaster/toastergui/templates/project.html new file mode 100644 index 0000000000..11603d1e12 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/project.html @@ -0,0 +1,161 @@ +{% extends "baseprojectpage.html" %} + +{% load projecttags %} +{% load humanize %} +{% load static %} + +{% block title %} Configuration - {{project.name}} - Toaster {% endblock %} +{% block projectinfomain %} + +<script src="{% static 'js/layerDepsModal.js' %}"></script> +<script src="{% static 'js/projectpage.js' %}"></script> +<script> + $(document).ready(function (){ + var ctx = { + testReleaseChangeUrl: "{% url 'xhr_testreleasechange' project.id %}", + }; + + try { + projectPageInit(ctx); + } catch (e) { + document.write("Sorry, An error has occurred loading this page"); + console.warn(e); + } + }); +</script> + +<div id="delete-project-modal" class="modal fade" tabindex="-1" role="dialog" data-backdrop="static" data-keyboard="false"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <h4>Are you sure you want to delete this project?</h4> + </div> + <div class="modal-body"> + <p>Deleting the <strong class="project-name"></strong> project + will:</p> + <ul> + <li>Cancel its builds currently in progress</li> + <li>Remove its configuration information</li> + <li>Remove its imported layers</li> + <li>Remove its custom images</li> + <li>Remove all its build information</li> + </ul> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-primary" id="delete-project-confirmed"> + <span data-role="submit-state">Delete project</span> + <span data-role="loading-state" style="display:none"> + <span class="fa-pulse"> + <i class="fa-pulse icon-spinner"></i> + </span> + Deleting project... + </span> + </button> + <button type="button" class="btn btn-link" data-dismiss="modal">Cancel</button> + </div> + </div><!-- /.modal-content --> + </div><!-- /.modal-dialog --> +</div> + + +<div class="row" id="project-page" style="display:none"> + <div class="col-md-6"> + <div class="well well-transparent" id="machine-section"> + <h3>Machine</h3> + + <p class="lead"><span id="project-machine-name"></span> <span class="glyphicon glyphicon-edit" id="change-machine-toggle"></span></p> + + <form id="select-machine-form" style="display:none;" class="form-inline"> + <span class="help-block">Machine suggestions come from the list of layers added to your project. If you don't see the machine you are looking for, <a href="{% url 'projectmachines' project.id %}">check the full list of machines</a></span> + <div class="form-group" id="machine-input-form"> + <input class="form-control" id="machine-change-input" autocomplete="off" value="" data-provide="typeahead" data-minlength="1" data-autocomplete="off" type="text"> + </div> + <button id="machine-change-btn" class="btn btn-default" type="button">Save</button> + <a href="#" id="cancel-machine-change" class="btn btn-link">Cancel</a> + <span class="help-block text-danger" id="invalid-machine-name-help" style="display:none">A valid machine name cannot include spaces.</span> + <p class="form-link"><a href="{% url 'projectmachines' project.id %}">View compatible machines</a></p> + </form> + </div> + + <div class="well well-transparent" id="distro-section"> + <h3>Distro</h3> + + <p class="lead"><span id="project-distro-name"></span> <span class="glyphicon glyphicon-edit" id="change-distro-toggle"></span></p> + + <form id="select-distro-form" style="display:none;" class="form-inline"> + <span class="help-block">Distro suggestions come from the Layer Index</a></span> + <div class="form-group"> + <input class="form-control" id="distro-change-input" autocomplete="off" value="" data-provide="typeahead" data-minlength="1" data-autocomplete="off" type="text"> + </div> + <button id="distro-change-btn" class="btn btn-default" type="button">Save</button> + <a href="#" id="cancel-distro-change" class="btn btn-link">Cancel</a> + <p class="form-link"><a href="{% url 'projectdistros' project.id %}">View compatible distros</a></p> + </form> + </div> + + <div class="well well-transparent"> + <h3>Most built recipes</h3> + + <div class="alert alert-info" style="display:none" id="no-most-built"> + <h4>You haven't built any recipes yet</h4> + <p class="form-link"><a href="{% url 'projectimagerecipes' project.id %}">Choose a recipe to build</a></p> + </div> + + <ul class="list-unstyled lead" id="freq-build-list"> + </ul> + <button class="btn btn-primary" id="freq-build-btn" disabled="disabled">Build selected recipes</button> + </div> + + <div class="well well-transparent"> + <h3>Project release</h3> + + <p class="lead"><span id="project-release-title"></span> + + <!-- Comment out the ability to change the project release, until we decide what to do with this functionality --> + + <!--i title="" data-original-title="" id="release-change-toggle" class="icon-pencil"></i--> + </p> + + <!-- Comment out the ability to change the project release, until we decide what to do with this functionality --> + + <!--form class="form-inline" id="change-release-form" style="display:none;"> + <select></select> + <button class="btn" style="margin-left:5px;" id="change-release-btn">Change</button> <a href="#" id="cancel-release-change" class="btn btn-link">Cancel</a> + </form--> + </div> + </div> + + <div class="col-md-6"> + <div class="well well-transparent" id="layer-container"> + <h3>Layers <span class="counter">(<span id="project-layers-count"></span>)</span> + <span title="OpenEmbedded organises recipes and machines into thematic groups called <strong>layers</strong>. Click on a layer name to see the recipes and machines it includes." class="glyphicon glyphicon-question-sign get-help"></span> + </h3> + + <div class="alert alert-warning" id="no-layers-in-project" style="display:none"> + <h4>This project has no layers</h4> + In order to build this project you need to add some layers first. For that you can: + <ul> + <li><a href="{% url 'projectlayers' project.id %}">Choose from the layers compatible with this project</a></li> + <li><a href="{% url 'importlayer' project.id %}">Import a layer</a></li> + <li><a href="http://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#understanding-and-creating-layers" target="_blank">Read about layers in the documentation</a></li> + <li>Or type a layer name below</li> + </ul> + </div> + + <form class="form-inline"> + <div class="form-group"> + <input id="layer-add-input" class="form-control" autocomplete="off" placeholder="Type a layer name" data-minlength="1" data-autocomplete="off" data-provide="typeahead" data-source="" type="text"> + </div> + <button id="add-layer-btn" class="btn btn-default" disabled>Add layer</button> + <p class="form-link"> + <a href="{% url 'projectlayers' project.id %}" id="view-compatible-layers">View compatible layers</a> + <span class="text-muted">|</span> + <a href="{% url 'importlayer' project.id %}">Import layer</a> + </p> + </form> + + <ul class="list-unstyled lead" id="layers-in-project-list"> + </ul> + </div> +</div> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html b/poky/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html new file mode 100644 index 0000000000..a5fed2dd41 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/projectbuilds-toastertable.html @@ -0,0 +1,65 @@ +{% extends 'base.html' %} + +{% load static %} + +{% block extraheadcontent %} +<link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" type='text/css'> +<link rel="stylesheet" href="{% static 'css/jquery-ui.structure.min.css' %}" type='text/css'> +<link rel="stylesheet" href="{% static 'css/jquery-ui.theme.min.css' %}" type='text/css'> +<script src="{% static 'js/jquery-ui.min.js' %}"> +</script> +{% endblock %} + +{% block title %} {{title}} - {{project.name}} - Toaster {% endblock %} + +{% block pagecontent %} +<div class="row"> + + {% include "projecttopbar.html" %} + + <div class="col-md-12"> + {% with mru=mru mrb_type=mrb_type %} + {% include 'mrb_section.html' %} + {% endwith %} + + <h2 class="top-air" data-role="page-title"></h2> + + {% if not build_in_progress_none_completed %} + {% url 'projectbuilds' project.id as xhr_table_url %} + {% include 'toastertable.html' %} + {% endif %} + </div> + + <script> + $(document).ready(function () { + // title + var tableElt = $("#{{table_name}}"); + var titleElt = $("[data-role='page-title']"); + + tableElt.on("table-done", function (e, total, tableParams) { + var title = "All project builds"; + + if (tableParams.search || tableParams.filter) { + if (total === 0) { + title = "No project builds found"; + } + else if (total > 0) { + title = total + " project build" + (total > 1 ? 's' : '') + " found"; + } + } + + if (total === 0) { + titleElt.hide(); + } else { + titleElt.show(); + titleElt.text(title); + } + }); + + // highlight builds tab + $("#topbar-builds-tab").addClass("active") + }); + </script> + +</div> +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/projectbuilds.html b/poky/bitbake/lib/toaster/toastergui/templates/projectbuilds.html new file mode 100644 index 0000000000..50697a159b --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/projectbuilds.html @@ -0,0 +1,118 @@ +{% extends "baseprojectbuildspage.html" %} +{% load projecttags %} +{% load humanize %} + +{% block title %} Builds - {{project.name}} - Toaster {% endblock %} +{% block extraheadcontent %} +<link rel="stylesheet" href="/static/css/jquery-ui.min.css" type='text/css'> +<link rel="stylesheet" href="/static/css/jquery-ui.structure.min.css" type='text/css'> +<link rel="stylesheet" href="/static/css/jquery-ui.theme.min.css" type='text/css'> +<script src="/static/js/jquery-ui.min.js"></script> +<script src="/static/js/filtersnippet.js"></script> +{% endblock %} + +{% block projectinfomain %} + +<script> + // initialize the date range controls + $(document).ready(function () { + date_init('started_on','{{last_date_from}}','{{last_date_to}}','{{dateMin_started_on}}','{{dateMax_started_on}}','{{daterange_selected}}'); + date_init('completed_on','{{last_date_from}}','{{last_date_to}}','{{dateMin_completed_on}}','{{dateMax_completed_on}}','{{daterange_selected}}'); + }); +</script> + + {% with mrb_type='project' %} + {% include "mrb_section.html" %} + {% endwith %} + + <h2> + {% if request.GET.filter and objects.paginator.count > 0 or request.GET.search and objects.paginator.count > 0 %} + {{objects.paginator.count}} project build{{objects.paginator.count|pluralize}} found + {%elif request.GET.filter and objects.paginator.count == 0 or request.GET.search and objects.paginator.count == 0 %} + No project builds found + {%else%} + All project builds + {%endif%} + <i class="icon-question-sign get-help heading-help" title="This page lists all the builds for the current project"></i> + </h2> + + + {% if objects.paginator.count == 0 %} + {% if request.GET.filter or request.GET.search %} + <div class="row"> + <div class="alert"> + <form class="no-results input-append" id="searchform"> + <input id="search" name="search" class="input-xxlarge" type="text" value="{{request.GET.search}}"/>{% if request.GET.search %}<a href="javascript:$('#search').val('');searchform.submit()" class="input-append-addon btn" tabindex="-1"><i class="glyphicon glyphicon-remove"></i></a>{% endif %} + <button class="btn" type="submit" value="Search">Search</button> + <button class="btn btn-link" onclick="javascript:$('#search').val('');searchform.submit()">Show all builds</button> + </form> + </div> + </div> + {% else %} + <div class="alert alert-info"> + <p class="lead"> + This project has no builds. + </p> + </div> + {% endif %} + + {% else %} + + {% include "basetable_top.html" %} + <!-- Table data rows; the order needs to match the order of "tablecols" definitions; and the <td class value needs to match the tablecols clclass value for show/hide buttons to work --> + {% for build in objects %} {# if we have a build, just display it #} + <tr class="data"> + <td class="outcome"><a href="{% url "builddashboard" build.id %}">{%if build.outcome == build.SUCCEEDED%}<i class="icon-ok-sign success"></i>{%elif build.outcome == build.FAILED%}<i class="icon-minus-sign error"></i>{%else%}{%endif%}</a> + {% if build.cooker_log_path %} + + <a href="{% url 'build_artifact' build.id "cookerlog" build.id %}"> + <i class="icon-download-alt" title="Download build log"></i> + </a> + {% endif %} + </td> + + <td class="target"> + {% for t in build.target_set.all %} + <a href="{% url "builddashboard" build.id %}"> + {% if t.task %} + {{t.target}}:{{t.task}} + {% else %} + {{t.target}} + {% endif %} + </a> <br /> + {% endfor %} + </td> + <td class="machine"><a href="{% url "builddashboard" build.id %}">{{build.machine}}</a></td> + <td class="started_on"><a href="{% url "builddashboard" build.id %}">{{build.started_on|date:"d/m/y H:i"}}</a></td> + <td class="completed_on"><a href="{% url "builddashboard" build.id %}">{{build.completed_on|date:"d/m/y H:i"}}</a></td> + <td class="failed_tasks error"> + {% query build.task_build outcome=4 order__gt=0 as exectask%} + {% if exectask.count == 1 %} + <a href="{% url "task" build.id exectask.0.id %}">{{exectask.0.recipe.name}}.{{exectask.0.task_name}}</a> + <a href="{% url 'build_artifact' build.id "tasklogfile" exectask.0.id %}"> + <i class="icon-download-alt" title="" data-original-title="Download task log file"></i> + </a> + {% elif exectask.count > 1%} + <a href="{% url "tasks" build.id %}?filter=outcome%3A4">{{exectask.count}} task{{exectask.count|pluralize}}</a> + {%endif%} + </td> + <td class="errors.count"> + {% if build.errors.count %} + <a class="errors.count error" href="{% url "builddashboard" build.id %}#errors">{{build.errors.count}} error{{build.errors.count|pluralize}}</a> + {%endif%} + </td> + <td class="warnings.count">{% if build.warnings.count %}<a class="warnings.count warning" href="{% url "builddashboard" build.id %}#warnings">{{build.warnings.count}} warning{{build.warnings.count|pluralize}}</a>{%endif%}</td> + <td class="time"><a href="{% url "buildtime" build.id %}">{{build.timespent_seconds|sectohms}}</a></td> + <td class="output"> + {% if build.outcome == build.SUCCEEDED %} + <a href="{%url "builddashboard" build.id%}#images">{{fstypes|get_dict_value:build.id}}</a> + {% endif %} + </td> + </tr> + {% endfor %} + + + {% include "basetable_bottom.html" %} +{% endif %} + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/projectconf.html b/poky/bitbake/lib/toaster/toastergui/templates/projectconf.html new file mode 100644 index 0000000000..933c588f34 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/projectconf.html @@ -0,0 +1,1042 @@ +{% extends "baseprojectpage.html" %} +{% load projecttags %} +{% load humanize %} + +{% block title %} BitBake variables - {{project.name}} - Toaster {% endblock %} +{% block projectinfomain %} + +<h2>Bitbake variables</h2> +<div> + <dl> + {% if distro_defined %} + <dt> + <span class="js-config-var-name js-config-var-managed-name">DISTRO</span> + <span class="glyphicon glyphicon-question-sign get-help" title="The short name of the distribution. If the variable is blank, meta/conf/distro/defaultsetup.conf will be used"></span> + </dt> + <dd class="variable-list"> + <span class="lead" id="distro">{{distro}}</span> + <span class="glyphicon glyphicon-edit" id="change-distro-icon"></span> + <form id="change-distro-form" class="form-inline" style="display:none;"> + <div id="edit-distro-name-div" class="form-group"> + <input type="text" class="form-control" id="new-distro" value="{{distro}}"> + </div> + <button id="apply-change-distro" class="btn btn-default" type="button">Save</button> + <button id="cancel-change-distro" type="button" class="btn btn-link">Cancel</button> + <span class="help-block" id="distro-error-message"></span> + </form> + </dd> + {% endif %} + + {% if dl_dir_defined %} + <dt> + <span class="js-config-var-name js-config-var-managed-name">DL_DIR</span> + <span class="glyphicon glyphicon-question-sign get-help" title="Absolute path to the directory used to store downloads required for your builds. By default, Toaster projects share the same downloads directory"></span> + </dt> + <dd class="variable-list"> + <span id="dl_dir" class="lead {% if not dl_dir %} text-muted {% endif %}">{% if dl_dir %}{{dl_dir}}{%else%}Not set{%endif%}</span> + <span class="glyphicon glyphicon-edit" id="change-dl_dir-icon"></span> + <form id="change-dl_dir-form" class="form-inline" style="display:none;"> + <div class="form-group" id="validate-dl_dir"> + <input type="text" class="form-control" id="new-dl_dir" placeholder="Type an absolute path"> + </div> + <button id="apply-change-dl_dir" class="btn btn-default" type="button">Save</button> + <button id="cancel-change-dl_dir" type="button" class="btn btn-link">Cancel</button> + <p class="help-block" id="hintError-dl_dir" style="display:none;">The directory path cannot include spaces or any of these characters: \ ? % * : | " " < ></p> + <p class="help-block" id="hintError-initialChar-dl_dir" style="display:none;">The directory path should either start with a /, e.g. /home/toaster/downloads; or with a variable, e.g. ${TOPDIR}/downloads.</p> + </form> + </dd> + {% endif %} + + {% if fstypes_defined %} + <dt> + <span class="js-config-var-name js-config-var-managed-name">IMAGE_FSTYPES</span> + <span class="glyphicon glyphicon-question-sign get-help" title="Formats of root file system images that you want to create"></span> + </dt> + <dd class="variable-list"> + <span class="lead" id="image_fstypes">{{fstypes}}</span> + <span class="glyphicon glyphicon-edit" id="change-image_fstypes-icon"></span> + <form id="change-image_fstypes-form" style="display:none;"> + <label>Type the image types you want to build:</label> + <div class="form-group form-inline" id="validate-image_fstypes"> + <input type="text" class="form-control "id="new-imagefs_types"> + <button id="apply-change-image_fstypes" type="button" class="btn btn-default">Save</button> + <button id="cancel-change-image_fstypes" type="button" class="btn btn-link">Cancel</button> + </div> + <p class="help-block text-danger" style="display:none;" id="hintError-image-fs_type">A valid image type cannot include underscores</p> + <p class="help-block text-danger" style="display:none;" id="fstypes-error-message">You must select at least one image type</p> + <label>Or choose from known image types:</label> + <input id="filter-image_fstypes" type="text" placeholder="Search image types" class="form-control"> + <div id="all-image_fstypes" class="scrolling"></div> + </form> + </dd> + {% endif %} + + {% if image_install_append_defined %} + <dt> + <span class="js-config-var-name js-config-var-managed-name">IMAGE_INSTALL_append</span> + <span class="glyphicon glyphicon-question-sign get-help" title="Specifies additional packages to install into an image. If your build creates more than one image, the packages will be installed in all of them"></span> + </dt> + <dd class="variable-list"> + <span id="image_install" class="lead {% if not image_install_append %} text-muted {%endif%}">{% if image_install_append %}{{image_install_append}}{%else%}Not set{%endif%}</span> + <span class="glyphicon glyphicon-edit" id="change-image_install-icon"></span> + <span class="glyphicon glyphicon-trash" id="delete-image_install-icon" {% if image_install_append %}{%else%}style="display:none;"{%endif%}></span> + <form id="change-image_install-form" class="form-inline" style="display:none;"> + <div class="row"> + <div class="col-md-4"> + <span class="help-block">To set IMAGE_INSTALL_append to more than one package, type the package names separated by a space.</span> + </div> + </div> + <div class="form-group"> + <input type="text" class="form-control" id="new-image_install" placeholder="Type one or more package names"> + </div> + <button id="apply-change-image_install" class="btn btn-default" type="button">Save</button> + <button id="cancel-change-image_install" type="button" class="btn btn-link">Cancel</button> + </form> + </dd> + {% endif %} + + {% if package_classes_defined %} + <dt> + <span class="js-config-var-name js-config-var-managed-name">PACKAGE_CLASSES</span> + <span class="glyphicon glyphicon-question-sign get-help" title="Specifies the package manager to use when packaging data"></span> + </dt> + <dd class="variable-list"> + <span class="lead" id="package_classes">{{package_classes}}</span> + <span id="change-package_classes-icon" class="glyphicon glyphicon-edit"></span> + <form id="change-package_classes-form" style="display:none;"> + <div class="form-group"> + <label class="control-label"> + Root file system package format + <span class="glyphicon glyphicon-question-sign get-help" title="The package format used to generate the root file system. Options are <code>deb</code>, <code>ipk</code> and <code>rpm</code>"></i> + </label> + <select id="package_classes-select" class="form-control"> + <option>package_deb</option> + <option>package_ipk</option> + <option>package_rpm</option> + </select> + </div> + <div class="form-group"> + <label class="control-label"> + Additional package formats + <span class="glyphicon glyphicon-question-sign get-help" title="Extra package formats to build"></span> + </label> + <div class="checkbox"> + <label id="package_class_1"> + <input type="checkbox" id="package_class_1_input"> package_deb + </label> + </div> + <div class="checkbox"> + <label id="package_class_2"> + <input type="checkbox" id="package_class_2_input"> package_ipk + </label> + </div> + </div> + <button id="apply-change-package_classes" type="button" class="btn btn-default">Save</button> + <button id="cancel-change-package_classes" type="button" class="btn btn-link">Cancel</button> + </form> + </dd> + {% endif %} + + {% if sstate_dir_defined %} + <dt> + <span class="js-config-var-name js-config-var-managed-name">SSTATE_DIR</span> + <span class="glyphicon glyphicon-question-sign get-help" title="Absolute path to the directory used to store shared state cache files. These files are reused across the builds, which makes the builds faster. By default, Toaster projects share the same cache directory"></span> + </dt> + <dd class="variable-list"> + <span id="sstate_dir" class="lead {% if not sstate_dir %} text-muted {% endif %}">{% if sstate_dir %}{{sstate_dir}}{%else%}Not set{%endif%}</span> + <span class="glyphicon glyphicon-edit" id="change-sstate_dir-icon"></span> + <form class="form-inline" id="change-sstate_dir-form" style="display:none;"> + <div class="form-group" id="validate-sstate_dir"> + <input type="text" class="form-control" id="new-sstate_dir" placeholder="Type an absolute path"> + </div> + <button id="apply-change-sstate_dir" class="btn btn-default" type="button">Save</button> + <button id="cancel-change-sstate_dir" type="button" class="btn btn-link">Cancel</button> + <p class="help-block" id="hintError-sstate_dir" style="display:none;">The directory path cannot include spaces or any of these characters: \ ? % * : | " " < ></p> + <p class="help-block" id="hintError-initialChar-sstate_dir" style="display:none;">The directory path should either start with a /, e.g. /home/toaster/sstate-cache; or with a variable, e.g. ${TOPDIR}/sstate-cache.</p> + </form> + </dd> + {% endif %} + </dl> + + <!-- <ul class="list-unstyled configuration-list" id="configvar-list"> --> + <dl id="configvar-list"> + <!-- the added configuration variables are inserted here --> + </dl> + + <!-- pass the fstypes list, black list, and externally managed variables here --> + {% for fstype in vars_fstypes %} + <input type="hidden" class="js-checkbox-fstypes-list" value="{{fstype}}"> + {% endfor %} + {% for b in vars_blacklist %} + <input type="hidden" class="js-config-blacklist-name" value="{{b}}"> + {% endfor %} + {% for b in vars_managed %} + <input type="hidden" class="js-config-managed-name" value="{{b}}"> + {% endfor %} + + <form id="variable-form"> + <fieldset> + <legend>Add variable</legend> + <div class="row"> + <div class="col-md-3"> + <div id="add-configvar-name-div" class="form-group"> + <label class="control-label"> + Variable + <span class="glyphicon glyphicon-question-sign get-help" + title="Variable names are case sensitive, + cannot have spaces, and can only include letters, numbers, underscores + and dashes"></span> + </label> + <input type="text" class="form-control" placeholder="Type the variable name" id="variable"> + </div> + <p class="help-block" id="new-variable-error-message"></p> + <div class="form-group"> + <label clas="control-label">Value</label> + <input id="value" type="text" class="form-control" placeholder="Type the variable value"> + </div> + <button id="add-configvar-button" class="btn btn-default save" type="button" disabled>Add variable</button> + </div> + <div class="col-md-5 help-block"> + <h5>Some variables cannot be set from Toaster</h5> + <p>Toaster cannot set any variables that impact 1) the configuration of the build servers, + or 2) where artifacts produced by the build are stored. Such variables include: </p> + <p> + <code><a href="http://www.yoctoproject.org/docs/1.6.1/ref-manual/ref-manual.html#var-BB_DISKMON_DIRS" target="_blank">BB_DISKMON_DIRS</a></code> + <code><a href="http://www.yoctoproject.org/docs/1.6.1/ref-manual/ref-manual.html#var-BB_NUMBER_THREADS" target="_blank">BB_NUMBER_THREADS</a></code> + <code>CVS_PROXY_HOST</code> + <code>CVS_PROXY_PORT</code> + <code><a href="http://www.yoctoproject.org/docs/1.6.1/ref-manual/ref-manual.html#var-PARALLEL_MAKE" target="_blank">PARALLEL_MAKE</a></code> + <code><a href="http://www.yoctoproject.org/docs/1.6.1/ref-manual/ref-manual.html#var-TMPDIR" target="_blank">TMPDIR</a></code></p> + <p>Plus the following standard shell environment variables:</p> + <p><code>http_proxy</code> <code>ftp_proxy</code> <code>https_proxy</code> <code>all_proxy</code></p> + </div> + </div> + </fieldset> + </form> +</div> + +</div> + +<script> + +// global variables +var do_reload=false; + +// validate new variable name +function validate_new_variable() { + var variable = $("input#variable").val(); + var value = $("input#value").val(); + + // presumed innocence + $('#new-variable-error-message').text(""); + var error_msg = ""; + + var existing_configvars = document.getElementsByClassName('js-config-var-name'); + for (var i = 0, length = existing_configvars.length; i < length; i++) { + if (existing_configvars[i].innerHTML.toUpperCase() == variable.toUpperCase()) { + error_msg = "This variable is already set in this page. Edit its value instead"; + } + } + + var blacklist_configvars = document.getElementsByClassName('js-config-blacklist-name'); + for (var i = 0, length = blacklist_configvars.length; i < length; i++) { + if (blacklist_configvars[i].value.toUpperCase() == variable.toUpperCase()) { + error_msg = "You cannot edit this variable in Toaster because it is set by the build servers"; + } + } + + var managed_configvars = document.getElementsByClassName('js-config-managed-name'); + for (var i = 0, length = managed_configvars.length; i < length; i++) { + if (managed_configvars[i].value.toUpperCase() == variable.toUpperCase()) { + error_msg = "You cannot set this variable here. Please set it in the <a href=\"{% url 'project' project.id %}\">project main page</a>"; + } + } + + var bad_chars = /[^a-zA-Z0-9\-_/]/.test(variable); + var has_spaces = (0 <= variable.indexOf(" ")); + var only_spaces = (0 < variable.length) && (0 == variable.trim().length); + + if (only_spaces) { + error_msg = "A valid variable name cannot include spaces"; + } else if (bad_chars && has_spaces) { + error_msg = "A valid variable name can only include letters, numbers and the special characters <code> _ - /</code>. Variable names cannot include spaces"; + } else if (bad_chars) { + error_msg = "A valid variable name can only include letters, numbers and the special characters <code>_ - /</code>"; + } + + if ("" != error_msg) { + $('#new-variable-error-message').html(error_msg); + $(".save").attr("disabled","disabled"); + + // add one (and only one) error class append + $("#add-configvar-name-div").addClass("has-error"); + $("#new-variable-error-message").addClass("text-danger"); + + return false; + } else if (0 == variable.length) { + $(".save").attr("disabled","disabled"); + return false; + } + + $("#add-configvar-name-div").removeClass("has-error"); + + // now set the "Save" enablement if 'value' also passes + if (value.trim().length > 0) { + $(".save").removeAttr("disabled"); + } else { + $(".save").attr("disabled","disabled"); + } + + return true; +} + +// validate distro name +function validate_distro_name() { + var value = $("input#new-distro").val(); + + // presumed innocence + $('#distro-error-message').text(""); + var error_msg = ""; + + var has_spaces = (0 <= value.indexOf(" ")); + + if (has_spaces) { + error_msg = "A valid distro name cannot include spaces"; + } else if (0 == value.length) { + error_msg = " "; + } + + if ("" != error_msg) { + $('#distro-error-message').text(error_msg); + $("#apply-change-distro").attr("disabled","disabled"); + + // add one (and only one) error class append + $("#change-distro-form").addClass("has-error"); + + return false; + } + + $("#change-distro-form").removeClass("has-error"); + $("#apply-change-distro").removeAttr("disabled"); + return true; +} + +// Test to insure at least one FS Type is checked +function enableFsTypesSave() { + var any_checked = 0; + $(".fs-checkbox-fstypes:checked").each(function(){ + any_checked = 1; + }); + if ( 0 == any_checked ) { + $("#apply-change-image_fstypes").attr("disabled","disabled"); + $('.scrolling').addClass('has-error'); + $('#fstypes-error-message').show(); + } + else { + $("#apply-change-image_fstypes").removeAttr("disabled"); + $('.scrolling').removeClass('has-error'); + $('#fstypes-error-message').hide(); + } +} + +// Preset or reset the Package Class checkbox labels +function updatePackageClassCheckboxes() { + $('#package_class_1, #package_class_2').hide(); + if ($('select').val() == 'package_deb') { + $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_ipk'); + $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_rpm'); + } + if ($('select').val() == 'package_ipk') { + $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_deb'); + $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_rpm'); + } + if ($('select').val() == 'package_rpm') { + $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_deb'); + $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_ipk'); + } + $('#package_class_1, #package_class_2').fadeIn(1500); +} + +// Re-assert handlers when the page is served and/or refreshed via Ajax +function setEventHandlersForDynamicElements() { + + // change variable value + $('.js-icon-pencil-config_var').click(function (evt) { + var pk = $(this).attr("x-data"); + var current_val = $("#config_var_value_"+pk).text(); + $("#config_var_value_"+pk).hide(); + $("#config_var_trash_"+pk).hide(); + $(".js-icon-pencil-config_var[x-data="+pk+"]").hide(); + $("#change-config_var-form_"+pk).slideDown(); + $("#new-config_var_"+pk).val(current_val); + if ( $("#new-config_var_"+pk).val().length ) { + $("#apply-change-config_var_"+pk).removeAttr("disabled"); + } + else { + $("#apply-change-config_var_"+pk).attr("disabled"); + } + }); + + $('.js-cancel-change-config_var').click(function (evt) { + var pk = evt.target.attributes["x-data"].value; + $("#change-config_var-form_"+pk).slideUp(function() { + $("#config_var_trash_"+pk).show(); + $('#config_var_value_'+pk).show(); + $(".js-icon-pencil-config_var[x-data="+pk+"]").show(); + }); + }); + + $(".js-new-config_var").on('input', function(){ + if ($(this).val().length == 0) { + $(this).parent("div").next(".btn-default").attr("disabled","disabled"); + } + else { + $(this).parent("div").next(".btn-default").removeAttr("disabled"); + } + }); + + $('.js-apply-change-config_var').click(function (evt) { + var xdata = evt.target.attributes["x-data"].value.split(":"); + var pk = xdata[0]; + var variable = xdata[1]; + var val = $('#new-config_var_'+pk).val(); + postEditAjaxRequest({"configvarChange" : variable+':'+val}); + $("#change-config_var-form_"+pk).slideUp(); + $("#config_var_trash_"+pk).fadeIn(); + $('#config_var_value_'+pk).fadeIn(); + $(".js-icon-pencil-config_var[x-data="+pk+"]").fadeIn(); + }); + + // delete variable + $(".js-icon-trash-config_var").click(function (evt) { + var pk = $(this).attr("x-data"); + + // fade out the variable+value div, then refresh the variable list + $(this).fadeOut(); + $(this).tooltip("hide"); + $("config_var_entry_"+pk).fadeOut(); + $('#config_var_value_'+pk).parent("dd").fadeOut(); + postEditAjaxRequest({"configvarDel": evt.target.attributes["x-data"].value}); + }); + +} + +function onEditPageUpdate(data) { + // update targets + var i; var orightml = ""; + + var configvars_sorted = data.configvars.sort(function(a, b){return a[0] > b[0]}); + + var managed_configvars = document.getElementsByClassName('js-config-var-managed-name'); + + for (i = 0; i < configvars_sorted.length; i++) { + // skip if the variable name has a special context (not user defined) + var var_context=undefined; + for (var j = 0, length = managed_configvars.length; j < length; j++) { + if ((managed_configvars[j].innerHTML == configvars_sorted[i][0]) || + (managed_configvars[j].value == configvars_sorted[i][0]) ) { + var_context='m'; + } + } + if (var_context == undefined) { + orightml += '<dt><span id="config_var_entry_'+configvars_sorted[i][2]+'" class="js-config-var-name"></span><span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="config_var_trash_'+configvars_sorted[i][2]+'" x-data="'+configvars_sorted[i][2]+'"></span> </dt>' + orightml += '<dd class="variable-list">' + orightml += ' <span class="lead" id="config_var_value_'+configvars_sorted[i][2]+'"></span>' + orightml += ' <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" x-data="'+configvars_sorted[i][2]+'"></span>' + orightml += ' <form class="form-inline" id="change-config_var-form_'+configvars_sorted[i][2]+'" style="display:none;">' + orightml += ' <div class="form-group">' + orightml += ' <input type="text" class="form-control js-new-config_var" id="new-config_var_'+configvars_sorted[i][2]+'" value=""></div>' + orightml += ' <button id="apply-change-config_var_'+configvars_sorted[i][2]+'" class="btn btn-default js-apply-change-config_var" type="button" x-data="'+configvars_sorted[i][2]+':'+configvars_sorted[i][0]+'" disabled>Save</button>' + orightml += ' <button type="button" class="btn btn-link js-cancel-change-config_var" x-data="'+configvars_sorted[i][2]+'">Cancel</button>' + orightml += ' </form>' + orightml += '</dd>' + } + } + + // update configvars list HTML framework + $("dl#configvar-list").html(orightml); + + // insert the name/value pairs safely as non-HTML + for (i = 0; i < configvars_sorted.length; i++) { + $('#config_var_entry_'+configvars_sorted[i][2]).text(configvars_sorted[i][0]); + $('#config_var_value_'+configvars_sorted[i][2]).text(configvars_sorted[i][1]); + } + + // Add the tooltips + $(".js-icon-trash-config_var").each( function(){ setDeleteTooltip($(this)); }); + $(".js-icon-pencil-config_var").each(function(){ setChangeTooltip($(this)); }); + + // re-assert these event handlers + setEventHandlersForDynamicElements(); +} + +function onEditAjaxSuccess(data, textstatus) { + console.log("XHR returned:", data, "(" + textstatus + ")"); + if (data.error != "ok") { + alert("error on request:\n" + data.error); + return; + } + + // delayed page reload? + if (do_reload) { + do_reload=false; + location.reload(true); + } else { + onEditPageUpdate(data); + } +} + +function onEditAjaxError(jqXHR, textstatus, error) { + alert("XHR errored:\n" + error + "\n(" + textstatus + ")"); + // re-assert the event handlers +} + +/* ensure cookie exists {% csrf_token %} */ +function postEditAjaxRequest(reqdata) { + var ajax = $.ajax({ + type:"POST", + data: $.param(reqdata), + url:"{% url 'xhr_configvaredit' project.id%}", + headers: { 'X-CSRFToken': $.cookie("csrftoken")}, + success: onEditAjaxSuccess, + error: onEditAjaxError, + }) +} + +function setDeleteTooltip(object) { + object.tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Delete" }); +} +function setChangeTooltip(object) { + object.tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Change" }); +} + +$(document).ready(function() { + + // + // Register handlers for static elements + // + + {% if distro_defined %} + // change distro variable + $('#change-distro-icon').click(function() { + $('#change-distro-icon, #distro').hide(); + $("#change-distro-form").slideDown(); + $("#new-distro").val( $('#distro').text() ); + $("#apply-change-distro").removeAttr("disabled"); + }); + + $('#cancel-change-distro').click(function(){ + $("#change-distro-form").slideUp(function() { + $('#distro, #change-distro-icon').show(); + + // reset any dangling error state + $('#distro-error-message').text(""); + $("#change-distro-form").removeClass("has-error"); + }); + }); + + // validate new distro name + $("input#new-distro").on('input', function (evt) { + validate_distro_name(); + }); + + $('#apply-change-distro').click(function(){ + //$('#repo').parent().removeClass('highlight-go'); + var name = $('#new-distro').val(); + postEditAjaxRequest({"configvarChange" : 'DISTRO:'+name}); + $('#distro').text(name); + $("#change-distro-form").slideUp(function () { + $('#distro, #change-distro-icon').show(); + }); + }); + {% endif %} + + {% if dl_dir_defined %} + + // change DL_DIR variable + $('#change-dl_dir-icon').click(function() { + $('#change-dl_dir-form').removeClass('has-error'); + // preset the edit value + var current_val = $("#dl_dir").text().trim(); + if (current_val == "Not set") { + current_val=""; + $("#apply-change-dl_dir").attr("disabled","disabled"); + } + $("input#new-dl_dir").val(current_val); + // enable / disable the save button based on the input value + if ( current_val.length ) { + $("#apply-change-dl_dir").removeAttr("disabled"); + } + else { + $("#apply-change-dl_dir").attr("disabled","disabled"); + } + + $('#change-dl_dir-icon, #dl_dir').hide(); + $("#change-dl_dir-form").slideDown(); + }); + + $('#cancel-change-dl_dir').click(function(){ + $("#hintError-dl_dir").hide(); + $("#hintError-initialChar-dl_dir").hide(); + $("#change-dl_dir-form").slideUp(function() { + $('#dl_dir, #change-dl_dir-icon').show(); + }); + }); + + $("#new-dl_dir").on('input', function(){ + if ($(this).val().trim().length == 0) { + $("#apply-change-dl_dir").attr("disabled","disabled"); + $('#change-dl_dir-form').addClass('has-error'); + $('#hintError-dl_dir').hide(); + $('#hintError-initialChar-dl_dir').hide(); + } + else { + var input = $(this); + var reBeginWithSlash = /^\//; + var reCheckVariable = /^\$/; + var re = /([ <>\\|":%\?\*]+)/; + var invalidDir = re.test(input.val()); + var invalidSlash = reBeginWithSlash.test(input.val()); + var invalidVar = reCheckVariable.test(input.val()); + if (!invalidSlash && !invalidVar) { + $('#change-dl_dir-form').addClass('has-error'); + $("#apply-change-dl_dir").attr("disabled","disabled"); + $('#hintError-initialChar-dl_dir').show(); + } else if (invalidDir) { + $('#change-dl_dir-form').addClass('has-error'); + $("#apply-change-dl_dir").attr("disabled","disabled"); + $('#hintError-dl_dir').show(); + } else { + $('#change-dl_dir-form').removeClass('has-error'); + $("#apply-change-dl_dir").removeAttr("disabled"); + $('#hintError-dl_dir').hide(); + $('#hintError-initialChar-dl_dir').hide(); + } + } + }); + + $('#apply-change-dl_dir').click(function(){ + var value = $('#new-dl_dir').val().trim(); + postEditAjaxRequest({"configvarChange" : 'DL_DIR:'+value}); + $('#dl_dir').text(value); + $('#dl_dir').removeClass('muted'); + $("#change-dl_dir-form").slideUp(function () { + $('#dl_dir, #change-dl_dir-icon').show(); + }); + }); + + {% endif %} + + {% if fstypes_defined %} + // change IMAGE_FSTYPES variable + + // get value of fstypes and add to the textbox + $("#new-imagefs_types").val("{{fstypes}}"); + + // If value of new-imagefs_types is empty disable save button + $("#new-imagefs_types").on("input", function() { + $(this).val($(this).val().replace(/\s+/g,' ')); + if ($(this).val().length === 0) { + //$('#apply-change-image_fstypes').prop('disabled', true); + $('#apply-change-image_fstypes').attr("disabled", "disabled"); + } else { + //$('#apply-change-image_fstypes').prop('disabled', false); + $('#apply-change-image_fstypes').removeAttr("disabled"); + } + + /*If user types imagefs do the action on checkboxes. + Lets say if an imagefstype typed by user and the same + imagefs is unchecked in the checkbox, then checkbox needs + to get checked. Similarly when user deletes imagefs from + textbox the checkbox which is checked gets unchecked. + */ + $('#all-image_fstypes input').each(function(){ + var imagefs_userval = $('#new-imagefs_types').val(); + if( imagefs_userval.indexOf($(this).val()) > -1) { + $(this).prop('checked', true); + } else { + $(this).prop('checked', false); + } + }); + + // Validate underscore in image fs types + if ($(this).val().indexOf('_') > -1) { + $('#validate-image_fstypes').addClass('has-error'); + $('#hintError-image-fs_type').show(); + $("#apply-change-image_fstypes").prop("disabled", true); + } else { + $('#validate-image_fstypes').removeClass('has-error'); + $('#hintError-image-fs_type').hide(); + } + }); + + $('#change-image_fstypes-icon').click(function() { + $('#change-image_fstypes-icon, #image_fstypes').hide(); + $("#change-image_fstypes-form").slideDown(); + // avoid false substring matches by including space separators + var html = ""; + var fstypes = " " + document.getElementById("image_fstypes").innerHTML + " "; + var fstypes_list = document.getElementsByClassName('js-checkbox-fstypes-list'); + // Add the checked boxes first + if (" " != fstypes) { + for (var i = 0, length = fstypes_list.length; i < length; i++) { + if (0 <= fstypes.indexOf(" "+fstypes_list[i].value+" ")) { + html += '<div class="checkbox"><label><input type="checkbox" class="fs-checkbox-fstypes" value="'+fstypes_list[i].value+'" checked="checked">'+fstypes_list[i].value+'</label></div>'; + } + } + } + // Add the un-checked boxes second + for (var i = 0, length = fstypes_list.length; i < length; i++) { + if (0 > fstypes.indexOf(" "+fstypes_list[i].value+" ")) { + html += '<div class="checkbox"><label><input type="checkbox" class="fs-checkbox-fstypes" value="'+fstypes_list[i].value+'">'+fstypes_list[i].value+'</label></div>'; + } + } + // Add the 'no search matches' line last + html += '<label id="no-match-fstypes" class="text-muted">No image types found</label>\n'; + // Display the list + document.getElementById("all-image_fstypes").innerHTML = html; + $('#no-match-fstypes').hide(); + + // clear the previous filter values and warning messages + $("input#filter-image_fstypes").val(""); + }); + + // When checkbox is checked/unchecked kindly update the text + $(document).on("change", "#all-image_fstypes :checkbox", function() { + var imagefs = $(this); + var imagefs_obj = $('#new-imagefs_types'); + var imagefs_userval = imagefs_obj.val(); + if ($(this).is(':checked')) { + if (imagefs_userval.indexOf($(imagefs).val()) === -1) { + imagefs_obj.val(imagefs_userval + " " + $(imagefs).val()); + } + } else { + if (imagefs_userval.indexOf($(imagefs).val()) > -1) { + imagefs_obj.val(imagefs_userval.replace($(imagefs).val(), '').trim()); + } + } + if ($('#new-imagefs_types').val().length === 0) { + $("#apply-change-image_fstypes").prop("disabled", true); + $('#fstypes-error-message').show(); + } else { + $("#apply-change-image_fstypes").prop("disabled", false); + $('#fstypes-error-message').hide(); + } + }); + + $('#cancel-change-image_fstypes').click(function(){ + $("#new-imagefs_types").val("{{fstypes}}"); + $("#change-image_fstypes-form").slideUp(function() { + $('#image_fstypes, #change-image_fstypes-icon').show(); + }); + }); + + $('#filter-image_fstypes').on('input', function(){ + var valThis = $(this).val().toLowerCase(); + var matchCount=0; + $('#all-image_fstypes label').each(function(){ + var text = $(this).text().toLowerCase(); + var match = text.indexOf(valThis); + if (match >= 0) { + $(this).show(); + matchCount += 1; + } + else { + $(this).hide(); + } + }); + if (matchCount === 0) { + $('#no-match-fstypes').show(); + } else { + $('#no-match-fstypes').hide(); + } + }); + + $('#apply-change-image_fstypes').click(function(){ + var fstypes = $('#new-imagefs_types').val(); + + postEditAjaxRequest({"configvarChange" : 'IMAGE_FSTYPES:'+fstypes}); + $('#image_fstypes').text(fstypes); + $('#image_fstypes').parent().removeClass('muted'); + + $("#change-image_fstypes-form").slideUp(function() { + $('#image_fstypes, #change-image_fstypes-icon').show(); + }); + }); + {% endif %} + + + {% if image_install_append_defined %} + + // init IMAGE_INSTALL_append trash icon + setDeleteTooltip($('#delete-image_install-icon')); + + // change IMAGE_INSTALL_append variable + $('#change-image_install-icon').click(function() { + // preset the edit value + var current_val = $("span#image_install").text().trim(); + if (current_val == "Not set") { + current_val=""; + $("#apply-change-image_install").attr("disabled","disabled"); + } else { + // insure these non-empty values have single space prefix + current_val=" " + current_val; + $("#apply-change-image_install").removeAttr("disabled"); + } + $("input#new-image_install").val(current_val); + + $('#change-image_install-icon, #delete-image_install-icon, #image_install').hide(); + $("#change-image_install-form").slideDown(); + }); + + $('#cancel-change-image_install').click(function(){ + $("#change-image_install-form").slideUp(function() { + $('#image_install, #change-image_install-icon').show(); + if ($("span#image_install").text() != "Not set") { + $('#delete-image_install-icon').show(); + setDeleteTooltip($('#delete-image_install-icon')); + } + }); + }); + + $("#new-image_install").on('input', function(){ + if ($(this).val().trim().length == 0) { + $("#apply-change-image_install").attr("disabled","disabled"); + } + else { + $("#apply-change-image_install").removeAttr("disabled"); + } + }); + + $('#apply-change-image_install').click(function(){ + // insure these non-empty values have single space prefix + var value = " " + $('#new-image_install').val().trim(); + postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL_append:'+value}); + $('#image_install').text(value); + $('#image_install').removeClass('text-muted'); + $("#change-image_install-form").slideUp(function () { + $('#image_install, #change-image_install-icon').show(); + if (value.length > -1) { + $('#delete-image_install-icon').show(); + setDeleteTooltip($('#delete-image_install-icon')); + } + }); + }); + + // delete IMAGE_INSTALL_append variable value + $('#delete-image_install-icon').click(function(){ + $(this).tooltip('hide'); + postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL_append:'+''}); + $('#image_install').parent().fadeOut(1000, function(){ + $('#image_install').addClass('text-muted'); + $('#image_install').text('Not set'); + $('#delete-image_install-icon').hide(); + $('#image_install').parent().fadeIn(1000); + }); + }); + {% endif %} + + + {% if package_classes_defined %} + // change PACKAGE_CLASSES variable + $('#change-package_classes-icon').click(function() { + $('#change-package_classes-icon, #package_classes').hide(); + $("#change-package_classes-form").slideDown(); + + // initialize the pulldown and checkboxes + var value = $("#package_classes").text(); + if ( value.indexOf("package_deb") == 0 ) { + $("#package_classes-select").prop('selectedIndex', 0); + updatePackageClassCheckboxes(); + if ( value.indexOf("_ipk") > 0 ) { + $("#package_class_1_input").attr("checked",true); + } + if ( value.indexOf("_rpm") > 0 ) { + $("#package_class_2_input").attr("checked",true); + } + } + + if ( value.indexOf("package_ipk") == 0 ) { + $("#package_classes-select").prop('selectedIndex', 1); + updatePackageClassCheckboxes(); + if ( value.indexOf("_deb") > 0 ) { + $("#package_class_1_input").attr("checked",true); + } + if ( value.indexOf("_rpm") > 0 ) { + $("#package_class_2_input").attr("checked",true); + } + } + + if ( value.indexOf("package_rpm") == 0 ) { + $("#package_classes-select").prop('selectedIndex', 2); + updatePackageClassCheckboxes(); + if ( value.indexOf("_deb") > 0 ) { + $("#package_class_1_input").attr("checked",true); + } + if ( value.indexOf("_ipk") > 0 ) { + $("#package_class_2_input").attr("checked",true); + } + } + }); + + $('#cancel-change-package_classes').click(function(){ + $("#change-package_classes-form").slideUp(function() { + $('#package_classes, #change-package_classes-icon').show(); + }); + }); + + $('select').change(function() { + updatePackageClassCheckboxes(); + }); + + $('#apply-change-package_classes').click(function(){ + var e = document.getElementById("package_classes-select"); + var val = e.options[e.selectedIndex].text; + + pc1_checked = document.getElementById("package_class_1_input").checked; + pc2_checked = document.getElementById("package_class_2_input").checked; + if (val == "package_deb") { + if (pc1_checked) val = val + " package_ipk"; + if (pc2_checked) val = val + " package_rpm"; + } + if (val == "package_ipk") { + if (pc1_checked) val = val + " package_deb"; + if (pc2_checked) val = val + " package_rpm"; + } + if (val == "package_rpm") { + if (pc1_checked) val = val + " package_deb"; + if (pc2_checked) val = val + " package_ipk"; + } + + $('#package_classes').text(val); + //$('#package_classes').parent().removeClass('muted'); + postEditAjaxRequest({"configvarChange" : 'PACKAGE_CLASSES:'+val}); + $("#change-package_classes-form").slideUp(function() { + $('#package_classes, #change-package_classes-icon').show(); + }); + }); + {% endif %} + + {% if sstate_dir_defined %} + + // change SSTATE_DIR variable + $('#change-sstate_dir-icon').click(function() { + $('#change-sstate_dir-form').removeClass('has-error'); + // preset the edit value + var current_val = $("span#sstate_dir").text().trim(); + if (current_val == "Not set") { + current_val=""; + $("#apply-change-sstate_dir").attr("disabled","disabled"); + } + $("input#new-sstate_dir").val(current_val); + + // enable / disable the save button based on the input value + if ( current_val.length ) { + $("#apply-change-sstate_dir").removeAttr("disabled"); + } + else { + $("#apply-change-sstate_dir").attr("disabled","disabled"); + } + + $('#change-sstate_dir-icon, #sstate_dir').hide(); + $("#change-sstate_dir-form").slideDown(); + }); + + $('#cancel-change-sstate_dir').click(function(){ + $("#hintError-sstate_dir").hide(); + $("#hintError-initialChar-sstate_dir").hide(); + $("#change-sstate_dir-form").slideUp(function() { + $('#sstate_dir, #change-sstate_dir-icon').show(); + }); + }); + + $("#new-sstate_dir").on('input', function(){ + if ($(this).val().trim().length == 0) { + $("#apply-change-sstate_dir").attr("disabled","disabled"); + $('#change-sstate_dir-form').addClass('has-error'); + $('#hintError-sstate_dir').hide(); + $('#hintError-initialChar-sstate_dir').hide(); + } + else { + var input = $(this); + var reBeginWithSlash = /^\//; + var reCheckVariable = /^\$/; + var re = /([ <>\\|":%\?\*]+)/; + var invalidDir = re.test(input.val()); + var invalidSlash = reBeginWithSlash.test(input.val()); + var invalidVar = reCheckVariable.test(input.val()); + if (!invalidSlash && !invalidVar) { + $('#change-sstate_dir-form').addClass('has-error'); + $("#apply-change-sstate_dir").attr("disabled","disabled"); + $('#hintError-initialChar-sstate_dir').show(); + } else if (invalidDir) { + $('#change-sstate_dir-form').addClass('has-error'); + $("#apply-change-sstate_dir").attr("disabled","disabled"); + $('#hintError-sstate_dir').show(); + } else { + $('#change-sstate_dir-form').removeClass('has-error'); + $("#apply-change-sstate_dir").removeAttr("disabled"); + $('#hintError-sstate_dir').hide(); + $('#hintError-initialChar-sstate_dir').hide(); + } + } + }); + + $('#apply-change-sstate_dir').click(function(){ + var value = $('#new-sstate_dir').val().trim(); + postEditAjaxRequest({"configvarChange" : 'SSTATE_DIR:'+value}); + $('#sstate_dir').text(value); + $('#sstate_dir').removeClass('text-muted'); + $("#change-sstate_dir-form").slideUp(function () { + $('#sstate_dir, #change-sstate_dir-icon').show(); + }); + }); + + {% endif %} + + // add new variable + $("button#add-configvar-button").click( function (evt) { + var variable = $("input#variable").val(); + var value = $("input#value").val(); + + postEditAjaxRequest({"configvarAdd" : variable+':'+value}); + + // clear the previous values + $("input#variable").val(""); + $("input#value").val(""); + // Disable add button + $(".save").attr("disabled","disabled"); + + // Reload page if admin-removed core managed value is manually added back in + if (0 <= " DISTRO DL_DIR IMAGE_FSTYPES IMAGE_INSTALL_append PACKAGE_CLASSES SSTATE_DIR ".indexOf( " "+variable+" " )) { + // delayed reload to avoid race condition with postEditAjaxRequest + do_reload=true; + } + }); + + // validate new variable name and value + $("#variable, #value").on('input', function() { + validate_new_variable(); + }); + + // + // draw and register the dynamic configuration variables and handlers + // + + var data = { + configvars : [] + }; + {% for c in configvars %} + data.configvars.push([ "{{c.name}}","{{c.value}}","{{c.pk}}" ]); + {% if '' != vars_context|get_dict_value:c.name %} + data.vars_context[ "{{c.name}}" ] = "{{vars_context|get_dict_value:c.name }}"; + {% endif %} + {% endfor %} + + // draw these elements and assert their event handlers + onEditPageUpdate(data); +}); + +</script> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/projects-toastertable.html b/poky/bitbake/lib/toaster/toastergui/templates/projects-toastertable.html new file mode 100644 index 0000000000..d8020a97f2 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/projects-toastertable.html @@ -0,0 +1,42 @@ +{% extends 'base.html' %} + +{% block title %} All projects - Toaster {% endblock %} + +{% block pagecontent %} + +<div class="row"> + <div class="col-md-12"> + + <div class="page-header"> + <h1 data-role="page-title"></h1> + </div> + + {% url 'projects' as xhr_table_url %} + {% include 'toastertable.html' %} + + <script> +$(document).ready(function () { + var tableElt = $("#{{table_name}}"); + var titleElt = $("[data-role='page-title']"); + + tableElt.on("table-done", function (e, total, tableParams) { + var title = "All projects"; + + if (tableParams.search || tableParams.filter) { + if (total === 0) { + title = "No projects found"; + } + else if (total > 0) { + title = total + " project" + (total > 1 ? 's' : '') + " found"; + } + } + + titleElt.text(title); + }); + }); + </script> + + </div> +</div> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/projecttopbar.html b/poky/bitbake/lib/toaster/toastergui/templates/projecttopbar.html new file mode 100644 index 0000000000..768ca94554 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/projecttopbar.html @@ -0,0 +1,79 @@ +{% load static %} +<script src="{% static 'js/projecttopbar.js' %}"></script> +<script> + $(document).ready(function () { + var ctx = { + numProjectLayers : {{project.get_project_layer_versions.count}}, + machine : "{{project.get_current_machine_name|default_if_none:""}}", + } + + try { + projectTopBarInit(ctx); + } catch (e) { + document.write("Sorry, An error has occurred loading this page"); + console.warn(e); + } + }); +</script> + +<div class="col-md-12"> + <div class="alert alert-success alert-dismissible change-notification" id="project-created-notification" style="display:none"> + <button type="button" class="close" data-dismiss="alert">×</button> + <p>Your project <strong>{{project.name}}</strong> has been created. You can now <a class="alert-link" href="{% url 'projectmachines' project.id %}">select your target machine</a> and <a class="alert-link" href="{% url 'projectimagerecipes' project.id %}">choose image recipes</a> to build.</p> + </div> + <!-- project name --> + <div class="page-header"> + <h1 id="project-name-container"> + <span class="project-name">{{project.name}}</span> + + <span class="glyphicon glyphicon-edit" id="project-change-form-toggle"></i> + + {% if project.is_default %} + <span class="glyphicon glyphicon-question-sign get-help" title="This project shows information about the builds you start from the command line while Toaster is running"></span> + {% endif %} + </h1> + <form id="project-name-change-form" class="form-inline" style="display: none;"> + <div class="form-group"> + <input class="form-control input-lg" type="text" id="project-name-change-input" autocomplete="off" value="{{project.name}}"> + </div> + <button id="project-name-change-btn" class="btn btn-default btn-lg" type="button">Save</button> + <a href="#" id="project-name-change-cancel" class="btn btn-lg btn-link">Cancel</a> + </form> + </div> + + {% if not project.is_default %} + <div id="project-topbar"> + <ul class="nav nav-tabs"> + <li id="topbar-configuration-tab"> + <a href="{% url 'project' project.id %}"> + Configuration + </a> + </li> + <li> + <a href="{% url 'projectbuilds' project.id %}"> + Builds ({{project.get_number_of_builds}}) + </a> + </li> + <li> + <a href="{% url 'importlayer' project.id %}"> + Import layer + </a> + </li> + <li> + <a href="{% url 'newcustomimage' project.id %}"> + New custom image + </a> + </li> + <li class="pull-right"> + <form class="form-inline"> + <div class="form-group"> + <span class="glyphicon glyphicon-question-sign get-help" data-placement="left" title="Type the name of one or more recipes you want to build, separated by a space. You can also specify a task by appending a colon and a task name to the recipe name, like so: <code>busybox:clean</code>"></span> + <input id="build-input" type="text" class="form-control input-lg" placeholder="Type the recipe you want to build" autocomplete="off" disabled> + </div> + <button id="build-button" class="btn btn-primary btn-lg" data-project-id="{{project.id}}" disabled>Build</button> + </form> + </li> + </ul> + </div> + {% endif %} +</div> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/recipe.html b/poky/bitbake/lib/toaster/toastergui/templates/recipe.html new file mode 100644 index 0000000000..bf2cd7169a --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/recipe.html @@ -0,0 +1,320 @@ +{% extends "basebuilddetailpage.html" %} + +{% load projecttags %} + +{% block title %} {{object.name}}_{{object.version}} - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %} +{% block localbreadcrumb %} +<li><a href="{% url 'recipes' build.pk %}">Recipes</a></li> +<li>{{object.name}}_{{object.version}} </li> +{% endblock %} + +{% block pagedetailinfomain %} + +<!-- Begin container --> + +<div class="row"> + <div class="col-md-12"> + <div class="page-header build-data"> + <h1>{{object.name}}_{{object.version}}</h1> + </div> + </div> +</div> + +<div class="row"> + <div class="col-md-8 tabbable"> + <ul class="nav nav-tabs"> + <li class="{{tab_states.1}}"> + <a href="#information" data-toggle="tab"> + <span class="glyphicon glyphicon-question-sign get-help" title="Build-related + information about the recipe"></span> + Recipe details + </a> + </li> + <li> + <a href="{% url "recipe_packages" build.pk object.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="The packaged + output resulting from building the recipe"></span> + Packages ({{package_count}}) + </a> + </li> + <li class="{{tab_states.3}}"> + <a href="#dependencies" data-toggle="tab"> + <span class="glyphicon glyphicon-question-sign get-help" title="The recipe + build-time dependencies (i.e. other recipes)"></span> + Build dependencies ({{object.r_dependencies_recipe.all.count}}) + </a> + </li> + <li class="{{tab_states.4}}"> + <a href="#brought-in-by" data-toggle="tab"> + <span class="glyphicon glyphicon-question-sign get-help" title="The recipe + build-time reverse dependencies (i.e. the recipes that + depend on this recipe)"></span> + Reverse build dependencies ({{object.r_dependencies_depends.all.count}}) + </a> + </li> + </ul> + <div class="tab-content"> + <div class="tab-pane {{tab_states.1}}" id="information"> + <dl class="dl-horizontal"> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="The name of + the layer providing the recipe"></span> + Layer + </dt> + <dd>{{layer.name}}</dd> + + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Path to the + recipe .bb file"></span> + Recipe file + </dt> + <dd><code>{{object.file_path}} {% if object.pathflags %}<i>({{object.pathflags}})</i>{% endif %}</code></dd> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" + title="The Git branch of the layer providing the + recipe"></span> + Layer branch + </dt> + {% if layer_version.layer.local_source_dir %} + <dd> + <span class="text-muted">Not applicable</span> + <span class="glyphicon glyphicon-question-sign get-help" title="The source + code of {{layer_version.layer.name}} is not in a git repository + so there is no branch associated with it"></span> + </dd> + {% else %} + <dd>{{layer_version.branch}}</dd> + {% endif %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="The Git + commit of the layer providing the recipe"></span> + Layer commit + </dt> + {% if layer_version.layer.local_source_dir %} + <dd> + <span class="text-muted">Not applicable</span> + <span class="glyphicon glyphicon-question-sign get-help" title="The source + code of {{layer_version.layer.name}} is not in a git repository + so there is no commit associated with it"></span> + </dd> + {% else %} + <dd class="iscommit">{{layer_version.commit}}</dd> + {% endif %} + {% if object.provides_set.all %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" + title="A list of aliases by which a particular recipe can be known. The additional aliases are + synonyms for the recipe and can be useful satisfying dependencies of other recipes during + the build"></span> + PROVIDES + </dt> + <dd><code>{% for provider in object.provides_set.all %}{{ provider.name }} {% endfor %}</code></dd> + {% endif %} + </dl> + + <h2 class="details">Tasks</h2> + {% if not tasks %} + <div class="alert alert-info"> + <strong>{{object.name}}_{{object.version}}</strong> does not have any tasks in this build. + </div> + {% else %} + <div class="table-responsive"> + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th> + <span class="glyphicon glyphicon-question-sign + get-help" title="The running sequence of each task + in the build"></span> + Order + </th> + <th> + <span class="glyphicon glyphicon-question-sign get-help" title="The name + of the task"></span> + Task + </th> + <th> + <span class="glyphicon glyphicon-question-sign get-help" title="This + value tells you if a task had to run (executed) in + order to generate the task output, or if the output was + provided by another task and therefore the task didn't need + to run (not executed)"></span> + Executed + </th> + <th> + <span class="glyphicon glyphicon-question-sign get-help" title="This + column tells you if 'executed' tasks succeeded or + failed. The column also tells you why 'not executed' + tasks did not need to run"></span> + Outcome + </th> + <th> + <span class="glyphicon glyphicon-question-sign get-help" title="This + column tells you if a task tried to restore output + from the <code>sstate-cache</code> directory or + mirrors, and reports the result: Succeeded, Failed or File + not in cache"></span> + Cache attempt + </th> + </tr> + </thead> + <tbody> + + {% for task in tasks %} + + <tr {{ task|task_color }} > + + <td>{{task.order}}</td> + <td> + <a href="{% url "task" build.pk task.pk %}">{{task.task_name}}</a> + {% if task.get_description %}<span class="glyphicon + glyphicon-question-sign get-help hover-help" + title="{{task.get_description}}"></span> + {% endif %} + </td> + + <td>{{task.get_executed_display}}</td> + + <td>{{task.get_outcome_display}} + {% if task.outcome = task.OUTCOME_FAILED %} + <a href="{% url 'build_artifact' build.pk "tasklogfile" task.pk %}"> + <span class="glyphicon glyphicon-download-alt + get-help" title="Download task log + file"></span> + </a> + {% endif %} + <i class="icon-question-sign get-help hover-help" title="{{task.get_outcome_help}}"></i> + </td> + <td> + {% ifnotequal task.sstate_result task.SSTATE_NA %} + {{task.get_sstate_result_display}} + {% endifnotequal %} + </td> + + </tr> + + {% endfor %} + </tbody> + </table> + </div> + {% endif %} + </div> + <div class="tab-pane {{tab_states.3}}" id="dependencies"> + + {% if not object.r_dependencies_recipe.all %} + <div class="alert alert-info"> + <strong>{{object.name}}_{{object.version}}</strong> has no build dependencies. + </div> + {% else %} + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th> + Recipe + </th> + <th> + Version + </th> + </tr> + </thead> + <tbody> + + {% for rr in object.r_dependencies_recipe.all|dictsort:"depends_on.name" %} + <tr> + <td><a href="{% url "recipe" build.pk rr.depends_on.pk %}">{{rr.depends_on.name}}</a> + {% if rr.via %} + <span class="text-muted">satisfied via <code class="text-muted">{{rr.via.name}}</code></span> + <span class="glyphicon glyphicon-question-sign get-help hover-help" + title="This dependency is satisfied by the PROVIDES value + <code>{{rr.via.name}}</code> in the <code>{{rr.depends_on.name}}</code> recipe"></span> + {% endif %} + </td> + <td>{{rr.depends_on.version}}</td> + </tr> + {% endfor %} + + </tbody> + </table> + {% endif %} + + </div> + <div class="tab-pane {{tab_states.4}}" id="brought-in-by"> + + {% if not object.r_dependencies_depends.all %} + <div class="alert alert-info"> + <strong>{{object.name}}_{{object.version}}</strong> has no reverse build dependencies. + </div> + {% else %} + <table class="table table-bordered table-hover"> + <thead> + <tr> + <th> + Recipe + </th> + <th> + Version + </th> + </tr> + </thead> + <tbody> + + {% for rr in object.r_dependencies_depends.all|dictsort:"recipe.name" %} + <tr> + <td><a href="{% url "recipe" build.pk rr.recipe.pk %}">{{rr.recipe.name}}</a> + {% if rr.via %} + <span class="text-muted"> satisfied via <code class="text-muted">{{rr.via.name}}</code></span> + <span class="glyphicon glyphicon-question-sign get-help hover-help" + title="This dependency is satisfied by the PROVIDES value + <code>{{rr.via.name}}</code> in the <code>{{rr.depends_on.name}}</code> recipe"></i> + {% endif %} + </td> + <td>{{rr.recipe.version}}</td> + </tr> + {% endfor %} + + </tbody> + </table> + {% endif %} + + </div> + </div> +</div> + +<div class="col-md-4"> + <div class="well"> + <h2>About {{object.name}}</h2> + <dl class="item-info"> + {% if object.summary %} + <dt>Summary</dt> + <dd>{{object.summary}}</dd> + {% endif %} + {% if object.description %} + <dt>Description</dt> + <dd>{{object.description}}</dd> + {% endif %} + {% if object.homepage %} + <dt>Homepage</dt> + <dd><a href="{{object.homepage}}">{{object.homepage}}</a></dd> + {% endif %} + {% if object.bugtracker %} + <dt>Bugtracker</dt> + <dd><a href="{{object.bugtracker}}">{{object.bugtracker}}</a></dd> + {% endif %} + {% if object.section %} + <dt> + Section + <span class="glyphicon glyphicon-question-sign get-help" title="The section in which recipes should be categorized"></span> + </dt> + <dd>{{object.section}}</dd> + {% endif %} + {% if object.license %} + <dt>License</dt> + <dd>{{object.license}}</dd> + {% endif %} + </dl> + </div> +</div> + +</div> <!-- end row --> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/recipe_btn.html b/poky/bitbake/lib/toaster/toastergui/templates/recipe_btn.html new file mode 100644 index 0000000000..0ee0ba5593 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/recipe_btn.html @@ -0,0 +1,23 @@ +<a data-recipe-name="{{data.name}}" class="btn btn-default btn-block layer-exists-{{data.layer_version.pk}} build-recipe-btn" style="margin-top: 5px; + {% if data.layer_version.pk not in extra.current_layers %} + display:none; + {% endif %}" + > + Build recipe +</a> +<a class="btn btn-default btn-block layerbtn layer-add-{{data.layer_version.pk}}" + data-layer='{ + "id": {{data.layer_version.pk}}, + "name": "{{data.layer_version.layer.name}}", + "layerdetailurl": "{%url "layerdetails" extra.pid data.layer_version.pk%}", + "xhrLayerUrl": "{% url "xhr_layer" extra.pid data.layer_version.pk %}" + }' data-directive="add" + {% if data.layer_version.pk in extra.current_layers %} + style="display:none;" + {% endif %} +> + <span class="glyphicon glyphicon-plus"></span> + Add layer + <span class="glyphicon glyphicon-question-sign get-help" title="To build this + recipe you must first add the {{data.layer_version.layer.name}} layer to your project"></i> +</a> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/recipe_packages.html b/poky/bitbake/lib/toaster/toastergui/templates/recipe_packages.html new file mode 100644 index 0000000000..37a586f389 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/recipe_packages.html @@ -0,0 +1,135 @@ +{% extends "basebuilddetailpage.html" %} + +{% load projecttags %} +{% load humanize %} +{% block localbreadcrumb %} +<li><a href="{% url 'recipes' build.pk %}">Recipes</a></li> +<li>{{recipe.name}}_{{recipe.version}} </li> +{% endblock %} + +{% block pagedetailinfomain %} + +<!-- Begin container --> + +<div class="row"> + <div class="col-md-12"> + <div class="page-header build-data"> + <h1>{{recipe.name}}_{{recipe.version}}</h1> + </div> + </div> +</div> + +<div class="row"> + <div class="col-md-8 tabbable"> + <ul class="nav nav-tabs"> + <li> + <a href="{% url "recipe" build.pk recipe.id "1" %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="Build-related + information about the recipe"></span> + Recipe details + </a> + </li> + <li class="active"> + <a href="#packages-built" data-toggle="tab"> + <span class="glyphicon glyphicon-question-sign get-help" title="The packaged + output resulting from building the recipe"></span> + Packages ({{object_count}}) + </a> + </li> + <li> + <a href="{% url "recipe" build.pk recipe.id "3" %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="The recipe + build-time dependencies (i.e. other recipes)"></span> + Build dependencies ({{recipe.r_dependencies_recipe.all.count}}) + </a> + </li> + <li> + <a href="{% url "recipe" build.pk recipe.id "4" %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="The recipe + build-time reverse dependencies (i.e. the recipes that + depend on this recipe)"></span> + Reverse build dependencies ({{recipe.r_dependencies_depends.all.count}}) + </a> + </li> + </ul> + <div class="tab-content"> +{# <div class="tab-pane active" id="packages-built" name="packages-built">#} + <div class="tab-pane active" id="packages-built"> + {% if not objects and not request.GET.search %} + <div class="alert alert-info"> + <strong>{{recipe.name}}_{{recipe.version}}</strong> does not build any packages. + </div> + + {% elif not objects %} + {# have empty search results, no table nor pagination #} + {% with "packages" as search_what %} + {% include "detail_search_header.html" %} + {% endwith %} + + {% else %} + + + {% with "packages" as search_what %} + {% include "detail_search_header.html" %} + {% endwith %} + <table class="table table-bordered table-hover tablesorter" id="otable"> + {% include "detail_sorted_header.html" %} + + <tbody> + {% for package in objects %} + + <tr> + <td><a href="{% url "package_built_detail" build.pk package.pk %}">{{package.name}}</a></td> + <td>{{package.version}}_{{package.revision}}</td> + <td class="sizecol">{{package.size|filtered_filesizeformat}}</td> + </tr> + + {% endfor %} + + {% endif %} + {% if objects %} + </tbody> + </table> + {% include "detail_pagination_bottom.html" %} + {% endif %} + </div> {# tab-pane #} + </div> {# tab-content #} +</div> {# col-md-8 #} + +<div class="col-md-4"> + <div class="well"> + <h2>About {{recipe.name}}</h2> + <dl class="item-info"> + {% if recipe.summary %} + <dt>Summary</dt> + <dd>{{recipe.summary}}</dd> + {% endif %} + {% if recipe.description %} + <dt>Description</dt> + <dd>{{recipe.description}}</dd> + {% endif %} + {% if recipe.homepage %} + <dt>Homepage</dt> + <dd><a href="{{recipe.homepage}}">{{recipe.homepage}}</a></dd> + {% endif %} + {% if recipe.bugtracker %} + <dt>Bugtracker</dt> + <dd><a href="{{recipe.bugtracker}}">{{recipe.bugtracker}}</a></dd> + {% endif %} + {% if recipe.section %} + <dt> + Section + <i class="icon-question-sign get-help" title="The section in which recipes should be categorized"></i> + </dt> + <dd>{{recipe.section}}</dd> + {% endif %} + {% if recipe.license %} + <dt>License</dt> + <dd>{{recipe.license}}</dd> + {% endif %} + </dl> + </div> +</div> + +</div> <!-- end row --> +{% endblock pagedetailinfomain %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/recipedetails.html b/poky/bitbake/lib/toaster/toastergui/templates/recipedetails.html new file mode 100644 index 0000000000..66c1f7bcd0 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/recipedetails.html @@ -0,0 +1,175 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} +{% load static %} +{% block pagecontent %} + +<ul class="breadcrumb"> + <li> + <a href="{% url 'project' project.id %}">{{project.name}}</a> + <span class="divider">→</span> + </li> + <li> + {% if recipe.is_image %} + <a href="{% url 'projectimagerecipes' project.id %}">Image recipes</a> + {% else %} + <a href="{% url 'projectsoftwarerecipes' project.id %}">Software recipes</a> + {% endif %} + <span class="divider">→</span> + </li> + <li class="active"> + {{recipe.name}} ({{recipe.layer_version.layer.name}}) + </li> +</ul> + +<script src="{% static 'js/recipedetails.js' %}"></script> +<script> + $(document).ready(function (){ + var ctx = { + recipe : { + id: {{recipe.pk}}, + name: "{{recipe.name}}", + totalPackages: {{packages.count}}, + layer_version : { + id: {{recipe.layer_version.pk}}, + name: "{{recipe.layer_version.layer.name}}", + layerdetailurl: "{% url 'layerdetails' project.pk recipe.layer_version.pk %}" + } + } + }; + + try { + recipeDetailsPageInit(ctx); + } catch (e) { + document.write("Sorry, An error has occurred loading this page"); + console.warn(e); + } + }); +</script> + +{% include 'newcustomimage_modal.html' %} + +<div class="alert alert-success lead" id="image-created-notification" style="margin-top: 15px; display: none"> + <button type="button" data-dismiss="alert" class="close">x</button> + Your custom image <strong>{{recipe.name}}</strong> has been created. You can now add or remove packages as needed. +</div> +<div class="page-header"> + <h1> + {{recipe.name}} + <small>({{recipe.layer_version.layer.name}})</small> + </h1> +</div> + +<div class="row"> + <div class="col-md-8"> + <div class="button-place btn-group" id="customise-build-btns" + style="width: 100%; + {% if not in_project %} + display:none; + {% endif %}"> + <button class="btn btn-default btn-lg build-recipe-btn" style="width: 50%"> + Build {{recipe.name}} + </button> + {% if recipe.is_image %} + <button class="btn btn-default btn-lg customise-btn" data-recipe="{{recipe.pk}}" style="width: 50%"> + Customise {{recipe.name}} + </button> + {% endif %} + </div> + <div class="button-place"> + <button class="btn btn-default btn-block btn-lg" id="add-layer-btn" + style="width:100%; + {% if in_project %} + display:none; + {% endif %}"> + <i class="glyphicon glyphicon-plus"></i> + Add the {{recipe.layer_version.layer.name}} layer to your project to build or customise this image recipe + </button> + </div> + + <div id="packages-table"> + {% if packages.count %} + {% url 'recipepackages' project.id recipe.id as xhr_table_url %} + <h2>{{title}} (<span class="table-count-{{table_name}}">0</span>) </h2> + {% include "toastertable.html" %} + {% else %} + <h2>{{title}}</h2> + {% endif %} + + <div class="alert alert-info air" id="build-to-get-packages-msg" + {# if there are packages and it's in the project don't show this msg #} + {% if packages.count or not packages.count and not in_project %} + style="display:none" + {% endif %} > + <p class="lead">Toaster has no package information for {{recipe.name}}. To generate package information, build {{recipe.name}}</p> + <button class="btn btn-info btn-lg build-recipe-btn" style="margin:20px 0 10px 0;">Build {{recipe.name}}</button> + </div> + + <div class="alert alert-info air" id="packages-alert" + {% if packages.count or in_project %} + style="display:none" + {% endif %} + > + <p class="lead">Toaster has no package information for {{recipe.name}} + </p> + </div> + </div> + </div> + <div class="col-md-4"> + <div class="well"> + <h2>About {{recipe.name}}</h2> + <dl class="item-info"> + <dt> + Approx. packages included + <span class="glyphicon glyphicon-question-sign get-help" title="The number of packages included is based on information from previous builds and from parsing layers, so we can never be sure it is 100% accurate"></span> + </dt> + <dd class="no-packages">{{packages.count}}</dd> + <dt> + Approx. package size + <span class="glyphicon glyphicon-question-sign get-help" title="Package size is based on information from previous builds, so we can never be sure it is 100% accurate"></span> + </dt> + <dd>{{approx_pkg_size.size__sum|filtered_filesizeformat}}</dd> + {% if last_build %} + <dt>Last build</dt> + <dd> + <span class="glyphicon glyphicon-ok-circle"></span> + <a href="{% url 'projectbuilds' project.id%}">{{last_build.completed_on|date:"d/m/y H:i"}}</a> + </dd> + {% endif %} + <dt>Recipe file</dt> + <dd> + <code>{{recipe.file_path|cut_path_prefix:recipe.layer_version.local_path}}</code> + <a href="{{recipe.get_vcs_recipe_file_link_url}}"><span class="glyphicon glyphicon-new-window" title="View recipe file" data-toggle="tooltip"></span></a> + </dd> + <dt>Layer</dt> + <dd><a href="{% url 'layerdetails' project.id recipe.layer_version.pk %}">{{recipe.layer_version.layer.name}}</a></dd> + <dt> + Summary + </dt> + <dd> + {{recipe.summary}} + </dd> + <dt> + Description + </dt> + <dd> + {{recipe.description}} + </dd> + <dt>Version</dt> + <dd> + {{recipe.version}} + </dd> + <dt>Section</dt> + <dd> + {{recipe.section}} + </dd> + <dt>License</dt> + <dd> + {{recipe.license}} + </dd> + </dl> + </div> + </div> +</div> + +{% endblock %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/snippets/gitrev_popover.html b/poky/bitbake/lib/toaster/toastergui/templates/snippets/gitrev_popover.html new file mode 100644 index 0000000000..c1e3dabfbf --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/snippets/gitrev_popover.html @@ -0,0 +1,8 @@ +{% load projecttags %} +{% if vcs_ref|is_shaid %} +<a class="btn btn-default" data-content="{{vcs_ref}}"> + {{vcs_ref|truncatechars:10}} +</a> +{% else %} +{{vcs_ref}} +{% endif %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/snippets/pkg_dependencies_popover.html b/poky/bitbake/lib/toaster/toastergui/templates/snippets/pkg_dependencies_popover.html new file mode 100644 index 0000000000..273437e380 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/snippets/pkg_dependencies_popover.html @@ -0,0 +1,38 @@ +{# Popover that displays the dependences and sizes of a package 'data' used in the Packages table #} +{% load projecttags %} + +{% with package_deps=data.package_dependencies_source|for_target:extra.target_name %} +{% with count_package=package_deps.packages|length %} + +{% if count_package > 0 %} + <a data-content='<ul class="list-unstyled"> + {% for dep in package_deps.packages %} + <li> + {% if extra.add_links %} + <a href="{% url 'package_included_detail' extra.build.pk extra.target_id dep.depends_on.pk %}"> + {{dep.depends_on.name}}</a> + {% else %} + {{dep.depends_on.name}} + {% endif %} + {% if dep.depends_on.size > 0 %} + ({{dep.depends_on.size|filtered_filesizeformat}}) + {% endif %} + </li> + {% endfor %} + </ul>' class="btn btn-default" title=' + <strong> + {% if extra.add_links %} + <a href="{% url 'package_included_dependencies' extra.build.pk extra.target_id data.pk %}"> + {{data.name}}</a> + {% else %} + {{data.name}} + {% endif %} + </strong> + dependencies - + <strong>{{package_deps.size|filtered_filesizeformat}}</strong>'> + {{count_package}} + </a> +{% endif %} + +{% endwith %} +{% endwith %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/snippets/pkg_revdependencies_popover.html b/poky/bitbake/lib/toaster/toastergui/templates/snippets/pkg_revdependencies_popover.html new file mode 100644 index 0000000000..e6ef816e7c --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/snippets/pkg_revdependencies_popover.html @@ -0,0 +1,38 @@ +{# Popover that displays the reverse dependences and sizes of a package 'data' used in the Packages table #} +{% load projecttags %} + +{% with package_deps=data.package_dependencies_target|for_target:extra.target_name %} +{% with count_package=package_deps.packages|length %} + +{% if count_package > 0 %} + <a data-content='<ul class="list-unstyled"> + {% for dep in package_deps.packages|dictsort:"package.name" %} + <li> + {% if extra.add_links %} + <a href="{% url 'package_included_detail' extra.build.pk extra.target_id dep.package.pk %}"> + {{dep.package.name}}</a> + {% else %} + {{dep.package.name}} + {% endif %} + {% if dep.package.size > 0 %} + ({{dep.package.size|filtered_filesizeformat}}) + {% endif %} + </li> + {% endfor %} + </ul>' class="btn btn-default" title=' + <strong> + {% if extra.add_links %} + <a href="{% url 'package_included_reverse_dependencies' extra.build.pk extra.target_id data.pk %}"> + {{data.name}}</a> + {% else %} + {{data.name}} + {% endif %} + </strong> + dependencies - + <strong>{{package_deps.size|filtered_filesizeformat}}</strong>'> + {{count_package}} + </a> +{% endif %} + +{% endwith %} +{% endwith %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/tablesort.html b/poky/bitbake/lib/toaster/toastergui/templates/tablesort.html new file mode 100644 index 0000000000..362474293e --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/tablesort.html @@ -0,0 +1,38 @@ +{% load projecttags %} +<!-- component to display a generic table --> + {% if disable_sort %} + <table class="table table-bordered table-hover" id="detail_table"> + <thead> + <tr> + {% for tc in tablecols %} + <th class="{%if tc.dclass%}{{tc.dclass}}{%endif%} {%if tc.clclass%}{{tc.clclass}}{%endif%}"> + {%if tc.qhelp%}<i class="icon-question-sign get-help" title="{{tc.qhelp}}"></i>{%endif%} + {{tc.name}} + </th> + {% endfor %} + </tr> + </thead> + {% else %} + <table class="table table-bordered table-hover tablesorter" id="otable"> + <thead> + <!-- Table header row; generated from "tablecols" entry in the context dict --> + <tr> + {% for tc in tablecols %} + <th class="{%if tc.dclass%}{{tc.dclass}}{%endif%} {%if tc.clclass%}{{tc.clclass}}{%endif%}"> + {%if tc.qhelp%}<i class="icon-question-sign get-help" title="{{tc.qhelp}}"></i>{%endif%} + {%if tc.orderfield%} + <a {%if tc.ordericon%} class="sorted" {%endif%} + href="javascript:reload_params({'page': 1, 'orderby' : '{{tc.orderfield}}' })" > + {{tc.name}} + </a> + {%else%} + <span class="muted"> + {{tc.name}} + </span> + {%endif%} + {%if tc.ordericon%} <i class="icon-caret-{{tc.ordericon}}"></i>{%endif%} + </th> + {% endfor %} + </tr> + </thead> + {% endif %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/target.html b/poky/bitbake/lib/toaster/toastergui/templates/target.html new file mode 100644 index 0000000000..1924a0dad7 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/target.html @@ -0,0 +1,56 @@ +{% extends "basebuildpage.html" %} +{% block title %} Packages included - {{ target.target }} {{ target.build.machine }} - {{ target.build.project.name }} - Toaster {% endblock %} +{% block localbreadcrumb %} +<li>{{target.target}}</li> +{% endblock localbreadcrumb%} + +{% load projecttags %} + +{% block nav-target %} + {% for t in build.get_sorted_target_list %} + {% ifequal target.pk t.pk %} + <li class="active"><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li> + {% else %} + <li><a href="{% url 'target' build.pk t.pk %}">{{t.target}}</a><li> + {% endifequal %} + {% endfor %} +{% endblock %} + +{% block buildinfomain %} +<div class="col-md-10"> + <div class="page-header build-data"> + <h1> + {% if request.GET.search and objects.paginator.count > 0 %} + {{objects.paginator.count}} package{{objects.paginator.count|pluralize}} found + {% elif request.GET.search and objects.paginator.count == 0 %} + No packages found + {% else %} + {{target.target}} + {% endif %} + </h1> + </div> +<div id="navTab"> + <ul class="nav nav-tabs"> + <li class="active"> + <a href="#target"> + <span class="glyphicon glyphicon-question-sign get-help" title="Of all the packages built, the subset installed in the root file system of this image"></span> + Packages included ({{target.package_count}} - {{packages_sum|filtered_filesizeformat}}) + </a> + </li> + <li> + <a href="{% url 'dirinfo' build.id target.id %}"> + <span class="glyphicon glyphicon-question-sign get-help" title="The directories and files in the root file system of this image"></span> + Directory structure + </a> + </li> + </ul> + + <div id="image-packages" class="tab-pane"> + {# xhr_table_url is just the current url so leave it blank #} + {% with xhr_table_url='' %} + {% include "toastertable.html" %} + {% endwith %} + </div> <!-- tabpane --> + </div> <!--navTab --> +<!-- col-md-10 --> +{% endblock buildinfomain %} diff --git a/poky/bitbake/lib/toaster/toastergui/templates/task.html b/poky/bitbake/lib/toaster/toastergui/templates/task.html new file mode 100644 index 0000000000..214c777831 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/task.html @@ -0,0 +1,348 @@ +{% extends "basebuilddetailpage.html" %} + +{% load projecttags %} +{% load humanize %} + +{% block title %} {{task.recipe.name}}_{{task.recipe.version}} {{task.task_name}} - {{build.target_set.all|dictsort:"target"|join:", "}} {{build.machine}} - {{build.project.name}} - Toaster {% endblock %} +{% block localbreadcrumb %} +<li><a href="{% url 'tasks' build.pk %}">Tasks</a></li> +<li>{{task.recipe.name}}_{{task.recipe.version}} {{task.task_name}}</li> +{% endblock %} + +{% block pagedetailinfomain %} + +<div class="row"> + <div class="col-md-12"> + <div class="page-header build-data"> + <h1><a href="{%url 'recipe' build.pk task.recipe.pk %}">{{task.recipe.name}}_{{task.recipe.version}}</a> {{task.task_name}}</h1> + </div> + +{# Outcome section #} +<h2 {{ task|task_color:True }}> + {{task.get_outcome_display}} + <span class="glyphicon glyphicon-question-sign get-help" title="{{task.get_outcome_help}}"></i> +</h2> +{%if task.task_executed %} + {# executed tasks outcome #} + {% if task.logfile %} + <a class="btn btn-default btn-lg" + href="{% url 'build_artifact' build.id 'tasklogfile' task.pk %}"> + Download task log + </a> + {% endif %} + {# show stack trace for failed task #} + {% if task.outcome == task.OUTCOME_FAILED and log_head %} + <h3>Python stack trace</h3> + <div> + <pre style="min-height:160px;"> + <code>{{log_head}}</code><a id="full-trace-show" data-target="#fulltrace" data-toggle="collapse" class="btn btn-xs">...</a> + <div id="fulltrace" class="collapse" style="margin-top: -20px; height: 0px;"> + <code>{{log_body}}</code><br><a id="full-trace-hide" class="btn btn-xs collapsed" style="font-family:Helvetica Neue" data-target="#fulltrace" data-toggle="collapse">Collapse stack trace<i class="icon-caret-up"></i></a></div></pre> + </div> + {% endif %} +{% else %} +{# not executed tasks outcome #} + {% if task.outcome == task.OUTCOME_PREBUILT %} + {% if not showing_matches %} + <a class="btn btn-default" + href="javascript:reload_params({'show_matches' : 'true' + })">Match to tasks in previous builds <span class="glyphicon +glyphicon-question-sign get-help" title="This shows you a list of tasks from +previous builds with the same signature generated from the same inputs as used +in the prebuilt task. Any of them could be the task that generated the output +this prebuilt task is reusing"></span></a> + {% elif matching_tasks %} + <h3 class="details">Prebuilt task could be based on + <span class="glyphicon glyphicon-question-sign get-help" title="This + table shows a list of tasks from previous builds with the + same signature generated from the same inputs as used in the + prebuilt task. Any of them could be the task that generated the + output this prebuilt task is reusing"></span> + </h3> + <div class="table-responsive"> + <table class="table table-bordered table-hover"> + <thead> + <th> + <span class="glyphicon glyphicon-question-sign + get-help" title="The name of the recipe to which + each task applies"></span> + Recipe + </th> + <th> + <span class="glyphicon glyphicon-question-sign get-help" title="The name + of the task"></span> + Task + </th> + <th> + <span class="glyphicon glyphicon-question-sign get-help" title="This + value tells you if a task had to run (executed) in + order to generate the task output, or if the output was + provided by another task and therefore the task didn't need + to run (not executed)"></span> + Executed + </th> + <th> + <span class="glyphicon glyphicon-question-sign + get-help" title="This column tells you if + 'executed' tasks succeeded or failed. The column also + tells you why 'not executed' tasks did not need to + run"></span> + Outcome + </th> + <th> + <span class="glyphicon glyphicon-question-sign + get-help" title="The date and time the build + finished"></span> + Build completed on + </th> + </thead> + <tbody> + {% for match in matching_tasks %} + <tr {{ match|task_color }}> + <td> + {{match.recipe.name}} + </td> + <td> + <a href="{%url "task" match.build.pk match.pk%}">{{match.task_name}}</a> + {% if task.get_description %} + <span class="glyphicon + glyphicon-question-sign get-help + hover-help" + title="{{task.get_description}}"></span> + {% endif %} + </td> + <td> + {{match.get_executed_display}} + </td> + <td> + {{match.get_outcome_display}} + <span class="glyphicon glyphicon-question-sign + get-help hover-help" + title="{{match.get_outcome_help}}"></span> + </td> + <td> + {{match.build.completed_on|date:"d/m/y H:i"}} + </td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + {% else %} + <p class="alert"> + <strong> We have found no tasks matching this prebuilt task</strong><br/> + The task you are looking for could belong to a build for which Toaster has no data. + </p> + {% endif %} + {% elif task.outcome == task.OUTCOME_COVERED %} + <dl class="dl-horizontal"> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="The task(s) + providing the outcome of this task"></span> Task covered by + </dt> + <dd> + <ul class="list-unstyled"> + {% for t in covered_by %} + <li> + <a href="{%url 'task' t.build.pk t.pk%}" + class="task-info" + title="{{t.get_executed_display}} | {{t.get_outcome_display}}"> + {{t.recipe.name}}_{{t.recipe.version}} + {{t.task_name}} + </a> + </li> + {% endfor %} + </ul> + </dd> + </dl> + {%elif task.outcome == task.OUTCOME_CACHED%} + {% for t in task.get_related_setscene %} + {% if forloop.last %} + <a class="btn btn-default btn-lg" + href="{% url 'build_artifact' build.id "tasklogfile" t.pk %}"> + Download task log + </a> + {% endif %} + {% endfor %} + + {%elif task.outcome == task.OUTCOME_EMPTY%} + <div class="alert alert-info details"> + This task is empty because it has the <code>noexec</code> flag set to <code>1</code>, or the task function is empty + </div> + {% endif %} +{% endif %} + +{# Execution section #} + {% if task.task_executed %} + <h2> + Executed + <span class="glyphicon glyphicon-question-sign get-help" + title="'Executed' tasks are those that need to run in order to + generate the task output"></span> + {% else %} + <h2> + Not Executed + <span class="glyphicon glyphicon-question-sign get-help" title="'Not + executed' tasks don't need to run because their outcome is provided + by another task"></span> + {% endif %} + </h2> + +<dl class="dl-horizontal"> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="To make builds more + efficient, the build system detects changes in the 'inputs' to a + given task by creating a 'task signature'. If the signature changes, + the build system assumes the inputs have changed and the task needs to be +rerun"></span> + Task inputs signature + </dt> + <dd> + {{task.sstate_checksum}} + </dd> + {% if task.sstate_result != task.SSTATE_NA %} + </dl> + <div class="alert alert-info">Attempting to restore output from sstate cache + <span class="glyphicon glyphicon-question-sign get-help + get-help-blue" title="The build system is searching for the + task output in your <code>sstate-cache</code> directory and + mirrors. If the build system finds the task output, it will reuse it + instead of building it from scratch by running the real task. Reusing the + task output makes the build faster"></span> + </div> + <dl class="dl-horizontal"> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="The name of the + file searched for in your <code>sstate-cache</code> + directory and mirrors"></span> + File searched for + </dt> + <dd><code>{{task.path_to_sstate_obj}}</code></dd> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="The locations + searched for the above file (i.e. your + <code>sstate-cache</code> directory and any mirrors you have + set up)"></span> + URI(s) searched + </dt> + <dd><ul class="list-unstyled">{% for uri in uri_list %}<li><code>{{uri}}</code></li>{% endfor %}</ul></dd> + </dl> + {% endif %} + {% if task.sstate_result == task.SSTATE_MISS %} + <div class="alert alert-info"> + <strong>File not in sstate cache.</strong> Running the real task instead. + </div> + {% elif task.sstate_result == task.SSTATE_FAILED%} + <div class="alert alert-warning"> + <strong>Failed</strong> to restore output from sstate cache. The file was found but could not be unpacked. + </div> + <dl class="dl-horizontal"> + <a href="{% url 'build_artifact' build.id "tasklogfile" task.pk %}" style="margin:15px;">Download log</a> + </dl> + <div class="alert alert-info"> + Running the real task instead. + </div> + {% elif task.sstate_result == task.SSTATE_RESTORED %} + <div class="alert alert-info"> + Output <strong>successfully restored</strong> from sstate cache. + </div> + {% endif %} + <dl class="dl-horizontal"> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="The + running sequence of each task in the build"></span> + Task order + </dt> + <dd><a href="{%url "tasks" build.pk %}?page={{task_in_tasks_table_pg}}&limit=25#task-{{task.order}}">{{task.order}}</a></dd> + {% if task.task_executed %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" + title="Indicates if this task executes a Python or Shell + function(s)"></span> + Task script type + </dt> + <dd>{{task.get_script_type_display}}</dd> + {% endif %} +<!-- + <dt> + <i class="icon-question-sign get-help" title="The code executed by the task"></i> + Task executable output + </dt> + <dd><code>{{task.source_url}}</code></dd> +--> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Task dependency chain + (i.e. other tasks)"></span> + Dependencies + </dt> + <dd> + <ul class="list-unstyled"> + {% for dep in deps %} + <li><a href="{%url 'task' dep.build.pk dep.pk%}" class="task-info" title="{{dep.get_executed_display}} | {{dep.get_outcome_display}}">{{dep.recipe.name}}_{{dep.recipe.version}} <span class="task-name">{{dep.task_name}}</span></a></li> + {% empty %} + <li class="text-muted" style="margin-bottom: -10px;">This task has no dependencies</li> + {% endfor %} + </ul> + </dd> + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Tasks that depend on this + task"></span> + Reverse dependencies + </dt> + <dd> + <ul class="list-unstyled"> + {% for dep in rdeps %} + <li><a href="{%url 'task' dep.build.pk dep.pk%}" class="task-info" title="{{dep.get_executed_display}} | {{dep.get_outcome_display}}">{{dep.recipe.name}}_{{dep.recipe.version}} <span class="task-name">{{dep.task_name}}</span></a></li> + {% empty %} + <li class="text-muted">This task has no reverse dependencies</li> + {% endfor %} + </ul> +</dl> + +{# Performance section - shown only for executed tasks #} +{%if task.elapsed_time or task.cpu_time_user or task.cpu_time_system or task.disk_io %} + <h2 class="details">Performance</h2> +{% endif %} + <dl class="dl-horizontal"> + {% if task.elapsed_time %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="How + long it took the task to finish in seconds"></span> + Time (secs) + </dt> + <dd>{{task.elapsed_time|format_none_and_zero|floatformat:2}}</dd> + {% endif %} + {% if task.cpu_time_user > 0 %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Total amount of time + spent executing in user mode, in seconds. Note that this time + can be greater than the task time due to parallel + execution."></span> + User CPU time (secs) + </dt> + <dd>{{task.cpu_time_user|format_none_and_zero|floatformat:2}}</dd> + {% endif %} + {% if task.cpu_time_system > 0 %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Total amount of time + spent executing in kernel mode, in seconds. Note that this time + can be greater than the task time due to parallel + execution."></span> + System CPU time (secs) + </dt> + <dd>{{task.cpu_time_system|format_none_and_zero|floatformat:2}}</dd> + {% endif %} + {% if task.disk_io > 0 %} + <dt> + <span class="glyphicon glyphicon-question-sign get-help" title="Number of bytes + written to and read from the disk during the task"></span> + Disk I/O (bytes) + </dt> + <dd>{{task.disk_io|format_none_and_zero|intcomma}}</dd> + {% endif %} + </dl> + +</div> + +{% endblock %} + diff --git a/poky/bitbake/lib/toaster/toastergui/templates/toastertable-filter.html b/poky/bitbake/lib/toaster/toastergui/templates/toastertable-filter.html new file mode 100644 index 0000000000..25eef52a3d --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/toastertable-filter.html @@ -0,0 +1,24 @@ +<!-- filter modal --> +<div id="filter-modal-{{table_name}}" class="modal fade" tabindex="-1" role="dialog" aria-hidden="false"> + <div class="modal-dialog"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> + <h3 id="filter-modal-title-{{table_name}}"> </h3> + </div> + <div class="modal-body"> + <form id="filter-modal-form-{{table_name}}" style="margin-bottom: 0px"> + <p>Show:</p> + <span id="filter-actions-{{table_name}}"></span> + </div> + <div class="modal-footer"> + <button class="btn btn-primary" type="submit" data-role="filter-apply"> + Apply + </button> + </div> + </form> + </div> + </div> +</div> +<button id="clear-filter-btn-{{table_name}}" style="display:none"></button> +<!-- end filter modal --> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/toastertable-simple.html b/poky/bitbake/lib/toaster/toastergui/templates/toastertable-simple.html new file mode 100644 index 0000000000..56cd2ce375 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/toastertable-simple.html @@ -0,0 +1,100 @@ + +{% load static %} +{% load projecttags %} + +<script src="{% static 'js/table.js' %}"></script> +<script src="{% static 'js/layerBtn.js' %}"></script> +<script> + $(document).ready(function() { + (function(){ + + var ctx = { + tableName : "{{table_name}}", + url : "{{ xhr_table_url }}?format=json", + title : "{{title}}", + projectLayers : {{projectlayers|json}}, + }; + + try { + tableInit(ctx); + } catch (e) { + document.write("Problem loading table widget: " + e); + } + })(); + }); +</script> + +{% include 'toastertable-filter.html' %} + +<div id="no-results-{{table_name}}" style="display:none"> + <div class="alert alert-warning"> + <form class="no-results form-inline"> + <div class="form-group"> + <div class="btn-group"> + <input class="form-control" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/> + <span class="remove-search-btn-{{table_name}} glyphicon glyphicon-remove-circle" tabindex="-1"></span> + </div> + </div> + <button class="btn btn-default search-submit-{{table_name}}">Search</button> + <button class="btn btn-link remove-search-btn-{{table_name}}">Show all {{title|lower}}</button> + </form> + </div> +</div> +<div id="table-container-{{table_name}}" style="visibility: hidden"> + <!-- control header --> + <div id="table-chrome-{{table_name}}"> + <div class="container-fluid detail-page-contols"> + <form class="navbar-form navbar-left"> + <div class="form-group"> + <div class="btn-group"> + <input class="form-control" id="search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{% if request.GET.search %}{{request.GET.search}}{% endif %}"/> + <span href="#" style="display:none" class="remove-search-btn-{{table_name}} glyphicon glyphicon-remove-circle" tabindex="-1"></span> + </div> + </div> + <button class="btn btn-default" id="search-submit-{{table_name}}" >Search</button> + </form> + + <form class="navbar-form navbar-right"> + <div class="form-group"> + <label>Show rows:</label> + <select class="form-control pagesize-{{table_name}}"> + {% with "10 25 50 100 150" as list%} + {% for i in list.split %} + <option value="{{i}}">{{i}}</option> + {% endfor %} + {% endwith %} + </select> + </div> + </form> + </div> + </div> + + <!-- The actual table --> + <div class="table-responsive"> + <table class="table table-bordered table-hover" id="{{table_name}}"> + <thead> + <tr><th></th></tr> + </thead> + <tbody></tbody> + </table> + </div> + + <!-- Pagination controls --> + <div id="pagination-{{table_name}}"> + <ul class="pagination"> + </ul> + + <form class="navbar-form navbar-right"> + <div class="form-group"> + <label>Show rows:</label> + <select class="form-control pagesize-{{table_name}}"> + {% with "10 25 50 100 150" as list%} + {% for i in list.split %} + <option value="{{i}}">{{i}}</option> + {% endfor %} + {% endwith %} + </select> + </div> + </form> + </div> +</div> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/toastertable.html b/poky/bitbake/lib/toaster/toastergui/templates/toastertable.html new file mode 100644 index 0000000000..aa148955e4 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/toastertable.html @@ -0,0 +1,125 @@ + +{% load static %} +{% load projecttags %} + +<script src="{% static 'js/table.js' %}"></script> +<script src="{% static 'js/layerBtn.js' %}"></script> +<script> + $(document).ready(function() { + (function(){ + + var ctx = { + tableName : "{{table_name}}", + url : "{{ xhr_table_url }}?format=json", + title : "{{title}}", + }; + + try { + tableInit(ctx); + } catch (e) { + document.write("Problem loading table widget: " + e); + } + })(); + }); +</script> + +{% include 'toastertable-filter.html' %} + +<div class="row-fluid" id="empty-state-{{table_name}}" style="display:none"> + <div class="alert alert-info">{{empty_state|safe}}</div> +</div> + +<div id="no-results-{{table_name}}" style="display:none"> + <div class="alert alert-warning"> + <form class="form-inline"> + <div class="form-group"> + <div class="btn-group"> + <input class="form-control" id="new-search-input-{{table_name}}" name="search" type="text" placeholder="Search {{title|lower}}" value="{%if request.GET.search %}{{request.GET.search}}{%endif%}"/> + <span class="remove-search-btn-{{table_name}} glyphicon glyphicon-remove-circle" tabindex="-1"></a> + </div> + </div> + <button class="btn btn-default search-submit-{{table_name}}"> + Search + </button> + <button class="btn btn-link show-all-{{table_name}} remove-search-btn-{{table_name}}"> + Show all + </button> + </form> + </div> +</div> + +<div id="table-container-{{table_name}}" style="visibility: hidden"> + <!-- control header --> + <div class="navbar navbar-default" id="table-chrome-{{table_name}}"> + <div class="container-fluid"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#table-chrome-collapse-{{table_name}}" aria-expanded="false"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + </div> + <div class="collapse navbar-collapse" id="table-chrome-collapse-{{table_name}}"> + <form class="navbar-form navbar-left"> + <div class="form-group"> + <div class="btn-group"> + <input id="search-input-{{table_name}}" class="form-control" name="search" type="text" placeholder="Search {{title|lower}}" value="{%if request.GET.search%}{{request.GET.search}}{%endif%}"/> + <span class="remove-search-btn-{{table_name}} glyphicon glyphicon-remove-circle" tabindex="-1" style="display:none;"> + </div> + </div> + <button class="btn btn-default" id="search-submit-{{table_name}}" >Search</button> + </form> + <form class="navbar-form navbar-right"> + <div clas="form-group"> + <label>Show rows:</label> + <select class="form-control pagesize-{{table_name}}"> + {% with "10 25 50 100 150" as list%} + {% for i in list.split %} + <option value="{{i}}">{{i}}</option> + {% endfor %} + {% endwith %} + </select> + </div> + </form> + <div class="btn-group navbar-right"> + <button id="edit-columns-button" class="btn btn-default navbar-btn dropdown-toggle" data-toggle="dropdown">Edit columns + <span class="caret"></span> + </button> + <ul class="dropdown-menu editcol"> + </ul> + </div> + </div> + </div> + </div> + + <!-- The actual table --> + <div class="table-responsive"> + <table class="table table-bordered table-hover" id="{{table_name}}"> + <thead> + <tr><th></th></tr> + </thead> + <tbody></tbody> + </table> + </div> + + <!-- Pagination controls --> + <div id="pagination-{{table_name}}"> + <ul class="pagination"> + </ul> + + <form class="navbar-form navbar-right"> + <div class="form-group"> + <label>Show rows:</label> + <select class="form-control pagesize-{{table_name}}"> + {% with "10 25 50 100 150" as list%} + {% for i in list.split %} + <option value="{{i}}">{{i}}</option> + {% endfor %} + {% endwith %} + </select> + </div> + </form> + </div> + +</div> <!--end table container --> diff --git a/poky/bitbake/lib/toaster/toastergui/templates/unavailable_artifact.html b/poky/bitbake/lib/toaster/toastergui/templates/unavailable_artifact.html new file mode 100644 index 0000000000..fc77e405f7 --- /dev/null +++ b/poky/bitbake/lib/toaster/toastergui/templates/unavailable_artifact.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{% load projecttags %} +{% load humanize %} +{% load static %} + +{% block title %} Build artifact does not exist - Toaster {% endblock %} + +{% block pagecontent %} + <div class="row"> + <div class="col-md-8"> + <div class="alert alert-info lead top-air"> + <p>The build artifact you are trying to download does not exist.</p> + <p><a href="javascript:window.history.back()">Back to previous page</a></p> + </div> + </div> + </div> +{% endblock %} + |