Skip to content

Commit

Permalink
Reflect search and pagination in TM tab (mozilla#3450)
Browse files Browse the repository at this point in the history
It is now possible to link to a particular view in a TM tab, reflecting any search parameters and the number of pages to load.

Also included are the following changes:
* Make TM tab available to Translators, not just Managers
* Add more contrast to the search fields
* Bugfix: Narrow down event targets
  • Loading branch information
mathjazz authored Nov 20, 2024
1 parent 6948122 commit 514c3bd
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 51 deletions.
1 change: 1 addition & 0 deletions pontoon/base/static/css/dark-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
--popup-background-1: #333941;
--input-background-1: #333941;
--input-color-1: #aaaaaa;
--input-color-2: #ffffff;
--toggle-color-1: #777777;
--icon-background-1: #3f4752;
--icon-border-1: #4d5967;
Expand Down
1 change: 1 addition & 0 deletions pontoon/base/static/css/light-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
--popup-background-1: #ffffff;
--input-background-1: #ffffff;
--input-color-1: #000000;
--input-color-2: #000000;
--toggle-color-1: #888888;
--icon-background-1: #d0d0d0;
--icon-border-1: #bbbbbb;
Expand Down
1 change: 1 addition & 0 deletions pontoon/base/static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1424,6 +1424,7 @@ body > form,
.controls > .search-wrapper input {
background: var(--dark-grey-1);
border: 1px solid var(--main-border-1);
color: var(--input-color-2);
font-size: 13px;
height: 28px;
width: 100%;
Expand Down
94 changes: 60 additions & 34 deletions pontoon/teams/static/js/translation_memory.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
$(function () {
let currentPage = 1; // First page is loaded on page load
let search = '';
const locale = $('#server').data('locale');

// Update state from URL parameters
const urlParams = new URLSearchParams(window.location.search);
let currentPage = parseInt(urlParams.get('pages')) || 1;
let search = urlParams.get('search') || '';

function updateURL() {
const url = new URL(window.location);

if (currentPage > 1) {
url.searchParams.set('pages', currentPage);
} else {
url.searchParams.delete('pages');
}

if (search) {
url.searchParams.set('search', search);
} else {
url.searchParams.delete('search');
}

history.replaceState(null, '', url);
}

function loadMoreEntries() {
const tmList = $('#main .container .translation-memory-list');
const tmList = $('#main .translation-memory-list');
const loader = tmList.find('.skeleton-loader');

// If the loader is already loading, don't load more entries
Expand All @@ -25,11 +46,12 @@ $(function () {
});
const tbody = tmList.find('tbody');
if (currentPage === 0) {
// Clear the table if it's a new search
// Clear the table for a new search
tbody.empty();
}
tbody.append(data);
currentPage += 1;
updateURL(); // Update the URL with the new pages count and search query
},
error: function () {
Pontoon.endLoader('Error loading more TM entries.');
Expand All @@ -54,7 +76,7 @@ $(function () {
});

// Listen for search on Enter key press
$('body').on('keypress', '.table-filter', function (e) {
$('body').on('keypress', '.translation-memory .table-filter', function (e) {
if (e.key === 'Enter') {
currentPage = 0; // Reset page count for a new search
search = $(this).val();
Expand All @@ -63,18 +85,18 @@ $(function () {
});

// Cancel action
$('body').on('click', '.button.cancel', function () {
$('body').on('click', '.translation-memory .button.cancel', function () {
const row = $(this).parents('tr');
row.removeClass('deleting editing');
});

// Edit TM entries
$('body').on('click', '.button.edit', function () {
$('body').on('click', '.translation-memory .button.edit', function () {
const row = $(this).parents('tr');
row.addClass('editing');
row.find('.target textarea').focus();
});
$('body').on('click', '.button.save', function () {
$('body').on('click', '.translation-memory .button.save', function () {
const row = $(this).parents('tr');
const ids = row.data('ids');
const target = row.find('.target textarea').val();
Expand Down Expand Up @@ -112,34 +134,38 @@ $(function () {
});

// Delete TM entries
$('body').on('click', '.button.delete', function () {
$('body').on('click', '.translation-memory .button.delete', function () {
const row = $(this).parents('tr');
row.addClass('deleting');
});
$('body').on('click', '.button.are-you-sure', function () {
const row = $(this).parents('tr');
const ids = row.data('ids');
$('body').on(
'click',
'.translation-memory .button.are-you-sure',
function () {
const row = $(this).parents('tr');
const ids = row.data('ids');

$.ajax({
url: `/${locale}/ajax/translation-memory/delete/`,
method: 'POST',
data: {
csrfmiddlewaretoken: $('body').data('csrf'),
ids: ids,
},
success: function () {
row.addClass('fade-out');
setTimeout(function () {
row.remove();
Pontoon.endLoader('TM entries deleted.');
}, 500);
},
error: function () {
Pontoon.endLoader('Error deleting TM entries.');
},
complete: function () {
row.removeClass('deleting');
},
});
});
$.ajax({
url: `/${locale}/ajax/translation-memory/delete/`,
method: 'POST',
data: {
csrfmiddlewaretoken: $('body').data('csrf'),
ids: ids,
},
success: function () {
row.addClass('fade-out');
setTimeout(function () {
row.remove();
Pontoon.endLoader('TM entries deleted.');
}, 500);
},
error: function () {
Pontoon.endLoader('Error deleting TM entries.');
},
complete: function () {
row.removeClass('deleting');
},
});
},
);
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
{% if tm_entries|length == 0 %}
<p class="no-results">No translation memory entries stored yet.</p>
{% else %}
<div class="translation-memory items">
<menu class="controls">
<div class="search-wrapper small clearfix">
<div class="icon fa fa-search"></div>
<input class="table-filter" type="search" autocomplete="off" autofocus
<input class="table-filter" type="search" autocomplete="off" value="{{ search_query }}" autofocus
placeholder="Search translation memory">
</div>
</menu>
Expand All @@ -23,4 +20,3 @@
</tbody>
</table>
</div>
{% endif %}
2 changes: 1 addition & 1 deletion pontoon/teams/templates/teams/team.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ <h1>
)
}}
{% endif %}
{% if request.user.has_perm('base.can_manage_locale', locale) %}
{% if request.user.has_perm('base.can_translate_locale', locale) %}
{{ Menu.item(
'TM',
url('pontoon.teams.translation-memory', locale.code),
Expand Down
38 changes: 27 additions & 11 deletions pontoon/teams/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,21 @@ def ajax_permissions(request, locale):


@require_AJAX
@permission_required_or_403("base.can_manage_locale", (Locale, "code", "locale"))
@permission_required_or_403("base.can_translate_locale", (Locale, "code", "locale"))
@transaction.atomic
def ajax_translation_memory(request, locale):
"""Translation Memory tab."""
locale = get_object_or_404(Locale, code=locale)
search_query = request.GET.get("search", "").strip()
page_number = request.GET.get("page", 1)

try:
first_page_number = int(request.GET.get("page", 1))
page_count = int(request.GET.get("pages", 1))
except ValueError as e:
return JsonResponse(
{"status": False, "message": f"Bad Request: {e}"},
status=400,
)

tm_entries = TranslationMemoryEntry.objects.filter(locale=locale)

Expand All @@ -289,14 +297,22 @@ def ajax_translation_memory(request, locale):
)
)

per_page = 100 # Number of entries per page
paginator = Paginator(tm_entries, per_page)
page = paginator.get_page(page_number)
entries_per_page = 100
paginator = Paginator(tm_entries, entries_per_page)

combined_entries = []

for page_number in range(first_page_number, first_page_number + page_count):
if page_number > paginator.num_pages:
break
page = paginator.get_page(page_number)
combined_entries.extend(page.object_list)

# If the subsequent page is requested, return only the entries
# For the inital load, render the entire tab. For subsequent requests
# (determined by the "page" attribute), only render the entries.
template = (
"teams/widgets/translation_memory_entries.html"
if page_number != 1
if "page" in request.GET
else "teams/includes/translation_memory.html"
)

Expand All @@ -306,15 +322,15 @@ def ajax_translation_memory(request, locale):
{
"locale": locale,
"search_query": search_query,
"tm_entries": page,
"has_next": page.has_next(),
"tm_entries": combined_entries,
"has_next": paginator.num_pages > page_number,
},
)


@require_AJAX
@require_POST
@permission_required_or_403("base.can_manage_locale", (Locale, "code", "locale"))
@permission_required_or_403("base.can_translate_locale", (Locale, "code", "locale"))
@transaction.atomic
def ajax_translation_memory_edit(request, locale):
"""Edit Translation Memory entries."""
Expand Down Expand Up @@ -342,7 +358,7 @@ def ajax_translation_memory_edit(request, locale):

@require_AJAX
@require_POST
@permission_required_or_403("base.can_manage_locale", (Locale, "code", "locale"))
@permission_required_or_403("base.can_translate_locale", (Locale, "code", "locale"))
@transaction.atomic
def ajax_translation_memory_delete(request, locale):
"""Delete Translation Memory entries."""
Expand Down

0 comments on commit 514c3bd

Please sign in to comment.