Skip to content

Commit

Permalink
Editor: allow filtering by check categories
Browse files Browse the repository at this point in the history
  • Loading branch information
Igor Afanasyev authored and julen committed Nov 13, 2016
1 parent c016403 commit 4a3732f
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 101 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Zing Changelog
v0.1.2 (in development)
-----------------------

* Editor: added the ability to select groups of failing checks (#80).
* Removed extra layer of serialization (#88).


Expand Down
18 changes: 11 additions & 7 deletions pootle/apps/pootle_store/unit/filters.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) Pootle contributors.
# Copyright (C) Zing contributors.
#
# This file is a part of the Pootle project. It is distributed under the GPL3
# This file is a part of the Zing project. It is distributed under the GPL3
# or later license. See the LICENSE file for a copy of the license and the
# AUTHORS file for copyright and authorship information.

Expand Down Expand Up @@ -33,7 +34,7 @@ def filter(self, unit_filter):
class UnitChecksFilter(BaseUnitFilter):

def __init__(self, qs, *args, **kwargs):
self.qs = qs
super(UnitChecksFilter, self).__init__(qs, *args, **kwargs)
self.checks = kwargs.get("checks")
self.category = kwargs.get("category")

Expand All @@ -42,11 +43,15 @@ def filter_checks(self):
return self.qs.filter(
qualitycheck__false_positive=False,
qualitycheck__name__in=self.checks).distinct()
elif self.category:

if self.category:
return self.qs.filter(
qualitycheck__false_positive=False,
qualitycheck__category=self.category).distinct()
return self.qs.none()

return self.qs.filter(
qualitycheck__false_positive=False,
).distinct()


class UnitStateFilter(BaseUnitFilter):
Expand All @@ -73,7 +78,7 @@ class UnitContributionFilter(BaseUnitFilter):
"""Filter a Unit qs based on user contributions"""

def __init__(self, qs, *args, **kwargs):
self.qs = qs
super(UnitContributionFilter, self).__init__(qs, *args, **kwargs)
self.user = kwargs.get("user")

def filter_suggestions(self):
Expand Down Expand Up @@ -128,8 +133,7 @@ def filter_my_submissions_overwritten(self):

class UnitSearchFilter(object):

filters = (
UnitChecksFilter, UnitStateFilter, UnitContributionFilter)
filters = (UnitChecksFilter, UnitStateFilter, UnitContributionFilter)

def filter(self, qs, unit_filter, *args, **kwargs):
for search_filter in self.filters:
Expand Down
19 changes: 18 additions & 1 deletion pootle/static/css/select2-pootle.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/*
* Copyright (C) Pootle contributors.
* Copyright (C) Zing contributors.
*
* This file is a part of the Pootle project. It is distributed under the GPL3
* This file is a part of the Zing project. It is distributed under the GPL3
* or later license. See the LICENSE file for a copy of the license and the
* AUTHORS file for copyright and authorship information.
*/
Expand Down Expand Up @@ -214,3 +215,19 @@ html[dir="rtl"] .select2-search-choice-close
min-width: 20em;
max-width: 20em;
}

/*
* For checks dropdown, we want to hide default optgroups and make
* options with 'category' class look more or less like optgroups.
*/

.checks-dropdown .optgroup > div.select2-result-label
{
display: none;
}

.checks-dropdown .category
{
font-weight: bold;
margin-left: -1em;
}
160 changes: 80 additions & 80 deletions pootle/static/js/editor/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ const ALLOWED_SORTS = ['oldest', 'newest', 'default'];

const filterSelectOpts = {
dropdownAutoWidth: true,
dropdownCssClass: 'checks-dropdown',
width: 'off',
};
const sortSelectOpts = assign({
Expand Down Expand Up @@ -438,25 +439,25 @@ PTL.editor = {
// Reset to defaults
this.filter = 'all';
this.checks = [];
this.category = [];
this.category = undefined;
this.sortBy = 'default';

if ('filter' in params) {
const filterName = params.filter;
const filterName = params.filter || 'all';

// Set current state
this.filter = filterName;
// Set current state
this.filter = filterName;

if (filterName === 'checks' && 'checks' in params) {
if (this.filter === 'checks') {
if ('checks' in params) {
this.checks = params.checks.split(',');
}
if (filterName === 'checks' && 'category' in params) {
} else if ('category' in params) {
this.category = params.category;
}
if ('sort' in params) {
const { sort } = params;
this.sortBy = ALLOWED_SORTS.indexOf(sort) !== -1 ? sort : 'default';
}
this.getCheckOptions();
}
if ('sort' in params) {
const { sort } = params;
this.sortBy = ALLOWED_SORTS.indexOf(sort) !== -1 ? sort : 'default';
}

if ('modified-since' in params) {
Expand Down Expand Up @@ -537,19 +538,15 @@ PTL.editor = {
this.$filterStatus.select2('val', filterValue);

if (this.filter === 'checks') {
// if the checks selector is empty (i.e. the 'change' event was not fired
// because the selection did not change), force the update to populate the selector
if (this.$filterChecks.is(':hidden')) {
this.getCheckOptions();
}
this.$filterChecksWrapper.css('display', 'inline-block');
const selectedValue = this.category || this.checks[0] || 'all';
this.$filterChecks.select2(filterSelectOpts).select2('val', selectedValue);
} else {
this.$filterChecksWrapper.hide();
}

this.$filterSortBy.select2('val', this.sortBy);

if (this.filter === 'search') {
this.$filterChecksWrapper.hide();
}

// re-enable normal event handling
this.preventNavigation = false;

Expand Down Expand Up @@ -1170,7 +1167,7 @@ PTL.editor = {
if (this.filter === 'checks' && this.checks.length) {
reqData.checks = this.checks.join(',');
}
if (this.filter === 'checks' && this.category.length) {
if (this.filter === 'checks' && this.category) {
reqData.category = this.category;
}

Expand Down Expand Up @@ -1735,7 +1732,7 @@ PTL.editor = {
getCheckOptions() {
StatsAPI.getChecks(this.settings.pootlePath)
.then(
(data) => this.appendChecks(data),
(data) => this.updateChecksDropdown(data),
this.error
);
},
Expand All @@ -1749,57 +1746,58 @@ PTL.editor = {
return false;
}

const filterChecks = this.$filterChecks.val();
const name = this.$filterChecks.val();
const isCategory = $(this.$filterChecks.select2('data').element)
.data('type') === 'category';

if (filterChecks !== 'none') {
const sortBy = this.$filterSortBy.val();
const newHash = {
filter: 'checks',
checks: filterChecks,
};
const sortBy = this.$filterSortBy.val();
const newHash = {
filter: 'checks',
};

if (sortBy !== 'default') {
newHash.sort = sortBy;
if (name !== 'all') {
if (isCategory) {
newHash.category = name;
} else {
newHash.checks = name;
}
}

$.history.load($.param(newHash));
if (sortBy !== 'default') {
newHash.sort = sortBy;
}

$.history.load($.param(newHash));
return true;
},

/* Adds the failing checks to the UI */
appendChecks(checks) {
if (Object.keys(checks).length) {
const $checks = this.$filterChecks;
const selectedValue = this.checks[0] || 'none';

$checks.find('optgroup').each(function displayGroups() {
const $gr = $(this);
let empty = true;

$gr.find('option').each(function displayOptions() {
const $opt = $(this);
const value = $opt.val();

if (value in checks) {
empty = false;
$opt.text(`${$opt.data('title')}(${checks[value]})`);
} else {
$opt.remove();
}
});
updateChecksDropdown(checks) {
const $checks = this.$filterChecks;

$checks.find('optgroup').each(function displayGroups() {
const $gr = $(this);
let groupTotal = 0;

$gr.find('option').each(function displayOptions() {
const $opt = $(this);
const value = $opt.val();

if ($opt.hasClass('category')) {
return;
}

if (empty) {
$gr.hide();
if (value in checks) {
groupTotal += checks[value];
} else {
$opt.remove();
}
});

$checks.select2(filterSelectOpts).select2('val', selectedValue);
this.$filterChecksWrapper.css('display', 'inline-block');
} else { // No results
this.displayMsg({ body: gettext('No results.') });
this.$filterStatus.select2('val', this.filter);
}
if (groupTotal === 0) {
$gr.hide();
}
});
},

filterSort() {
Expand All @@ -1810,9 +1808,12 @@ PTL.editor = {
const sortBy = this.$filterSortBy.val();
const user = this.user || null;

const newHash = { filter: filterBy };
const newHash = {};
if (filterBy !== 'all') {
newHash.filter = filterBy;
}

if (this.category.length) {
if (this.category) {
newHash.category = this.category;
} else if (filterChecks !== 'none') {
newHash.checks = filterChecks;
Expand Down Expand Up @@ -1840,28 +1841,27 @@ PTL.editor = {
const $selected = this.$filterStatus.find('option:selected');
const filterBy = $selected.val();

if (filterBy === 'checks') {
this.getCheckOptions();
} else { // Normal filtering options (untranslated, fuzzy...)
this.$filterChecksWrapper.hide();
this.$filterChecksWrapper.hide();

if (!this.preventNavigation) {
const newHash = { filter: filterBy };
const isUserFilter = $selected.data('user');
if (!this.preventNavigation) {
const newHash = {};
if (filterBy !== 'all') {
newHash.filter = filterBy;
}
const isUserFilter = $selected.data('user');

if (this.user && isUserFilter) {
newHash.user = this.user;
} else {
this.user = null;
$('.js-user-filter').remove();
if (this.user && isUserFilter) {
newHash.user = this.user;
} else {
this.user = null;
$('.js-user-filter').remove();

if (this.sortBy !== 'default') {
newHash.sort = this.sortBy;
}
if (this.sortBy !== 'default') {
newHash.sort = this.sortBy;
}

$.history.load($.param(newHash));
}

$.history.load($.param(newHash));
}
return true;
},
Expand Down
8 changes: 5 additions & 3 deletions pootle/templates/editor/_filters.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
</li>
<li class="js-filter-checks-wrapper hide">
<select id="js-filter-checks">
<option selected value="none">{% trans 'Select type' %}</option>
{% comment %}Translators: This refers to "All checks"{% endcomment %}
<option selected value="all">{% trans "All" %}</option>
{% for item in check_categories %}
<optgroup label="{{ item.title }}">
<optgroup class="optgroup" label="">
<option class="category" data-type="category" value="{{ item.name }}">{{ item.title }}</option>
{% for check in item.checks %}
<option value="{{ check.code }}" data-title="{{ check.title }}"></option>
<option value="{{ check.code }}">{{ check.title }}</option>
{% endfor %}
</optgroup>
{% endfor %}
Expand Down
3 changes: 2 additions & 1 deletion pytest_pootle/fixtures/search.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) Pootle contributors.
# Copyright (C) Zing contributors.
#
# This file is a part of the Pootle project. It is distributed under the GPL3
# This file is a part of the Zing project. It is distributed under the GPL3
# or later license. See the LICENSE file for a copy of the license and the
# AUTHORS file for copyright and authorship information.

Expand Down
Loading

0 comments on commit 4a3732f

Please sign in to comment.