Skip to content

Commit c9350a9

Browse files
feat: Add submission type filter to proposals review recap
Add the ability to filter proposals by submission type (talk/workshop) in the review recap screen. This includes: - Add submission_types to the template context in admin.py - Add filter UI with checkboxes for each submission type - Store typeId in JavaScript data for each submission - Unify all filters (reviews count, status, type) into a single applyFilters function for combined filtering Closes #4537 Co-authored-by: Marco Acierno <marcoacierno@users.noreply.github.com>
1 parent f74c682 commit c9350a9

2 files changed

Lines changed: 50 additions & 32 deletions

File tree

backend/reviews/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from grants.models import Grant, GrantReimbursement, GrantReimbursementCategory
3434
from participants.models import Participant
3535
from reviews.models import AvailableScoreOption, ReviewSession, UserReview
36-
from submissions.models import Submission, SubmissionTag
36+
from submissions.models import Submission, SubmissionTag, SubmissionType
3737
from users.admin_mixins import ConferencePermissionMixin
3838
from users.models import User
3939

@@ -602,6 +602,7 @@ def _review_proposals_recap_view(self, request, review_session):
602602
grants=grants,
603603
review_session_id=review_session_id,
604604
audience_levels=conference.audience_levels.all(),
605+
submission_types=SubmissionType.objects.all(),
605606
review_session_repr=str(review_session),
606607
all_statuses=[choice for choice in Submission.STATUS],
607608
title="Recap",

backend/reviews/templates/proposals-recap.html

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -205,56 +205,61 @@
205205
});
206206

207207
const filterWithReviewsSelect = document.querySelector('#filter-with-n-reviews');
208-
filterWithReviewsSelect.addEventListener('change', e => {
209-
e.preventDefault();
208+
const filterByStatusInputs = [...document.querySelectorAll('input[name="filter-by-status"]')];
209+
const filterByTypeInputs = [...document.querySelectorAll('input[name="filter-by-type"]')];
210+
211+
const applyFilters = () => {
212+
const reviewsFilterValue = filterWithReviewsSelect.value;
210213

211-
const filterValue = parseInt(e.target.value, 10);
214+
const visibleStatuses = filterByStatusInputs.filter(
215+
input => input.checked
216+
).map(
217+
input => input.value
218+
);
219+
220+
const visibleTypes = filterByTypeInputs.filter(
221+
input => input.checked
222+
).map(
223+
input => parseInt(input.value, 10)
224+
);
212225

213226
document.querySelectorAll('.proposal-item').forEach(
214227
proposalRow => {
215-
if (e.target.value === 'all') {
216-
proposalRow.classList.remove('hidden')
217-
return;
218-
}
219-
220228
const proposalId = parseInt(proposalRow.id.split('-')[1], 10);
221229
const proposalData = submissionsById[proposalId];
222230

223-
const numOfVotes = proposalData.numOfVotes;
224-
if (numOfVotes === filterValue) {
231+
const reviewsMatch = reviewsFilterValue === 'all' || proposalData.numOfVotes === parseInt(reviewsFilterValue, 10);
232+
const statusMatch = visibleStatuses.includes(proposalData.originalStatus);
233+
const typeMatch = visibleTypes.includes(proposalData.typeId);
234+
235+
if (reviewsMatch && statusMatch && typeMatch) {
225236
proposalRow.classList.remove('hidden')
226237
} else {
227238
proposalRow.classList.add('hidden')
228239
}
229240
}
230-
)
241+
);
242+
};
243+
244+
filterWithReviewsSelect.addEventListener('change', e => {
245+
e.preventDefault();
246+
applyFilters();
231247
});
232248

233-
const filterByStatusInputs = [...document.querySelectorAll('input[name="filter-by-status"]')];
234249
filterByStatusInputs.forEach(
235250
filterByStatusInput => {
236251
filterByStatusInput.addEventListener('change', e => {
237252
e.preventDefault();
253+
applyFilters();
254+
});
255+
}
256+
);
238257

239-
const filterValue = e.target.value;
240-
const visibleStatuses = filterByStatusInputs.filter(
241-
input => input.checked
242-
).map(
243-
input => input.value
244-
);
245-
246-
document.querySelectorAll('.proposal-item').forEach(
247-
proposalRow => {
248-
const proposalId = parseInt(proposalRow.id.split('-')[1], 10);
249-
const proposalData = submissionsById[proposalId];
250-
251-
if (visibleStatuses.includes(proposalData.originalStatus)) {
252-
proposalRow.classList.remove('hidden')
253-
} else {
254-
proposalRow.classList.add('hidden')
255-
}
256-
}
257-
);
258+
filterByTypeInputs.forEach(
259+
filterByTypeInput => {
260+
filterByTypeInput.addEventListener('change', e => {
261+
e.preventDefault();
262+
applyFilters();
258263
});
259264
}
260265
);
@@ -352,6 +357,17 @@ <h3>Show proposals with pending status:</h3>
352357
{% endfor %}
353358
</div>
354359
</div>
360+
<div class="opt-filter">
361+
<h3>Show proposals with type:</h3>
362+
<div>
363+
{% for submission_type in submission_types %}
364+
<label>
365+
<input checked type="checkbox" name="filter-by-type" value="{{ submission_type.id }}">
366+
<span>{{ submission_type.name }}</span>
367+
</label>
368+
{% endfor %}
369+
</div>
370+
</div>
355371
</div>
356372
<div class="module filtered" id="changelist">
357373
<div class="changelist-form-container">
@@ -399,6 +415,7 @@ <h3>Show proposals with pending status:</h3>
399415
audienceLevel: {{ item.audience_level.id }},
400416
languages: [{% for language in item.languages.all %}"{{language.code}}",{% endfor %}],
401417
numOfVotes: {{item.userreview_set.count}},
418+
typeId: {{ item.type.id }},
402419
};
403420
</script>
404421
<tr class="proposal-item" id="submission-{{item.id}}" data-original-status="{{ item.current_or_pending_status }}">

0 commit comments

Comments
 (0)