mirror of
git://git.yoctoproject.org/layerindex-web.git
synced 2025-07-19 20:59:01 +02:00
Add duplicate recipes/classes page
Add page that lists recipes and classes "duplicated" across different layers. Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
This commit is contained in:
parent
9af1144928
commit
89f9e6afe8
2
TODO
2
TODO
|
@ -20,7 +20,7 @@ Later:
|
|||
* Return to last page (review/detail) after editing (with success alert)?
|
||||
* Cancel button on edit form?
|
||||
* Query backend service? i.e. special URL to query information for external apps/scripts
|
||||
* Tool for finding/comparing duplicate recipes?
|
||||
* Add comparison to duplicates page
|
||||
* Tool for editing SUMMARY/DESCRIPTION? [Paul working on this]
|
||||
* Dynamic loading/filtering for recipes list
|
||||
* Some way to notify the user when they search for something that has been renamed / replaced / deprecated?
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.conf.urls.defaults import *
|
|||
from django.views.generic import TemplateView, DetailView, ListView
|
||||
from django.views.defaults import page_not_found
|
||||
from layerindex.models import LayerItem, Recipe
|
||||
from layerindex.views import LayerListView, LayerReviewListView, LayerReviewDetailView, RecipeSearchView, MachineSearchView, PlainTextListView, LayerDetailView, edit_layer_view, delete_layer_view, edit_layernote_view, delete_layernote_view, switch_branch_view, HistoryListView, EditProfileFormView
|
||||
from layerindex.views import LayerListView, LayerReviewListView, LayerReviewDetailView, RecipeSearchView, MachineSearchView, PlainTextListView, LayerDetailView, edit_layer_view, delete_layer_view, edit_layernote_view, delete_layernote_view, switch_branch_view, HistoryListView, EditProfileFormView, DuplicatesView
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$',
|
||||
|
@ -71,6 +71,10 @@ urlpatterns = patterns('',
|
|||
HistoryListView.as_view(
|
||||
template_name='layerindex/history.html'),
|
||||
name='history_list'),
|
||||
url(r'^duplicates/$',
|
||||
DuplicatesView.as_view(
|
||||
template_name='layerindex/duplicates.html'),
|
||||
name='duplicates'),
|
||||
url(r'^profile/$',
|
||||
EditProfileFormView.as_view(
|
||||
template_name='layerindex/profile.html'),
|
||||
|
|
|
@ -9,14 +9,14 @@ from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidde
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.template import RequestContext
|
||||
from layerindex.models import Branch, LayerItem, LayerMaintainer, LayerBranch, LayerDependency, LayerNote, Recipe, Machine
|
||||
from layerindex.models import Branch, LayerItem, LayerMaintainer, LayerBranch, LayerDependency, LayerNote, Recipe, Machine, BBClass
|
||||
from datetime import datetime
|
||||
from django.views.generic import DetailView, ListView
|
||||
from django.views.generic import TemplateView, DetailView, ListView
|
||||
from django.views.generic.edit import UpdateView
|
||||
from layerindex.forms import EditLayerForm, LayerMaintainerFormSet, EditNoteForm, EditProfileForm
|
||||
from django.db import transaction
|
||||
from django.contrib.auth.models import User, Permission
|
||||
from django.db.models import Q
|
||||
from django.db.models import Q, Count
|
||||
from django.core.mail import EmailMessage
|
||||
from django.template.loader import get_template
|
||||
from django.template import Context
|
||||
|
@ -256,25 +256,7 @@ class LayerReviewDetailView(LayerDetailView):
|
|||
raise PermissionDenied
|
||||
return super(LayerReviewDetailView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
class RecipeSearchView(ListView):
|
||||
context_object_name = 'recipe_list'
|
||||
paginate_by = 50
|
||||
|
||||
def get_queryset(self):
|
||||
query_string = self.request.GET.get('q', '')
|
||||
init_qs = Recipe.objects.filter(layerbranch__branch__name=self.request.session.get('branch', 'master'))
|
||||
if query_string.strip():
|
||||
entry_query = simplesearch.get_query(query_string, ['pn', 'summary', 'description', 'filename'])
|
||||
qs = init_qs.filter(entry_query).order_by('pn', 'layerbranch__layer')
|
||||
else:
|
||||
if 'q' in self.request.GET:
|
||||
qs = init_qs.order_by('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()
|
||||
|
||||
def recipes_preferred_count(qs):
|
||||
# Add extra column so we can show "duplicate" recipes from other layers de-emphasised
|
||||
# (it's a bit crude having to do this using SQL but I couldn't find a better way...)
|
||||
return qs.extra(
|
||||
|
@ -296,11 +278,51 @@ AND layer2.index_preference > layer1.index_preference
|
|||
},
|
||||
)
|
||||
|
||||
class RecipeSearchView(ListView):
|
||||
context_object_name = 'recipe_list'
|
||||
paginate_by = 50
|
||||
|
||||
def get_queryset(self):
|
||||
query_string = self.request.GET.get('q', '')
|
||||
init_qs = Recipe.objects.filter(layerbranch__branch__name=self.request.session.get('branch', 'master'))
|
||||
if query_string.strip():
|
||||
entry_query = simplesearch.get_query(query_string, ['pn', 'summary', 'description', 'filename'])
|
||||
qs = init_qs.filter(entry_query).order_by('pn', 'layerbranch__layer')
|
||||
else:
|
||||
if 'q' in self.request.GET:
|
||||
qs = init_qs.order_by('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 recipes_preferred_count(qs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(RecipeSearchView, self).get_context_data(**kwargs)
|
||||
context['search_keyword'] = self.request.GET.get('q', '')
|
||||
return context
|
||||
|
||||
class DuplicatesView(TemplateView):
|
||||
def get_recipes(self):
|
||||
init_qs = Recipe.objects.filter(layerbranch__branch__name=self.request.session.get('branch', 'master'))
|
||||
dupes = init_qs.values('pn').annotate(Count('layerbranch', distinct=True)).filter(layerbranch__count__gt=1)
|
||||
qs = init_qs.all().filter(pn__in=[item['pn'] for item in dupes]).order_by('pn', 'layerbranch__layer')
|
||||
return recipes_preferred_count(qs)
|
||||
|
||||
def get_classes(self):
|
||||
init_qs = BBClass.objects.filter(layerbranch__branch__name=self.request.session.get('branch', 'master'))
|
||||
dupes = init_qs.values('name').annotate(Count('layerbranch', distinct=True)).filter(layerbranch__count__gt=1)
|
||||
qs = init_qs.all().filter(name__in=[item['name'] for item in dupes]).order_by('name', 'layerbranch__layer')
|
||||
return qs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(DuplicatesView, self).get_context_data(**kwargs)
|
||||
context['recipes'] = self.get_recipes()
|
||||
context['classes'] = self.get_classes()
|
||||
return context
|
||||
|
||||
class MachineSearchView(ListView):
|
||||
context_object_name = 'machine_list'
|
||||
paginate_by = 50
|
||||
|
|
|
@ -63,6 +63,15 @@
|
|||
{% endif %}
|
||||
</a></li>
|
||||
{% endif %}
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
Tools
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{% url duplicates %}">Duplicates</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="divider-vertical"></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
|
|
96
templates/layerindex/duplicates.html
Normal file
96
templates/layerindex/duplicates.html
Normal file
|
@ -0,0 +1,96 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% comment %}
|
||||
|
||||
layerindex-web - duplicates page template
|
||||
|
||||
Copyright (C) 2013 Intel Corporation
|
||||
Licensed under the MIT license, see COPYING.MIT for details
|
||||
|
||||
{% endcomment %}
|
||||
|
||||
|
||||
<!--
|
||||
{% block title_append %} - duplicates{% endblock %}
|
||||
-->
|
||||
|
||||
{% block content %}
|
||||
{% autoescape on %}
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span9 offset1">
|
||||
<h2>Duplicate recipes</h2>
|
||||
{% if recipes %}
|
||||
<p>Recipes with the same name in different layers:</p>
|
||||
<table class="table table-striped table-bordered recipestable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Recipe name</th>
|
||||
<th>Version</th>
|
||||
<th class="span9">Description</th>
|
||||
<th>Layer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for recipe in recipes %}
|
||||
<tr {% if recipe.preferred_count > 0 %}class="muted"{% endif %}>
|
||||
<td><a href="{% url recipe recipe.id %}">{{ recipe.name }}</a></td>
|
||||
<td>{{ recipe.pv }}</td>
|
||||
<td>{{ recipe.short_desc }}</td>
|
||||
<td><a href="{% url layer_item recipe.layerbranch.layer.name %}">{{ recipe.layerbranch.layer.name }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No duplicate recipes in database.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span9 offset1">
|
||||
<h2>Duplicate classes</h2>
|
||||
{% if classes %}
|
||||
<p>Classes with the same name in different layers:</p>
|
||||
<table class="table table-striped table-bordered recipestable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Class name</th>
|
||||
<th>Layer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for class in classes %}
|
||||
<tr>
|
||||
<td><a href="{% url class.vcs_web_url %}">{{ class.name }}</a></td>
|
||||
<td><a href="{% url layer_item class.layerbranch.layer.name %}">{{ class.layerbranch.layer.name }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No duplicate classes in database.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endautoescape %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
firstfield = $("#filter-form input:text").first()
|
||||
if( ! firstfield.val() )
|
||||
firstfield.focus()
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user