Add support for other distro comparisons

Turn the existing OE-Classic support into something a bit more
generic so we can import data from other distributions and compare it to
what we have in layers.

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
Paul Eggleton 2018-05-14 16:35:06 +12:00
parent 8ab9c15085
commit 72d67231ec
12 changed files with 273 additions and 77 deletions

View File

@ -17,10 +17,10 @@ def layerindex_context(request):
else:
site_name = 'OpenEmbedded Layer Index'
return {
'all_branches': Branch.objects.exclude(name='oe-classic').order_by('sort_priority'),
'all_branches': Branch.objects.exclude(comparison=True).order_by('sort_priority'),
'unpublished_count': LayerItem.objects.filter(status='N').count(),
'oe_classic': Branch.objects.filter(name='oe-classic'),
'site_name': site_name,
'rrs_enabled': 'rrs' in settings.INSTALLED_APPS,
'notices': SiteNotice.objects.filter(disabled=False).filter(Q(expires__isnull=True) | Q(expires__gte=datetime.now())),
'comparison_branches': Branch.objects.filter(comparison=True),
}

View File

@ -215,7 +215,7 @@ BulkChangeEditFormSet = modelformset_factory(RecipeChange, form=BulkChangeEditFo
class ClassicRecipeSearchForm(forms.Form):
COVER_STATUS_CHOICES = [('','(any)'), ('!','(not migrated)')] + ClassicRecipe.COVER_STATUS_CHOICES
COVER_STATUS_CHOICES = [('','(any)'), ('!','(unknown / not available)')] + ClassicRecipe.COVER_STATUS_CHOICES
VERIFIED_CHOICES = [
('', '(any)'),
('1', 'Verified'),

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('layerindex', '0014_sitenotice'),
]
operations = [
migrations.AddField(
model_name='branch',
name='comparison',
field=models.BooleanField(default=False, help_text='If enabled, branch is for comparison purposes only and will appear separately', verbose_name='Comparison'),
),
migrations.AlterField(
model_name='classicrecipe',
name='cover_status',
field=models.CharField(default='U', choices=[('U', 'Unknown'), ('N', 'Not available'), ('R', 'Replaced'), ('P', 'Provided (BBCLASSEXTEND)'), ('C', 'Provided (PACKAGECONFIG)'), ('S', 'Distro-specific'), ('O', 'Obsolete'), ('E', 'Equivalent functionality'), ('D', 'Direct match')], max_length=1),
),
]

View File

@ -71,6 +71,7 @@ class Branch(models.Model):
short_description = models.CharField(max_length=50, blank=True)
sort_priority = models.IntegerField(blank=True, null=True)
updates_enabled = models.BooleanField('Enable updates', default=True, help_text='Enable automatically updating layer metadata for this branch via the update script')
comparison = models.BooleanField('Comparison', default=False, help_text='If enabled, branch is for comparison purposes only and will appear separately')
update_environment = models.ForeignKey(PythonEnvironment, blank=True, null=True, on_delete=models.SET_NULL)
updated = models.DateTimeField(auto_now=True, blank=True, null=True)
@ -80,7 +81,9 @@ class Branch(models.Model):
ordering = ['sort_priority']
def __str__(self):
if self.short_description:
if self.comparison and self.short_description:
return self.short_description
elif self.short_description:
return '%s (%s)' % (self.name, self.short_description)
else:
return self.name
@ -520,6 +523,7 @@ class ClassicRecipe(Recipe):
('R', 'Replaced'),
('P', 'Provided (BBCLASSEXTEND)'),
('C', 'Provided (PACKAGECONFIG)'),
('S', 'Distro-specific'),
('O', 'Obsolete'),
('E', 'Equivalent functionality'),
('D', 'Direct match'),

View File

@ -238,3 +238,19 @@ blockquote.span7.warn {
width: auto;
height: 1em;
}
td.success {
background-color: #dff0d8 !important;
}
td.error {
background-color: #f2dede !important;
}
td.warning {
background-color: #fcf8e3 !important;
}
td.info {
background-color: #d9edf7 !important;
}

View File

@ -129,16 +129,26 @@ urlpatterns = [
RedirectView.as_view(url=reverse_lazy('classic_recipe_search'), permanent=False),
name='classic'),
url(r'^oe-classic/recipes/$',
ClassicRecipeSearchView.as_view(
template_name='layerindex/classicrecipes.html'),
RedirectView.as_view(url=reverse_lazy('comparison_recipe_search', kwargs={'branch': 'oe-classic'}), permanent=False),
name='classic_recipe_search'),
url(r'^oe-classic/stats/$',
ClassicRecipeStatsView.as_view(
template_name='layerindex/classicstats.html'),
RedirectView.as_view(url=reverse_lazy('comparison_recipe_stats', kwargs={'branch': 'oe-classic'}), permanent=False),
name='classic_recipe_stats'),
url(r'^oe-classic/recipe/(?P<pk>[-\w]+)/$',
ClassicRecipeDetailView.as_view(
template_name='layerindex/classicrecipedetail.html'),
name='classic_recipe'),
url(r'^comparison/recipes/(?P<branch>[-\w]+)/$',
ClassicRecipeSearchView.as_view(
template_name='layerindex/classicrecipes.html'),
name='comparison_recipe_search'),
url(r'^comparison/stats/(?P<branch>[-\w]+)/$',
ClassicRecipeStatsView.as_view(
template_name='layerindex/classicstats.html'),
name='comparison_recipe_stats'),
url(r'^comparison/recipe/(?P<pk>[-\w]+)/$',
ClassicRecipeDetailView.as_view(
template_name='layerindex/classicrecipedetail.html'),
name='comparison_recipe'),
url(r'.*', page_not_found, kwargs={'exception': Exception("Page not Found")})
]

