bitbake: toaster: tables Add table for Packages and update SelectPackagesTable
Create a Packages table for use as the image details page. Change the SelectPackagesTable table to inherit from the Packages table. Remove the need for a separate view by adding the additional template context items to the Table's page context. (Bitbake rev: 336b1d8369d9e86ece78b63cb0e140e653216011) Signed-off-by: Michael Wood <michael.g.wood@intel.com> Signed-off-by: brian avery <avery.brian@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
parent
43f0a05fa4
commit
d6e7e4ad43
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
from toastergui.widgets import ToasterTable
|
from toastergui.widgets import ToasterTable
|
||||||
from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project
|
from orm.models import Recipe, ProjectLayer, Layer_Version, Machine, Project
|
||||||
from orm.models import CustomImageRecipe, Package, Build, LogMessage, Task
|
from orm.models import CustomImageRecipe, Package, Target, Build, LogMessage, Task
|
||||||
from orm.models import ProjectTarget
|
from orm.models import ProjectTarget
|
||||||
from django.db.models import Q, Max, Count, When, Case, Value, IntegerField
|
from django.db.models import Q, Max, Count, When, Case, Value, IntegerField
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
@ -483,8 +483,8 @@ class CustomImagesTable(ToasterTable):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(CustomImagesTable, self).get_context_data(**kwargs)
|
context = super(CustomImagesTable, self).get_context_data(**kwargs)
|
||||||
project = Project.objects.get(pk=kwargs['pid'])
|
project = Project.objects.get(pk=kwargs['pid'])
|
||||||
|
# TODO put project into the ToasterTable base class
|
||||||
context['project'] = project
|
context['project'] = project
|
||||||
context['projectlayers'] = map(lambda prjlayer: prjlayer.layercommit.id, ProjectLayer.objects.filter(project=context['project']))
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def setup_queryset(self, *args, **kwargs):
|
def setup_queryset(self, *args, **kwargs):
|
||||||
|
@ -502,22 +502,31 @@ class CustomImagesTable(ToasterTable):
|
||||||
|
|
||||||
self.add_column(title="Custom image",
|
self.add_column(title="Custom image",
|
||||||
hideable=False,
|
hideable=False,
|
||||||
|
orderable=True,
|
||||||
|
field_name="name",
|
||||||
static_data_name="name",
|
static_data_name="name",
|
||||||
static_data_template=name_link_template)
|
static_data_template=name_link_template)
|
||||||
|
|
||||||
self.add_column(title="Recipe file",
|
self.add_column(title="Recipe file",
|
||||||
static_data_name='recipe_file',
|
static_data_name='recipe_file',
|
||||||
static_data_template='')
|
static_data_template='',
|
||||||
|
field_name='local_path')
|
||||||
|
|
||||||
|
approx_packages_template = '''
|
||||||
|
<a href="{% url 'customrecipe' extra.pid data.id %}">
|
||||||
|
{{data.package_set.all|length}}
|
||||||
|
</a>'''
|
||||||
|
|
||||||
approx_packages_template = '<a href="#imagedetails">{{data.packages.all|length}}</a>'
|
|
||||||
self.add_column(title="Approx packages",
|
self.add_column(title="Approx packages",
|
||||||
static_data_name='approx_packages',
|
static_data_name='approx_packages',
|
||||||
static_data_template=approx_packages_template)
|
static_data_template=approx_packages_template)
|
||||||
|
|
||||||
|
|
||||||
build_btn_template = '''<button data-recipe-name="{{data.name}}"
|
build_btn_template = '''
|
||||||
|
<button data-recipe-name="{{data.name}}"
|
||||||
class="btn btn-block build-recipe-btn" style="margin-top: 5px;" >
|
class="btn btn-block build-recipe-btn" style="margin-top: 5px;" >
|
||||||
Build</button>'''
|
Build
|
||||||
|
</button>'''
|
||||||
|
|
||||||
self.add_column(title="Build",
|
self.add_column(title="Build",
|
||||||
hideable=False,
|
hideable=False,
|
||||||
|
@ -540,12 +549,19 @@ class ImageRecipesTable(RecipesTable):
|
||||||
|
|
||||||
|
|
||||||
def setup_columns(self, *args, **kwargs):
|
def setup_columns(self, *args, **kwargs):
|
||||||
|
|
||||||
|
name_link_template = '''
|
||||||
|
<a href="{% url 'recipedetails' extra.pid data.pk %}">{{data.name}}</a>
|
||||||
|
'''
|
||||||
|
|
||||||
self.add_column(title="Image recipe",
|
self.add_column(title="Image recipe",
|
||||||
help_text="When you build an image recipe, you get an "
|
help_text="When you build an image recipe, you get an "
|
||||||
"image: a root file system you can"
|
"image: a root file system you can"
|
||||||
"deploy to a machine",
|
"deploy to a machine",
|
||||||
hideable=False,
|
hideable=False,
|
||||||
orderable=True,
|
orderable=True,
|
||||||
|
static_data_name="name",
|
||||||
|
static_data_template=name_link_template,
|
||||||
field_name="name")
|
field_name="name")
|
||||||
|
|
||||||
super(ImageRecipesTable, self).setup_columns(*args, **kwargs)
|
super(ImageRecipesTable, self).setup_columns(*args, **kwargs)
|
||||||
|
@ -609,8 +625,96 @@ class SoftwareRecipesTable(RecipesTable):
|
||||||
|
|
||||||
self.add_column(**RecipesTable.build_col)
|
self.add_column(**RecipesTable.build_col)
|
||||||
|
|
||||||
|
class PackagesTable(ToasterTable):
|
||||||
|
""" Table to display the packages in a recipe from it's last successful
|
||||||
|
build"""
|
||||||
|
|
||||||
class SelectPackagesTable(ToasterTable):
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(PackagesTable, self).__init__(*args, **kwargs)
|
||||||
|
self.title = "Packages included"
|
||||||
|
self.packages = None
|
||||||
|
self.default_orderby = "name"
|
||||||
|
|
||||||
|
def create_package_list(self, recipe, project_id):
|
||||||
|
"""Creates a list of packages for the specified recipe by looking for
|
||||||
|
the last SUCCEEDED build of ther recipe"""
|
||||||
|
|
||||||
|
target = Target.objects.filter(Q(target=recipe.name) &
|
||||||
|
Q(build__project_id=project_id) &
|
||||||
|
Q(build__outcome=Build.SUCCEEDED)
|
||||||
|
).last()
|
||||||
|
|
||||||
|
if target:
|
||||||
|
return target.build.package_set.all()
|
||||||
|
|
||||||
|
# Target/recipe never successfully built so empty queryset
|
||||||
|
return Package.objects.none()
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
"""Context for rendering the sidebar and other items on the recipe
|
||||||
|
details page """
|
||||||
|
context = super(PackagesTable, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
|
recipe = Recipe.objects.get(pk=kwargs['recipe_id'])
|
||||||
|
project = Project.objects.get(pk=kwargs['pid'])
|
||||||
|
|
||||||
|
in_project = (recipe.layer_version.pk in
|
||||||
|
project.get_project_layer_versions(pk=True))
|
||||||
|
|
||||||
|
packages = self.create_package_list(recipe, project.pk)
|
||||||
|
|
||||||
|
context.update({'project': project,
|
||||||
|
'recipe' : recipe,
|
||||||
|
'packages': packages,
|
||||||
|
'approx_pkg_size' : packages.aggregate(Sum('size')),
|
||||||
|
'in_project' : in_project,
|
||||||
|
})
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def setup_queryset(self, *args, **kwargs):
|
||||||
|
recipe = Recipe.objects.get(pk=kwargs['recipe_id'])
|
||||||
|
|
||||||
|
self.queryset = self.create_package_list(recipe, kwargs['pid'])
|
||||||
|
self.queryset = self.queryset.order_by('name')
|
||||||
|
|
||||||
|
def setup_columns(self, *args, **kwargs):
|
||||||
|
self.add_column(title="Package",
|
||||||
|
hideable=False,
|
||||||
|
orderable=True,
|
||||||
|
field_name="name")
|
||||||
|
|
||||||
|
self.add_column(title="Package Version",
|
||||||
|
field_name="version",
|
||||||
|
hideable=False)
|
||||||
|
|
||||||
|
self.add_column(title="Approx Size",
|
||||||
|
orderable=True,
|
||||||
|
static_data_name="size",
|
||||||
|
static_data_template="{% load projecttags %} \
|
||||||
|
{{data.size|filtered_filesizeformat}}")
|
||||||
|
|
||||||
|
self.add_column(title="License",
|
||||||
|
field_name="license",
|
||||||
|
orderable=True)
|
||||||
|
|
||||||
|
|
||||||
|
self.add_column(title="Dependencies",
|
||||||
|
static_data_name="dependencies",
|
||||||
|
static_data_template='\
|
||||||
|
{% include "snippets/pkg_dependencies_popover.html" %}')
|
||||||
|
|
||||||
|
self.add_column(title="Recipe",
|
||||||
|
field_name="recipe__name",
|
||||||
|
orderable=True,
|
||||||
|
hidden=True)
|
||||||
|
|
||||||
|
self.add_column(title="Recipe version",
|
||||||
|
field_name="recipe__version",
|
||||||
|
hidden=True)
|
||||||
|
|
||||||
|
|
||||||
|
class SelectPackagesTable(PackagesTable):
|
||||||
""" Table to display the packages to add and remove from an image """
|
""" Table to display the packages to add and remove from an image """
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -637,29 +741,25 @@ class SelectPackagesTable(ToasterTable):
|
||||||
self.static_context_extra['current_packages'] = \
|
self.static_context_extra['current_packages'] = \
|
||||||
cust_recipe.packages.values_list('pk', flat=True)
|
cust_recipe.packages.values_list('pk', flat=True)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(SelectPackagesTable, self).get_context_data(**kwargs)
|
||||||
|
custom_recipe = CustomImageRecipe.objects.get(pk=kwargs['recipe_id'])
|
||||||
|
|
||||||
|
context['recipe'] = custom_recipe
|
||||||
|
context['approx_pkg_size'] = custom_recipe.package_set.aggregate(Sum('size'))
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
def setup_columns(self, *args, **kwargs):
|
def setup_columns(self, *args, **kwargs):
|
||||||
self.add_column(title="Package",
|
super(SelectPackagesTable, self).setup_columns(*args, **kwargs)
|
||||||
hideable=False,
|
|
||||||
orderable=True,
|
|
||||||
field_name="name")
|
|
||||||
|
|
||||||
self.add_column(title="Package Version",
|
|
||||||
field_name="version")
|
|
||||||
|
|
||||||
self.add_column(title="Approx Size",
|
|
||||||
orderable=True,
|
|
||||||
static_data_name="size",
|
|
||||||
static_data_template="{% load projecttags %} \
|
|
||||||
{{data.size|filtered_filesizeformat}}")
|
|
||||||
self.add_column(title="summary",
|
|
||||||
field_name="summary")
|
|
||||||
|
|
||||||
self.add_column(title="Add | Remove",
|
self.add_column(title="Add | Remove",
|
||||||
|
hideable=False,
|
||||||
help_text="Use the add and remove buttons to modify "
|
help_text="Use the add and remove buttons to modify "
|
||||||
"the package content of you custom image",
|
"the package content of you custom image",
|
||||||
static_data_name="add_rm_pkg_btn",
|
static_data_name="add_rm_pkg_btn",
|
||||||
static_data_template='{% include "pkg_add_rm_btn.html" %}',
|
static_data_template='{% include "pkg_add_rm_btn.html" %}',
|
||||||
static_data_template='{% include "pkg_add_rm_btn.html" %}'
|
filter_name="in_current_image"
|
||||||
)
|
)
|
||||||
|
|
||||||
def setup_filters(self, *args, **kwargs):
|
def setup_filters(self, *args, **kwargs):
|
||||||
|
@ -681,12 +781,11 @@ class SelectPackagesTable(ToasterTable):
|
||||||
self.filter_not_in_image)
|
self.filter_not_in_image)
|
||||||
])
|
])
|
||||||
|
|
||||||
def filter_in_image(self, count_only=False):
|
def filter_in_image(self):
|
||||||
return self.queryset.filter(
|
return self.queryset.filter(
|
||||||
pk__in=self.static_context_extra['current_packages'])
|
pk__in=self.static_context_extra['current_packages'])
|
||||||
|
|
||||||
|
def filter_not_in_image(self):
|
||||||
def filter_not_in_image(self, count_only=False):
|
|
||||||
return self.queryset.exclude(
|
return self.queryset.exclude(
|
||||||
pk__in=self.static_context_extra['current_packages'])
|
pk__in=self.static_context_extra['current_packages'])
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{# Popover that displays the dependences and sizes of a package 'data' used in the Packages table #}
|
||||||
|
{% with data.package_dependencies_source.count as dep_count %}
|
||||||
|
{% load projecttags %}
|
||||||
|
{% if dep_count %}
|
||||||
|
<a data-content="<ul class='unstyled'>
|
||||||
|
{% for dep in data.package_dependencies_source.all %}
|
||||||
|
<li>{{dep.depends_on.name}} {% if dep.depends_on.size > 0 %}({{dep.depends_on.size|filtered_filesizeformat}}){% endif %}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>" title="" class="btn" data-original-title="
|
||||||
|
<strong>{{data.name}}</strong> dependencies - <strong>{{data.package_dependencies_source.get_total_source_deps_size.depends_on__size__sum|filtered_filesizeformat}}</strong>">
|
||||||
|
{{dep_count}}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
|
@ -109,13 +109,10 @@ urlpatterns = patterns('toastergui.views',
|
||||||
tables.NewCustomImagesTable.as_view(template_name="newcustomimage.html"),
|
tables.NewCustomImagesTable.as_view(template_name="newcustomimage.html"),
|
||||||
name="newcustomimage"),
|
name="newcustomimage"),
|
||||||
|
|
||||||
|
|
||||||
url(r'^project/(?P<pid>\d+)/layers/$',
|
url(r'^project/(?P<pid>\d+)/layers/$',
|
||||||
tables.LayersTable.as_view(template_name="generic-toastertable-page.html"),
|
tables.LayersTable.as_view(template_name="generic-toastertable-page.html"),
|
||||||
name="projectlayers"),
|
name="projectlayers"),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
url(r'^project/(?P<pid>\d+)/layer/(?P<layerid>\d+)$',
|
url(r'^project/(?P<pid>\d+)/layer/(?P<layerid>\d+)$',
|
||||||
'layerdetails', name='layerdetails'),
|
'layerdetails', name='layerdetails'),
|
||||||
|
|
||||||
|
@ -133,17 +130,20 @@ urlpatterns = patterns('toastergui.views',
|
||||||
|
|
||||||
|
|
||||||
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipeid>\d+)/selectpackages/$',
|
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipeid>\d+)/selectpackages/$',
|
||||||
tables.SelectPackagesTable.as_view(template_name="generic-toastertable-page.html"), name="recipeselectpackages"),
|
tables.SelectPackagesTable.as_view(), name="recipeselectpackages"),
|
||||||
|
|
||||||
|
|
||||||
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)$',
|
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)$',
|
||||||
'customrecipe',
|
tables.SelectPackagesTable.as_view(template_name="customrecipe.html"),
|
||||||
name="customrecipe"),
|
name="customrecipe"),
|
||||||
|
|
||||||
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)/download$',
|
url(r'^project/(?P<pid>\d+)/customrecipe/(?P<recipe_id>\d+)/download$',
|
||||||
'customrecipe_download',
|
'customrecipe_download',
|
||||||
name="customrecipedownload"),
|
name="customrecipedownload"),
|
||||||
|
|
||||||
|
url(r'^project/(?P<pid>\d+)/recipe/(?P<recipe_id>\d+)$',
|
||||||
|
tables.PackagesTable.as_view(template_name="recipedetails.html"),
|
||||||
|
name="recipedetails"),
|
||||||
|
|
||||||
# typeahead api end points
|
# typeahead api end points
|
||||||
url(r'^xhr_typeahead/(?P<pid>\d+)/layers$',
|
url(r'^xhr_typeahead/(?P<pid>\d+)/layers$',
|
||||||
|
|
|
@ -2594,15 +2594,6 @@ if True:
|
||||||
|
|
||||||
return(vars_managed,sorted(vars_fstypes),vars_blacklist)
|
return(vars_managed,sorted(vars_fstypes),vars_blacklist)
|
||||||
|
|
||||||
def customrecipe(request, pid, recipe_id):
|
|
||||||
project = Project.objects.get(pk=pid)
|
|
||||||
context = {'project' : project,
|
|
||||||
'projectlayers': [],
|
|
||||||
'recipe' : CustomImageRecipe.objects.get(pk=recipe_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
return render(request, "customrecipe.html", context)
|
|
||||||
|
|
||||||
@_template_renderer("projectconf.html")
|
@_template_renderer("projectconf.html")
|
||||||
def projectconf(request, pid):
|
def projectconf(request, pid):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue