From 93788e04262cac3857eef4afd64794a4510be0f0 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:07:29 +0000 Subject: [PATCH 1/4] Add speaker name filter to proposal review recap screen Adds a text input filter that allows filtering proposals by speaker name in the review recap screen. The filter performs case-insensitive substring matching on the speaker's full name. Closes #4547 Co-authored-by: Marco Acierno --- backend/reviews/templates/proposals-recap.html | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/reviews/templates/proposals-recap.html b/backend/reviews/templates/proposals-recap.html index 4ad965f72a..e4d94242a5 100644 --- a/backend/reviews/templates/proposals-recap.html +++ b/backend/reviews/templates/proposals-recap.html @@ -261,11 +261,13 @@ const filterWithReviewsSelect = document.querySelector('#filter-with-n-reviews'); const filterByStatusInputs = [...document.querySelectorAll('input[name="filter-by-status"]')]; const filterByTypeInputs = [...document.querySelectorAll('input[name="filter-by-type"]')]; + const filterBySpeakerInput = document.querySelector('#filter-by-speaker'); const applyFilters = () => { const reviewFilterValue = filterWithReviewsSelect.value; const visibleStatuses = filterByStatusInputs.filter(input => input.checked).map(input => input.value); const visibleTypes = filterByTypeInputs.filter(input => input.checked).map(input => input.value); + const speakerFilter = filterBySpeakerInput.value.toLowerCase().trim(); document.querySelectorAll('.proposal-item').forEach(proposalRow => { const proposalId = parseInt(proposalRow.id.split('-')[1], 10); @@ -274,8 +276,9 @@ const matchesReviews = reviewFilterValue === 'all' || proposalData.numOfVotes === parseInt(reviewFilterValue, 10); const matchesStatus = visibleStatuses.includes(proposalData.originalStatus); const matchesType = visibleTypes.includes(proposalData.submissionType); + const matchesSpeaker = !speakerFilter || proposalData.speakerName.toLowerCase().includes(speakerFilter); - if (matchesReviews && matchesStatus && matchesType) { + if (matchesReviews && matchesStatus && matchesType && matchesSpeaker) { proposalRow.classList.remove('hidden'); } else { proposalRow.classList.add('hidden'); @@ -286,6 +289,7 @@ filterWithReviewsSelect.addEventListener('change', applyFilters); filterByStatusInputs.forEach(input => input.addEventListener('change', applyFilters)); filterByTypeInputs.forEach(input => input.addEventListener('change', applyFilters)); + filterBySpeakerInput.addEventListener('input', applyFilters); }); const updateBottomBarUI = () => { @@ -405,6 +409,10 @@

Show proposals with pending status:

{% endfor %} +
+

Filter by speaker name:

+ +

Show proposals of type:

@@ -464,6 +472,7 @@

Show proposals of type:

languages: [{% for language in item.languages.all %}"{{language.code}}",{% endfor %}], numOfVotes: {{item.userreview_set.count}}, submissionType: "{{ item.type.name }}", + speakerName: "{{ item.speaker.fullname|escapejs }}", }; From 7b2d4c0b44080d49cde4d5430669eefebc577cf6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:32:15 +0000 Subject: [PATCH 2/4] Make speaker name clickable to filter by name Clicking a speaker's name in the proposal row now sets the speaker name filter input and triggers filtering, scrolling the filter into view. Co-authored-by: Marco Acierno --- .../reviews/templates/proposals-recap.html | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/backend/reviews/templates/proposals-recap.html b/backend/reviews/templates/proposals-recap.html index e4d94242a5..af1b25692c 100644 --- a/backend/reviews/templates/proposals-recap.html +++ b/backend/reviews/templates/proposals-recap.html @@ -162,6 +162,16 @@ margin-left: 10px; } + .speaker-name-link { + cursor: pointer; + text-decoration: underline; + color: var(--link-fg, #417690); + } + + .speaker-name-link:hover { + color: var(--link-hover-color, #036); + } + tr:nth-of-type(odd) { background-color: var(--body-bg); } @@ -357,6 +367,14 @@ ); }; + // Filter by speaker name (called when clicking a speaker name link) + const filterBySpeakerName = (name) => { + const input = document.querySelector('#filter-by-speaker'); + input.value = name; + input.dispatchEvent(new Event('input')); + input.scrollIntoView({ behavior: 'smooth', block: 'center' }); + }; + // Toggle bottom bar visibility const toggleBottomBar = () => { const bottomBar = document.querySelector('.reviews-bottom-bar'); @@ -503,7 +521,7 @@

Show proposals of type:

{% with speaker_id=item.speaker_id|stringformat:"i" %}
  • Speaker Name - {{ item.speaker.fullname }} + {{ item.speaker.fullname }}
  • Speaker Country From b4ee3883f4afec57f65acf0c7d2fa5138beecb12 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:37:50 +0000 Subject: [PATCH 3/4] Add clear filter buttons for speaker name filter Add a clear button next to the speaker name filter input and next to each speaker name in proposal rows when the filter is active. Both buttons clear the filter and hide themselves when no filter is applied. Co-authored-by: Marco Acierno --- .../reviews/templates/proposals-recap.html | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/backend/reviews/templates/proposals-recap.html b/backend/reviews/templates/proposals-recap.html index af1b25692c..b1dbfb7bf5 100644 --- a/backend/reviews/templates/proposals-recap.html +++ b/backend/reviews/templates/proposals-recap.html @@ -172,6 +172,24 @@ color: var(--link-hover-color, #036); } + .clear-filter-btn { + background: none; + border: 1px solid #ccc; + border-radius: 3px; + cursor: pointer; + padding: 2px 8px; + font-size: 12px; + color: #666; + margin-left: 6px; + vertical-align: middle; + } + + .clear-filter-btn:hover { + background-color: #eee; + border-color: #999; + color: #333; + } + tr:nth-of-type(odd) { background-color: var(--body-bg); } @@ -299,7 +317,14 @@ filterWithReviewsSelect.addEventListener('change', applyFilters); filterByStatusInputs.forEach(input => input.addEventListener('change', applyFilters)); filterByTypeInputs.forEach(input => input.addEventListener('change', applyFilters)); - filterBySpeakerInput.addEventListener('input', applyFilters); + filterBySpeakerInput.addEventListener('input', () => { + applyFilters(); + const hasFilter = filterBySpeakerInput.value.trim() !== ''; + document.getElementById('clear-speaker-filter').style.display = hasFilter ? 'inline' : 'none'; + document.querySelectorAll('.speaker-row-clear-btn').forEach(btn => { + btn.style.display = hasFilter ? 'inline' : 'none'; + }); + }); }); const updateBottomBarUI = () => { @@ -375,6 +400,13 @@ input.scrollIntoView({ behavior: 'smooth', block: 'center' }); }; + // Clear speaker name filter + const clearSpeakerFilter = () => { + const input = document.querySelector('#filter-by-speaker'); + input.value = ''; + input.dispatchEvent(new Event('input')); + }; + // Toggle bottom bar visibility const toggleBottomBar = () => { const bottomBar = document.querySelector('.reviews-bottom-bar'); @@ -429,7 +461,10 @@

    Show proposals with pending status:

  • Filter by speaker name:

    - +
    + + +

    Show proposals of type:

    @@ -522,6 +557,7 @@

    Show proposals of type:

  • Speaker Name {{ item.speaker.fullname }} +
  • Speaker Country From 5f3010b68171a64be4e93d3cfcbf39a90ae06573 Mon Sep 17 00:00:00 2001 From: Marco Acierno Date: Fri, 30 Jan 2026 17:42:17 +0100 Subject: [PATCH 4/4] flxe --- backend/reviews/templates/proposals-recap.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/reviews/templates/proposals-recap.html b/backend/reviews/templates/proposals-recap.html index b1dbfb7bf5..184a99d9df 100644 --- a/backend/reviews/templates/proposals-recap.html +++ b/backend/reviews/templates/proposals-recap.html @@ -461,8 +461,8 @@

    Show proposals with pending status:

  • Filter by speaker name:

    -
    - +
    +