View File

@ -1,10 +1,12 @@
# layerindex-web - view definitions
#
# Copyright (C) 2013-2016 Intel Corporation
# Copyright (C) 2013-2018 Intel Corporation
#
# Licensed under the MIT license, see COPYING.MIT for details
import sys
from pkg_resources import parse_version
from itertools import islice
from django.shortcuts import get_object_or_404, get_list_or_404, render
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
from django.core.urlresolvers import reverse, reverse_lazy, resolve
@ -15,10 +17,13 @@ from datetime import datetime
from django.views.generic import TemplateView, DetailView, ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from django.views.generic.base import RedirectView
from django.contrib.messages.views import SuccessMessageMixin
from layerindex.forms import EditLayerForm, LayerMaintainerFormSet, EditNoteForm, EditProfileForm, RecipeChangesetForm, AdvancedRecipeSearchForm, BulkChangeEditFormSet, ClassicRecipeForm, ClassicRecipeSearchForm
from django.db import transaction
from django.contrib.auth.models import User, Permission
from django.db.models import Q, Count, Sum
from django.db.models.functions import Lower
from django.db.models.query import QuerySet
from django.template.loader import get_template
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
@ -867,21 +872,65 @@ class RecipeDetailView(DetailView):
return context
class ClassicRecipeLinkWrapper:
def __init__(self, queryset):
self.queryset = queryset
# This function is required by generic views, create another proxy
def _clone(self):
return ClassicRecipeLinkIterator(self.queryset._clone(), **self.kwargs)
def _annotate(self, obj):
recipe = None
vercmp = 0
if obj.cover_layerbranch and obj.cover_pn:
rq = Recipe.objects.filter(layerbranch=obj.cover_layerbranch).filter(pn=obj.cover_pn)
if rq:
recipe = rq.first()
if obj.pv and recipe.pv:
obj_ver = parse_version(obj.pv)
recipe_ver = parse_version(recipe.pv)
vercmp = ((recipe_ver > obj_ver) - (recipe_ver < obj_ver))
setattr(obj, 'cover_recipe', recipe)
setattr(obj, 'cover_vercmp', vercmp)
def __iter__(self):
for obj in self.queryset:
self._annotate(obj)
yield obj
def _slice(self, start, stop, step=1):
for item in islice(self.queryset, start, stop, step):
self._annotate(item)
yield item
def __getitem__(self, key):
if isinstance(key, slice):
return self._slice(key.start, key.stop, key.step)
else:
return next(self._slice(key, key+1))
def __len__(self):
if isinstance(self.queryset, QuerySet):
return self.queryset.count()
else:
return len(self.queryset)
class ClassicRecipeSearchView(RecipeSearchView):
def render_to_response(self, context, **kwargs):
# Bypass the redirect-to-single-instance behaviour of RecipeSearchView
return super(ListView, self).render_to_response(context, **kwargs)
def get_queryset(self):
self.kwargs['branch'] = 'oe-classic'
self.kwargs['branch'] = self.kwargs.get('branch', 'oe-classic')
query_string = self.request.GET.get('q', '')
cover_status = self.request.GET.get('cover_status', None)
cover_verified = self.request.GET.get('cover_verified', None)
category = self.request.GET.get('category', None)
init_qs = ClassicRecipe.objects.filter(layerbranch__branch__name='oe-classic')
init_qs = ClassicRecipe.objects.filter(layerbranch__branch__name=self.kwargs['branch'])
if cover_status:
if cover_status == '!':
init_qs = init_qs.filter(cover_status__in=['U', 'N'])
init_qs = init_qs.filter(cover_status__in=['U', 'N', 'S'])
else:
init_qs = init_qs.filter(cover_status=cover_status)
if cover_verified:
@ -889,7 +938,7 @@ class ClassicRecipeSearchView(RecipeSearchView):
if category:
init_qs = init_qs.filter(classic_category__icontains=category)
if query_string.strip():
order_by = ('pn', 'layerbranch__layer')
order_by = (Lower('pn'), 'layerbranch__layer')
qs0 = init_qs.filter(pn=query_string).order_by(*order_by)
@ -902,30 +951,33 @@ class ClassicRecipeSearchView(RecipeSearchView):
qs = list(utils.chain_unique(qs0, qs1, qs2))
else:
if 'q' in self.request.GET:
qs = init_qs.order_by('pn', 'layerbranch__layer')
qs = init_qs.order_by(Lower('pn'), 'layerbranch__layer')
else:
# It's a bit too slow to return all records by default, and most people
# won't actually want that (if they do they can just hit the search button
# with no query string)
return Recipe.objects.none()
return qs
return ClassicRecipeLinkWrapper(qs)
def get_context_data(self, **kwargs):
context = super(ClassicRecipeSearchView, self).get_context_data(**kwargs)
context['multi_classic_layers'] = LayerItem.objects.filter(classic=True).count() > 1
context['this_url_name'] = 'recipe_search'
branchname = self.kwargs.get('branch', 'oe-classic')
context['branch'] = get_object_or_404(Branch, name=branchname)
if 'q' in self.request.GET:
searched = True
search_form = ClassicRecipeSearchForm(self.request.GET)
else:
searched = False
search_form = ClassicRecipeSearchForm()
context['compare'] = self.request.GET.get('compare', False)
context['search_form'] = search_form
context['searched'] = searched
return context
class ClassicRecipeDetailView(UpdateView):
class ClassicRecipeDetailView(SuccessMessageMixin, UpdateView):
model = ClassicRecipe
form_class = ClassicRecipeForm
context_object_name = 'recipe'
@ -946,24 +998,41 @@ class ClassicRecipeDetailView(UpdateView):
return super(ClassicRecipeDetailView, self).post(request, *args, **kwargs)
def get_success_message(self, cleaned_data):
return "Comparison saved successfully"
def get_success_url(self):
return reverse_lazy('classic_recipe_search')
return reverse_lazy('comparison_recipe', args=(self.object.id,))
def get_context_data(self, **kwargs):
context = super(ClassicRecipeDetailView, self).get_context_data(**kwargs)
context['can_edit'] = self._can_edit()
recipe = context['recipe']
context['branch'] = recipe.layerbranch.branch
# Get covering recipe if any
cover_recipe = None
if recipe.cover_pn:
rq = Recipe.objects.filter(layerbranch=recipe.cover_layerbranch).filter(pn=recipe.cover_pn)
if rq:
cover_recipe = rq.first()
context['cover_recipe'] = cover_recipe
return context
class ClassicRecipeStatsView(TemplateView):
def get_context_data(self, **kwargs):
context = super(ClassicRecipeStatsView, self).get_context_data(**kwargs)
branchname = self.kwargs.get('branch', 'oe-classic')
context['branch'] = get_object_or_404(Branch, name=branchname)
context['url_branch'] = branchname
context['this_url_name'] = 'recipe_search'
# *** Cover status chart ***
recipes = ClassicRecipe.objects.filter(layerbranch__branch=context['branch'])
statuses = []
status_counts = {}
for choice, desc in ClassicRecipe.COVER_STATUS_CHOICES:
statuses.append(desc)
status_counts[desc] = ClassicRecipe.objects.filter(cover_status=choice).count()
status_counts[desc] = recipes.filter(cover_status=choice).count()
statuses = sorted(statuses, key=lambda status: status_counts[status], reverse=True)
chartdata = {'x': statuses, 'y': [status_counts[k] for k in statuses]}
context['charttype_status'] = 'pieChart'
@ -976,7 +1045,7 @@ class ClassicRecipeStatsView(TemplateView):
}
# *** Categories chart ***
categories = ['obsoletedir', 'nonworkingdir']
uniquevals = ClassicRecipe.objects.exclude(classic_category='').values_list('classic_category', flat=True).distinct()
uniquevals = recipes.exclude(classic_category='').values_list('classic_category', flat=True).distinct()
for value in uniquevals:
cats = value.split()
for cat in cats:
@ -984,7 +1053,7 @@ class ClassicRecipeStatsView(TemplateView):
categories.append(cat)
categories.append('none')
catcounts = dict.fromkeys(categories, 0)
unmigrated = ClassicRecipe.objects.filter(cover_status='U')
unmigrated = recipes.filter(cover_status='U')
catcounts['none'] = unmigrated.filter(classic_category='').count()
values = unmigrated.exclude(classic_category='').values_list('classic_category', flat=True)
# We gather data this way because an item might be in more than one category, thus

View File

@ -28,16 +28,19 @@
{% for branch in all_branches %}
<li><a href="{% url this_url_name branch.name %}{{ extra_url_param }}">
{% if branch.name == url_branch %}<b>{% endif %}
{{ branch.name }}
{% if branch.short_description %}
({{ branch.short_description }})
{% endif %}
{{ branch }}
{% if branch.name == url_branch %}</b>{% endif %}
</a></li>
{% endfor %}
{% if oe_classic %}
{% if comparison_branches %}
<li class="divider"></li>
<li><a href="{% url 'classic' %}">OE-Classic</a></li>
{% for branch in comparison_branches %}
<li><a href="{% url 'comparison_recipe_search' branch.name %}">
{% if branch.name == url_branch %}<b>{% endif %}
{{ branch }}
{% if branch.name == url_branch %}</b>{% endif %}
</a></li>
{% endfor %}
{% endif %}
</ul>
</li>

View File

@ -15,42 +15,23 @@
{% block title_append %} - OE-Classic{% endblock %}
-->
{% block branch_selector %}
{% autoescape on %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Branch: <b>OE-Classic</b>
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
{% for branch in all_branches %}
<li><a href="{% url 'layer_list' branch.name %}">
{{ branch.name }}
{% if branch.short_description %}
({{ branch.short_description }})
{% endif %}
</a></li>
{% endfor %}
<li class="divider"></li>
<li><a href="{% url 'classic' %}"><b>OE-Classic</b></a></li>
</ul>
</li>
{% endautoescape %}
{% endblock %}
{% block content_inner %}
{% autoescape on %}
<div class="container-fluid">
<div class="row-fluid">
{% if branch.name == 'oe-classic' %}
<h2>OE-Classic</h2>
<p>OpenEmbedded-Classic (OE-Classic) is the name for the old monolithic version of OpenEmbedded. It contained a number of recipes some of which have not yet been migrated on top of OE-Core. To help people to find and migrate these recipes we provide an index here as well as some statistics to get an idea of the migration.</p>
{% else %}
<h2>{{ branch.short_description }}</h2>
{% endif %}
<a class="btn btn-large btn-primary" href="{% url 'classic_recipe_search' %}">Recipes</a>
<a class="btn btn-large" href="{% url 'classic_recipe_search' %}?q=&cover_status=!">Unmigrated Recipes</a>
<a class="btn btn-large btn-primary" href="{% url 'classic_recipe_stats' %}">Stats</a>
<a class="btn btn-large btn-primary" href="{% url 'comparison_recipe_search' branch.name %}">Recipes</a>
<a class="btn btn-large" href="{% url 'comparison_recipe_search' branch.name %}?q=&cover_status=!">Unmigrated Recipes</a>
<a class="btn btn-large btn-primary" href="{% url 'comparison_recipe_stats' branch.name %}">Stats</a>
</div>
</div>

View File

@ -3,9 +3,9 @@
{% comment %}
layerindex-web - recipe detail page template
layerindex-web - comparison recipe detail page template
Copyright (C) 2013 Intel Corporation
Copyright (C) 2013, 2018 Intel Corporation
Licensed under the MIT license, see COPYING.MIT for details
{% endcomment %}
@ -13,7 +13,7 @@
<!--
{% autoescape on %}
{% block title_append %} - OE-Classic - {{ recipe.pn }}{% endblock %}
{% block title_append %} - {{ branch.short_description }} - {{ recipe.pn }}{% endblock %}
{% endautoescape %}
-->
@ -21,7 +21,7 @@
{% autoescape on %}
<ul class="breadcrumb">
<li><a href="{% url 'classic_recipe_search' %}">OE-Classic</a> <span class="divider">&rarr;</span></li>
<li><a href="{% url 'comparison_recipe_search' branch.name %}">{{ branch.short_description }}</a> <span class="divider">&rarr;</span></li>
<li class="active">{{ recipe.name }}</li>
</ul>
@ -33,9 +33,11 @@
<h1>{{ recipe.name }} {{ recipe.pv }}</h1>
</div>
{% if branch.name == 'oe-classic' %}
<div class="alert alert-warning">
<b>NOTE:</b> This recipe is for OE-Classic, the older monolithic version of OpenEmbedded which is no longer actively developed. See below for migration information. If no replacement is available in current OpenEmbedded layers, you may be able to <a href="http://www.openembedded.org/wiki/Migrating_metadata_to_OE-Core">migrate the recipe</a> yourself.
</div>
{% endif %}
<table class="table table-striped table-bordered">
<tbody>
@ -61,7 +63,7 @@
</tr>
<tr>
<th>License</th>
<td>{{ recipe.license }}*</td>
<td>{{ recipe.license }}{% if branch.name == 'oe-classic' %}*{% endif %}</td>
</tr>
<tr>
<th>Homepage</th>
@ -74,7 +76,7 @@
</tr>
{% endif %}
<tr>
<th>Recipe file</th>
<th>{% if branch.name == 'oe-classic' %}Recipe file{% else %}Package file{% endif %}</th>
<td>
{% if recipe.vcs_web_url %}
<a href="{{ recipe.vcs_web_url }}">{{ recipe.full_path }}</a>
@ -86,9 +88,37 @@
</tbody>
</table>
{% if branch.name == 'oe-classic' %}
<p>* - in OE-Classic, some of the license values were not accurate. Please refer to current recipes (if available) for this information.</p>
{% endif %}
<h2>Patches</h2>
{% if recipe.patch_set.exists %}
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Patch</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for patch in recipe.patch_set.all %}
<tr>
<td><a href="{{ patch.vcs_web_url }}">{{ patch.src_path }}</a></td>
<td>{{ patch.get_status_display }} {{ patch.status_extra }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>None</p>
{% endif %}
{% if branch.name == 'oe-classic' %}
<h2>Migration information</h2>
{% else %}
<h2>Comparison information</h2>
{% endif %}
{% if can_edit %}
<form id="migration_form" class="form-inline" method="post">
@ -122,6 +152,10 @@
<th class="span2">Coverage</th>
<td>{{ recipe.get_cover_desc }}</td>
</tr>
{% if recipe.cover_pn %}
<th>Covering recipe</th>
<td>{% if cover_recipe %}<a href="{% url 'recipe' cover_recipe.id %}">{% endif %}{{ recipe.cover_pn }}{% if cover_recipe %}</a>{% endif %}{% if recipe.cover_layerbranch %} (in <a href="{% url 'layer_item' 'master' recipe.cover_layerbranch.layer.name %}">{{ recipe.cover_layerbranch.layer.name }}</a>){% endif %}</td>
{% endif %}
<tr>
<th>Categories</th>
<td>{{ recipe.classic_category }}</td>
@ -141,7 +175,7 @@
<script>
enable_value_field = function() {
cover_status = $('#id_cover_status').val()
if( cover_status == 'U' || cover_status == 'N' ) {
if( cover_status == 'U' || cover_status == 'N' || cover_status == 'S' ) {
$('#id_cover_pn').prop('readonly', true);
$('#id_cover_layerbranch').prop('readonly', true);
$('#id_cover_verified').prop('readonly', true);

View File

@ -3,22 +3,22 @@
{% comment %}
layerindex-web - OE-Classic recipe search page template
layerindex-web - comparison recipe search page template
Copyright (C) 2013 Intel Corporation
Copyright (C) 2013, 2018 Intel Corporation
Licensed under the MIT license, see COPYING.MIT for details
{% endcomment %}
<!--
{% block title_append %} - OE-Classic recipes{% endblock %}
{% block title_append %} - {% if branch.name == 'oe-classic' %}OE-Classic recipes{% else %}{{ branch.short_description }} packages{% endif %}{% endblock %}
-->
{% block navs %}
{% autoescape on %}
<li class="active"><a href="{% url 'classic_recipe_search' %}">Recipes</a></li>
<li><a href="{% url 'classic_recipe_stats' %}">Stats</a></li>
<li class="active"><a href="{% url 'comparison_recipe_search' branch.name %}">Recipes</a></li>
<li><a href="{% url 'comparison_recipe_stats' branch.name %}">Stats</a></li>
{% endautoescape %}
{% endblock %}
@ -28,11 +28,16 @@
<div class="row-fluid">
<div class="span12">
{% if branch.name == 'oe-classic' %}
<h2>OE-Classic recipes</h2>
<div class="alert alert-warning">
<b>NOTE:</b> This is the recipe search for OE-Classic, the older monolithic version of OpenEmbedded which is no longer actively developed. <a href="{% url 'recipe_search' 'master' %}">Click here</a> to search current recipes.
</div>
{% else %}
<h2>{{ branch.short_description }} packages</h2>
{% endif %}
<div class="row-fluid">
<form id="search-form" class="form-inline" method="GET">
@ -48,6 +53,7 @@
</td>
</tr>
{% endfor %}
<tr><td><label class="checkbox"><input type="checkbox" name="compare" {% if compare %}checked{% endif %}></input>Show comparison</label></td></tr>
</tbody>
</table>
<button class="btn" type="submit">Search</button>
@ -58,28 +64,68 @@
<table class="table table-striped table-bordered recipestable">
<thead>
<tr>
{% if compare %}
{% if branch.name == 'oe-classic' %}
<th>Recipe name</th>
{% else %}
<th>Package name</th>
{% endif %}
<th>Version</th>
<th>Patches</th>
<th>Status</th>
<th>OE Layer</th>
<th>OE Recipe</th>
<th>OE Version</th>
<th>OE Patches</th>
{% else %}
{% if branch.name == 'oe-classic' %}
<th>Recipe name</th>
{% else %}
<th>Package name</th>
{% endif %}
<th>Version</th>
<th class="span7">Description</th>
<th class="span5">Status</th>
<th>Covering recipe</th>
<th>Categories</th>
{% if multi_classic_layers %}
<th>Layer</th>
{% endif %}
{% endif %}
</tr>
</thead>
<tbody>
{% for recipe in recipe_list %}
<tr {% if recipe.preferred_count > 0 %}class="muted"{% endif %}>
{% if compare %}
{% if branch.name == 'oe-classic' %}
<td><a href="{% url 'classic_recipe' recipe.id %}">{{ recipe.name }}</a></td>
{% else %}
<td><a href="{% url 'comparison_recipe' recipe.id %}">{{ recipe.name }}</a></td>
{% endif %}
<td>{{ recipe.pv|truncatechars:10 }}</td>
<td>{% if recipe.patch_set.exists %}{{ recipe.patch_set.count }}{% endif %}</td>
<td>{{ recipe.get_cover_status_display }}{% if recipe.cover_comment %} <a href="{% url 'classic_recipe' recipe.id %}"><i class="icon-comment" data-toggle="tooltip" title="{{ recipe.cover_comment }}"></i></a>{% endif %}</td>
<td>{% if recipe.cover_layerbranch %}<a href="{% url 'layer_item' 'master' recipe.cover_layerbranch.layer.name %}">{{ recipe.cover_layerbranch.layer.name }}</a>{% endif %}</td>
{% if recipe.cover_pn %}
<td>{% if recipe.cover_recipe %}<a href="{% url 'recipe' recipe.cover_recipe.id %}">{% endif %}{{ recipe.cover_pn }}{% if recipe.cover_recipe %}</a>{% endif %}</td>
<td {% if recipe.cover_vercmp < 0 %}class="error"{% endif %}>{% if recipe.cover_recipe %}{{ recipe.cover_recipe.pv|truncatechars:10 }}{% endif %}</td>
<td>{% if recipe.cover_recipe and recipe.cover_recipe.patch_set.exists %}{{ recipe.cover_recipe.patch_set.count }}{% endif %}</td>
{% else %}
<td></td>
<td></td>
<td></td>
{% endif %}
{% else %}
{% if branch.name == 'oe-classic' %}
<td><a href="{% url 'classic_recipe' recipe.id %}">{{ recipe.name }}</a></td>
{% else %}
<td><a href="{% url 'comparison_recipe' recipe.id %}">{{ recipe.name }}</a></td>
{% endif %}
<td>{{ recipe.pv }}</td>
<td>{{ recipe.short_desc }}</td>
<td>{{ recipe.get_cover_desc }}</td>
<td>{% if recipe.cover_pn %}{% if recipe.cover_recipe %}<a href="{% url 'recipe' recipe.cover_recipe.id %}">{% endif %}{{ recipe.cover_pn }}{% if recipe.cover_recipe %}</a>{% endif %}{% endif %}</td>
<td>{{ recipe.classic_category }}</td>
{% if multi_classic_layers %}
<td><a href="{% url 'layer_item' recipe.layerbranch.layer.name %}">{{ recipe.layerbranch.layer.name }}</a></td>
{% endif %}
{% endif %}
</tr>
{% endfor %}
</tbody>
@ -91,7 +137,11 @@
{% endif %}
{% else %}
{% if searched %}
{% if branch.name == 'oe-classic' %}
<p>No matching OE-Classic recipes in database.</p>
{% else %}
<p>No matching {{ branch }} packages in database.</p>
{% endif %}
{% endif %}
{% endif %}
@ -107,6 +157,7 @@
{% block scripts %}
<script>
$(document).ready(function() {
$('[data-toggle="tooltip"]').tooltip();
firstfield = $("#search-form input:text").first()
if( ! firstfield.val() )
firstfield.focus()

View File

@ -7,20 +7,20 @@
layerindex-web - OE-Classic recipe migration stats template
Copyright (C) 2013 Intel Corporation
Copyright (C) 2013, 2018 Intel Corporation
Licensed under the MIT license, see COPYING.MIT for details
{% endcomment %}
<!--
{% block title_append %} - OE-Classic recipe statistics{% endblock %}
{% block title_append %} - {% if branch.name == 'oe-classic' %}OE-Classic{% else %}{{ branch.short_description }}{% endif %} recipe statistics{% endblock %}
-->
{% block navs %}
{% autoescape on %}
<li><a href="{% url 'classic_recipe_search' %}">Recipes</a></li>
<li class="active"><a href="{% url 'classic_recipe_stats' %}">Stats</a></li>
<li><a href="{% url 'comparison_recipe_search' branch.name %}">Recipes</a></li>
<li class="active"><a href="{% url 'comparison_recipe_stats' branch.name %}">Stats</a></li>
{% endautoescape %}
{% endblock %}
@ -31,12 +31,16 @@
<div class="row-fluid">
{% if branch.name == 'oe-classic' %}
<h2>OE-Classic statistics</h2>
{% else %}
<h2>{{ branch.short_description }} statistics</h2>
{% endif %}
<h3>Migration status</h3>
<h3>Comparison status</h3>
{% include_container "chart_status" 400 600 %}
<h3>Unmigrated recipes by category</h3>
<h3>Unavailable recipes by category</h3>
{% include_container "chart_category" 400 600 %}
</div>