diff --git a/scipost_django/colleges/forms.py b/scipost_django/colleges/forms.py index 01a1752828d144e6d0a0703598d1168fc5e6b20a..10b0dd99a07489c32013764ed60295e168705c7b 100644 --- a/scipost_django/colleges/forms.py +++ b/scipost_django/colleges/forms.py @@ -534,11 +534,8 @@ class FellowshipNominationCommentForm(forms.ModelForm): placeholder="Add a comment (visible to EdAdmin and all Fellows)", rows=2, ), - css_class="col-lg-10", - ), - Div( - ButtonHolder(Submit("submit", "Add comment")), css_class="col-lg-2" ), + Div(ButtonHolder(Submit("submit", "Add comment"))), css_class="row", ), ) diff --git a/scipost_django/colleges/management/commands/create_nomination_voting_rounds.py b/scipost_django/colleges/management/commands/create_nomination_voting_rounds.py index 1021ad0c02850e1cad013964c79deca1ae367ecb..04b93e92a903f2b6c954dbda4aac8d4716ca3856 100644 --- a/scipost_django/colleges/management/commands/create_nomination_voting_rounds.py +++ b/scipost_django/colleges/management/commands/create_nomination_voting_rounds.py @@ -43,3 +43,31 @@ class Command(BaseCommand): .senior() .filter(college=nomination.college) ) + voting_round.save() + + if voting_round.eligible_to_vote.count() <= 5: + self.stdout.write( + self.style.ERROR( + "Only {nr_eligible_voters} eligible voters for {first_name} {last_name}, cannot create round.".format( + first_name=nomination.profile.first_name, + last_name=nomination.profile.last_name, + nr_eligible_voters=voting_round.eligible_to_vote.count(), + ) + ) + ) + voting_round.delete() + else: + self.stdout.write( + self.style.SUCCESS( + "Created voting round for {first_name} {last_name} with {nr_eligible_voters} eligible voters.".format( + first_name=nomination.profile.first_name, + last_name=nomination.profile.last_name, + nr_eligible_voters=voting_round.eligible_to_vote.count(), + ) + ) + ) + + if len(nominations) == 0: + self.stdout.write( + self.style.ERROR(f"No nominations found needing handling.") + ) diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_comments.html b/scipost_django/colleges/templates/colleges/_hx_nomination_comments.html index 4534351a8f395c00177f9297a9fe34bba552517d..010888e146f9839c0c870a05a095c35b0629a363 100644 --- a/scipost_django/colleges/templates/colleges/_hx_nomination_comments.html +++ b/scipost_django/colleges/templates/colleges/_hx_nomination_comments.html @@ -1,20 +1,18 @@ {% load crispy_forms_tags %} {% load automarkup %} + {% for comment in nomination.comments.all %} <details class="m-2 border" open> <summary class="bg-light p-2">{{ comment.by }} on {{ comment.on }}</summary> - <div class="m-2"> - {% automarkup comment.text %} - </div> + <div class="m-2">{% automarkup comment.text %}</div> </details> {% empty %} - <p>No comments have been received</p> + <p class="m-2">No comments have been received.</p> {% endfor %} <div class="m-2 mt-4"> <form hx-post="{% url 'colleges:_hx_nomination_comments' nomination_id=nomination.id %}" - hx-target="#nomination-{{ nomination.id }}-comments" - > + hx-target="#nomination-{{ nomination.id }}-comments"> {% crispy form %} </form> </div> diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_li.html b/scipost_django/colleges/templates/colleges/_hx_nomination_li.html index 66b4bb52a306265d35e95366d4b8a352fefee7a6..20f0263881830b690e31d7a871a0aaa353916e40 100644 --- a/scipost_django/colleges/templates/colleges/_hx_nomination_li.html +++ b/scipost_django/colleges/templates/colleges/_hx_nomination_li.html @@ -1,27 +1,56 @@ -<div class="border border-dark"> +<div class="my-2 border border-secondary"> <details id="nomination-{{ nomination.id }}-li-details"> - <summary class="bg-light p-2"> - {{ nomination.profile }} - <span class="float-end"> - {{ nomination.college }} -  {{ nomination.nominated_on|date:"Y-m-d" }} - <span class="ms-4">Outcome:</span> - {% if nomination.decision %} - {{ nomination.decision.get_outcome_display }} - {% else %} - pending - {% endif %} - {% if nomination.fellowship and nomination.fellowship.is_active %} -  <span class="p-2 bg-success text-white">Fellow</span> - {% endif %} - </span> + <summary class="bg-light p-2 list-triangle container-fluid d-flex"> + + <div class="row mb-0 w-100"> + + <div class="col-12 col-sm"> + <div class="fs-6">{{ nomination.profile }}</div> + <div class="d-none d-md-block">(click for details)</div> + </div> + + {% if nomination.fellowship and nomination.fellowship.is_active %} + <div class="d-none d-md-flex col-auto bg-success text-white my-auto py-1"> + Already + <br /> + Fellow + </div> + {% endif %} + + <div class="col-12 col-sm-auto"> + <div> + <span>Editorial College:</span><span> {{ nomination.college.name }}</span> + </div> + <div> + <span>Nominated on:</span><span> {{ nomination.nominated_on|date:"Y-m-d" }}</span> + </div> + </div> + + <div class="col-12 col-sm-auto"> + <div> + <span>Decision:</span> + + {% if nomination.decision.outcome == "elected" %} + <span class="badge bg-success">{{ nomination.decision.get_outcome_display }}</span> + {% elif nomination.decision.outcome == "notelected" %} + <span class="badge bg-danger">{{ nomination.decision.get_outcome_display }}</span> + {% else %} + <span class="badge bg-warning">Pending</span> + {% endif %} + + </div> + + <div> + <span>Deadline: </span><span>{{ round.voting_deadline|date:"Y-m-d" }}</span> + </div> + </div> + </div> + </summary> <div id="nomination-{{ nomination.id }}-li-contents" - hx-get="{% url 'colleges:_hx_nomination_li_contents' nomination_id=nomination.id %}" - hx-trigger="toggle from:#nomination-{{ nomination.id }}-li-details" - hx-target="this" - > - </div> + hx-get="{% url 'colleges:_hx_nomination_li_contents' nomination_id=nomination.id %}" + hx-trigger="toggle from:#nomination-{{ nomination.id }}-li-details" + hx-target="this"></div> </details> </div> diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html b/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html index 09273f0b9831677ab1402711e5befb8e3b13fcd9..b5e521051282722348740ef9a4bd718c7a31d720 100644 --- a/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html +++ b/scipost_django/colleges/templates/colleges/_hx_nomination_li_contents.html @@ -1,223 +1,187 @@ -<div class="p-2"> - <p>Nominated by {{ nomination.nominated_by }} on {{ nomination.nominated_on|date:"Y-m-d" }}</p> - <div class="row"> - <div class="col"> - <div class="card m-2 mt-4"> - <div class="card-header"> - Details - </div> - <div class="card-body"> - <table class="table"> - <tr> - <td>Field</td><td>{{ nomination.profile.acad_field }}</td> - </tr> - <tr> - <td>Specialties</td> - <td> - {% for specialty in nomination.profile.specialties.all %} - <div class="single d-inline" data-specialty="{{ specialty }}" data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ specialty }}">{{ specialty.code }}</div> - {% empty %} - undefined - {% endfor %} - </td> - </tr> - <tr> - <td>ORCID ID</td> - <td> - {% if nomination.profile.orcid_id %} - <a href="//orcid.org/{{ nomination.profile.orcid_id }}" target="_blank" rel="noopener">{{ nomination.profile.orcid_id }}</a> - {% else %} - unknown - {% endif %} - </td> - </tr> - <tr><td>Webpage</td> - <td> - {% if nomination.profile.webpage %} - <a href="{{ nomination.profile.webpage }}" target="_blank" rel="noopener">{{ nomination.profile.webpage }}</a> - {% else %} - unknown - {% endif %} - </td> - </tr> - </table> - </div> +<div class="p-4"> + <div class="row mb-0"> + <div class="col-12 col-md mb-3"> + <div class="card"> + <div class="card-header">Details</div> + <div class="card-body p-0"> + <table class="table mb-0"> + <tr> + <td>Field</td> + <td>{{ nomination.profile.acad_field }}</td> + </tr> + <tr> + <td>Specialties</td> + <td> + + {% for specialty in nomination.profile.specialties.all %} + <div class="single d-inline" + data-specialty="{{ specialty }}" + data-bs-toggle="tooltip" + data-bs-placement="bottom" + title="{{ specialty }}">{{ specialty.code }}</div> + {% empty %} + undefined + {% endfor %} + + </td> + </tr> + <tr> + <td>ORCID ID</td> + <td> + + {% if nomination.profile.orcid_id %} + <a href="//orcid.org/{{ nomination.profile.orcid_id }}" + target="_blank" + rel="noopener">{{ nomination.profile.orcid_id }}</a> + {% else %} + unknown + {% endif %} + + </td> + </tr> + <tr> + <td>Webpage</td> + <td> + + {% if nomination.profile.webpage %} + <a href="{{ nomination.profile.webpage }}" + target="_blank" + rel="noopener">{{ nomination.profile.webpage }}</a> + {% else %} + unknown + {% endif %} + + </td> + </tr> + </table> + </div> </div> </div> - <div class="col"> - <div class="card m-2 mt-4"> - <div class="card-header"> - Publications in SciPost Journals - </div> - <div class="card-body"> - <ul> - {% for pub in nomination.profile.publications.all %} - <li><a href="{{ pub.get_absolute_url }}">{{ pub.citation }}</a></li> - {% empty %} - <li>No Publication found</li> - {% endfor %} - </ul> - </div> + <div class="col-12 col-md mb-3"> + <div class="card"> + <div class="card-header">Publications in SciPost Journals</div> + <div class="card-body"> + <ul> + + {% for pub in nomination.profile.publications.all %} + <li> + <a href="{{ pub.get_absolute_url }}">{{ pub.citation }}</a> + </li> + {% empty %} + <li>No Publication found</li> + {% endfor %} + + </ul> + </div> </div> </div> </div> - <table class="table"> - <tr> - <td>Affiliations</td> - <td> - {% include 'profiles/_affiliations_table.html' with profile=nomination.profile actions=False %}</td> - </tr> - </table> - - <hr> - - {% if "edadmin" in user_roles or "active_senior_fellow" in user_roles %} - <details class="m-2 mt-4 border border-danger"> - <summary class="p-2 bg-light">Events</summary> - {% include 'colleges/_nomination_events_table.html' with nomination=nomination %} - </details> - {% endif %} - - <div class="card m-2 mt-4"> - <div class="card-header"> - Comments - </div> - <div class="card-body"> - {% if nomination.nominator_comments %} - <div class="row"> - <div class="col-lg-2"> - Nominator comments: - </div> - <div class="col-lg-10"> - <em>{{ nomination.nominator_comments }}</em> - </div> - </div> - {% endif %} - - <div id="nomination-{{ nomination.id }}-comments" - hx-get="{% url 'colleges:_hx_nomination_comments' nomination_id=nomination.id %}" - hx-trigger="revealed" - hx-target="this" - > + + <div class="row"> + <div class="col"> + <div class="card"> + <div class="card-header">Affiliations</div> + <div class="card-body p-0"> + {% include 'profiles/_affiliations_table.html' with profile=nomination.profile actions=False %} + </div> </div> </div> </div> + + <div class="row mb-0"> - {% with ongoing_round=nomination.ongoing_voting_round latest_round=nomination.voting_rounds.first %} - {% if ongoing_round %} - <div class="card m-2 mt-4"> - <div class="card-header"> - Ongoing voting round <em>(voting deadline: {{ ongoing_round.voting_deadline }})</em> - </div> - <div class="card-body"> - {% if session_fellowship and session_fellowship in ongoing_round.eligible_to_vote.all %} - <p>You are eligible to vote {{ include_vote_buttons }}</p> - <p><strong>Please go up to the main Vote dropdown to cast your vote</strong></p> - {% else %} - <p>You are not called upon to vote in this round.</p> - {% endif %} - </div> - </div> - {% elif latest_round %} - <div class="card m-2 mt-4"> - <div class="card-header"> - {{ latest_round }} - </div> - <div class="card-body"> - {% if session_fellowship and session_fellowship in latest_round.eligible_to_vote.all %} - {% include "colleges/_voting_results_box.html" with voting_round=latest_round %} - {% else %} - <p>You were not called upon to vote in this round.</p> - {% endif %} - </div> + {% if "edadmin" in user_roles or "active_senior_fellow" in user_roles %} + <div class="col-12 col-md mb-3"> + <details class="border"> + <summary class="p-2 bg-light list-triangle">Events</summary> + {% include 'colleges/_nomination_events_table.html' with nomination=nomination %} + </details> </div> {% endif %} - {% endwith %} - {% if "edadmin" in user_roles %} - <div class="border border-danger m-2 p-2"> - <strong class="text-danger">Editorial Administration</strong> - <h3>Voting rounds</h3> - {% for round in nomination.voting_rounds.all %} - <div class="card m-2 mt-4"> - <div class="card-header"> - {{ round }} - </div> - <div class="card-body"> - <div class="row"> - <div class="col-lg-6"> - <h4>Eligible to vote</h4> - <ul> - {% for voter in round.eligible_to_vote.all %} - <li>{{ voter }}</li> - {% empty %} - <li>None</li> - {% endfor %} - </ul> - </div> - <div class="col-lg-6"> - <h4>Results</h4> - {% include "colleges/_voting_results_box.html" with voting_round=round %} - <table class="table m-2"> - <tr> - <th>Agree</th> - <td> - <ul class="list-unstyled"> - {% for vote in round.votes.agree %} - <li>{{ vote.fellow }}</li> - {% empty %} - <li>None</li> - {% endfor %} - </ul> - </td> - </tr> - <tr> - <th>Abstain</th> - <td> - <ul class="list-unstyled"> - {% for vote in round.votes.abstain %} - <li>{{ vote.fellow }}</li> - {% empty %} - <li>None</li> - {% endfor %} - </ul> - </td> - </tr> - <tr> - <th>Disagree</th> - <td> - <ul class="list-unstyled"> - {% for vote in round.votes.disagree %} - <li>{{ vote.fellow }}</li> - {% empty %} - <li>None</li> - {% endfor %} - </ul> - </td> - </tr> - </table> - </div> - </div> - </div> - </div> - {% empty %} - <div>No voting round</div> - {% endfor %} - - <div class="card m-2 mt-4"> - <div class="card-header"> - Decision - </div> - <div class="card-body"> - <div id="nomination-{{ nomination.id }}-decision" - hx-get="{% url 'colleges:_hx_nomination_decision' nomination_id=nomination.id %}" - hx-trigger="revealed" - hx-target="this" - </div> - </div> + <div class="col-12 col-md mb-3"> + <details class="border"> + <summary class="p-2 bg-light list-triangle">Comments</summary> + + <div class="p-3"> + + {% if nomination.nominator_comments %} + <div class="row"> + <div class="fs-6">Nominator comments:</div> + <div> + <em>{{ nomination.nominator_comments }}</em> + </div> + </div> + <hr class="text-muted" /> + {% endif %} + + + <div id="nomination-{{ nomination.id }}-comments" + hx-get="{% url 'colleges:_hx_nomination_comments' nomination_id=nomination.id %}" + hx-trigger="revealed" + hx-target="this"></div> + </div> + </details> + </div> + </div> + + + {% with round=nomination.voting_rounds.first %} + + <div class="row"> + <div class="col"> + <div class="card"> + <div class="card-header">Voting Round Details</div> + <div class="card-body"> + + {% if session_fellowship and session_fellowship in round.eligible_to_vote.all or "edadmin" in user_roles %} + + {% if round.is_open and session_fellowship in round.eligible_to_vote.all %} + <div id="nomination-{{ round.nomination.id }}-vote" + hx-get="{% url 'colleges:_hx_nomination_vote' voting_round_id=round.id %}" + hx-trigger="revealed" + hx-target="this"></div> + {% else %} + {% include "colleges/_hx_voting_round_results.html" with voting_round=round %} + {% endif %} + + {% else %} + <p>You are not called upon to vote in this round.</p> + {% endif %} + + </div> + </div> </div> </div> - {% endif %} -</div> + {% endwith %} + + + {% if "edadmin" in user_roles %} + <div class="row"> + <div class="col"> + <details class="border"> + <summary class="p-2 bg-light list-triangle">All voting rounds</summary> + + <div class="p-3"> + + {% for round in nomination.voting_rounds.all %} + <details> + <summary class="list-triangle"> + #{{ forloop.counter0|add:1 }} from {{ round.voting_opens|date:"Y-m-d" }} to {{ round.voting_deadline|date:"Y-m-d" }} + </summary> + + {% include "colleges/_hx_voting_round_results.html" with voting_round=round %} + + </details> + {% empty %} + <div>No voting round</div> + {% endfor %} + + </details> + </div> + </div> + {% endif %} + + </div> diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_voter_table.html b/scipost_django/colleges/templates/colleges/_hx_nomination_voter_table.html new file mode 100644 index 0000000000000000000000000000000000000000..e43b1a4eccc5daf96588a6227380f95216b9ccce --- /dev/null +++ b/scipost_django/colleges/templates/colleges/_hx_nomination_voter_table.html @@ -0,0 +1,35 @@ +{% if voters %} + <table class="table"> + <thead class="table-light"> + <tr> + <th>Fellow</th> + <th>Vote</th> + <th>Voted on</th> + </tr> + </thead> + + <tbody> + + {% for voter in voters %} + <tr> + <td>{{ voter }}</td> + + {% if voter.vote.vote == "agree" %} + <td class="text-success">{{ voter.vote.get_vote_display }}</td> + {% elif voter.vote.vote == "abstain" %} + <td class="text-warning">{{ voter.vote.get_vote_display }}</td> + {% elif voter.vote.vote == "disagree" %} + <td class="text-danger">{{ voter.vote.get_vote_display }}</td> + {% else %} + <td class="text-muted">No vote</td> + {% endif %} + + <td>{{ voter.vote.on }}</td> + </tr> + {% endfor %} + + </tbody> + </table> +{% else %} + <p class="text-danger">No eligible voters found.</p> +{% endif %} diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations_invitations.html b/scipost_django/colleges/templates/colleges/_hx_nominations_invitations.html index 0b9771d42358f9ae2dfc18ef4e4841716a0b4a90..dda5c98a5cd0c57bd109aba03e7cab1a452cc9f0 100644 --- a/scipost_django/colleges/templates/colleges/_hx_nominations_invitations.html +++ b/scipost_django/colleges/templates/colleges/_hx_nominations_invitations.html @@ -2,8 +2,7 @@ {% for invitation in invitations.all %} <details id="invitation-{{ invitation.id }}-details" - class="m-2 mt-4 border border-2" - > + class="my-2 border border-2"> <summary class="bg-light p-2">{{ invitation }}</summary> <details class="m-2 mt-4 border"> <summary class="p-2 bg-light">Events for this nomination</summary> @@ -12,30 +11,46 @@ <div class="p-2"> <h4>Checklist</h4> <ul> - {% if not invitation.nomination.profile.contributor %} - <li class="text-danger">N.B.: this nominee is not yet registered as a Contributor</li> - {% else %} - <li><span class="text-success">{% include 'bi/check-square-fill.html' %}</span> This nominee has a Contributor account</li> - {% endif %} - {% if selected == 'notyetinvited' %} - <li> - For named or elected, but not yet invited: - <a class="btn btn-primary" href="{% url 'colleges:fellowship_invitation_email_initial' pk=invitation.id %}">prepare and send initial email</a> - </li> - {% elif selected == 'accepted' %} - <li>Accepted to serve as Fellow but not currently active in a College? <a href="{% url 'colleges:fellowship_create' contributor_id=invitation.nomination.profile.contributor.id %}" target="_blank">Set up a Fellowship</a></li> - {% endif %} + + {% if not invitation.nomination.profile.contributor %} + + <li class="text-danger">N.B.: this nominee is not yet registered as a Contributor</li> + + {% else %} + + <li> + <span class="text-success">{% include 'bi/check-square-fill.html' %}</span> This nominee has a Contributor account + </li> + + {% endif %} + + {% if selected == 'notyetinvited' %} + + <li> + For named or elected, but not yet invited: + <a class="btn btn-primary" + href="{% url 'colleges:fellowship_invitation_email_initial' pk=invitation.id %}">prepare and send initial email</a> + + </li> + + {% elif selected == 'accepted' %} + + <li> + Accepted to serve as Fellow but not currently active in a College? <a href="{% url 'colleges:fellowship_create' contributor_id=invitation.nomination.profile.contributor.id %}" + target="_blank">Set up a Fellowship</a> + </li> + + {% endif %} + </ul> - <hr> + <hr /> <h4>Update the response to this invitation:</h4> <div id="invitation-{{ invitation.id }}-update-response" - hx-get="{% url 'colleges:_hx_fellowship_invitation_update_response' invitation_id=invitation.id %}" - hx-trigger="toggle from:#invitation-{{ invitation.id }}-details" - hx-target="this" - > - </div> + hx-get="{% url 'colleges:_hx_fellowship_invitation_update_response' invitation_id=invitation.id %}" + hx-trigger="toggle from:#invitation-{{ invitation.id }}-details" + hx-target="this"></div> </div> </details> {% empty %} diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations_needing_specialties.html b/scipost_django/colleges/templates/colleges/_hx_nominations_needing_specialties.html index 50d4c6abf771e0ad1cd8728ebe3f38401f3a038a..d12155d46e71ee9bcbd39ba4be9b5031296f1c12 100644 --- a/scipost_django/colleges/templates/colleges/_hx_nominations_needing_specialties.html +++ b/scipost_django/colleges/templates/colleges/_hx_nominations_needing_specialties.html @@ -1,19 +1,14 @@ {% for nomination in nominations_needing_specialties %} <details id="nomination-{{ nomination.id }}-specialties" - class="border border-2 mt-4" - > + class="border border-2 my-2"> <summary class="p-2 bg-light">{{ nomination }}</summary> <div id="profile-{{ nomination.profile.id }}-specialties" - class="p-2 mt-2" - hx-get="{% url 'profiles:_hx_profile_specialties' profile_id=nomination.profile.id %}" - hx-trigger="toggle from:#nomination-{{ nomination.id }}-specialties" - > - </div> + class="p-2 mt-2" + hx-get="{% url 'profiles:_hx_profile_specialties' profile_id=nomination.profile.id %}" + hx-trigger="toggle from:#nomination-{{ nomination.id }}-specialties"></div> <button class="btn btn-success text-white m-2" - hx-get="{% url 'colleges:_hx_nominations_needing_specialties' %}" - hx-target="#nominations_needing_specialties"> - Done - </button> + hx-get="{% url 'colleges:_hx_nominations_needing_specialties' %}" + hx-target="#nominations_needing_specialties">Done</button> </details> {% empty %} <p>All nomination profiles have at least one specialty.</p> diff --git a/scipost_django/colleges/templates/colleges/_hx_voting_round_results.html b/scipost_django/colleges/templates/colleges/_hx_voting_round_results.html new file mode 100644 index 0000000000000000000000000000000000000000..646a4a9f4f5fbcd08b38ba82a2072f4f746b6d1c --- /dev/null +++ b/scipost_django/colleges/templates/colleges/_hx_voting_round_results.html @@ -0,0 +1,42 @@ +<div class="px-3"> + + + {% if "edadmin" in user_roles %} + <h3>Votes</h3> + <div id="nomination-{{ nomination.id }}-round-{{ voting_round.id }}-votes" + hx-get="{% url 'colleges:_hx_nomination_voter_table' round_id=voting_round.id %}" + hx-trigger="revealed" + hx-target="this"></div> + {% endif %} + + <div class="row mb-0"> + <div class="col"> + <h3>Decision</h3> + + {% if voting_round.decision.outcome == 'elected' %} + <div class="badge fs-4 ms-2 bg-success">{{ voting_round.decision.get_outcome_display }}</div> + {% elif voting_round.decision.outcome == 'notelected' %} + <div class="badge fs-4 ms-2 bg-danger">{{ voting_round.decision.get_outcome_display }}</div> + {% else %} + + {% if "edadmin" in user_roles %} + + {% if not voting_round.is_open %} + <div id="nomination-{{ nomination.id }}-decision_form" + hx-get="{% url 'colleges:_hx_nomination_decision_form' round_id=voting_round.id %}" + hx-trigger="revealed" + hx-target="this"></div> + {% else %} + <p class="text-warning">The voting round is still open. You many not draft a decision yet.</p> + {% endif %} + + {% else %} + <p class="text-warning">No decision has been formulated yet.</p> + {% endif %} + + {% endif %} + + </div> + <div class="col">{% include "colleges/_voting_results_box.html" with voting_round=voting_round %}</div> + </div> +</div> diff --git a/scipost_django/colleges/templates/colleges/_hx_voting_rounds.html b/scipost_django/colleges/templates/colleges/_hx_voting_rounds.html index a472a42bf9fc834d2e7b3a69595384e3549ca23f..710a57c302f2f4c64cbb055211e62c59695fc1c5 100644 --- a/scipost_django/colleges/templates/colleges/_hx_voting_rounds.html +++ b/scipost_django/colleges/templates/colleges/_hx_voting_rounds.html @@ -1,18 +1,10 @@ {% include 'colleges/_hx_voting_rounds_tablist.html' with selected=selected %} {% for round in voting_rounds %} - <div class="mt-4 p-2 border border-2" id="voting_round_{{ round.id }}"> + <div id="voting_round_{{ round.id }}"> {% include 'colleges/_hx_nomination_li.html' with nomination=round.nomination %} - <h3 class="mt-4">Voting deadline: {{ round.voting_deadline }}</h3> - {% if session_fellowship and session_fellowship in round.eligible_to_vote.all %} - <div id="nomination-{{ round.nomination.id }}-vote" - hx-get="{% url 'colleges:_hx_nomination_vote' voting_round_id=round.id %}" - hx-trigger="revealed" - hx-target="this" - > - </div> - {% endif %} + </div> {% empty %} <div class="p-2">No voting round found</div> diff --git a/scipost_django/colleges/templates/colleges/_nomination_events_table.html b/scipost_django/colleges/templates/colleges/_nomination_events_table.html index 366616e9443ed813565fade618cdd051417e05c7..33e0307e93caf1df6b46abf6b61fbacfc5625608 100644 --- a/scipost_django/colleges/templates/colleges/_nomination_events_table.html +++ b/scipost_django/colleges/templates/colleges/_nomination_events_table.html @@ -1,18 +1,20 @@ -<table class="table m-2"> +<table class="table mb-0"> <thead> <tr> - <th>Date and time</th> + <th>Date</th> <th>Description</th> <th>By</th> </tr> </thead> <tbody> + {% for event in nomination.events.all %} <tr> - <td>{{ event.on }}</td> - <td>{{ event.description }}</td> - <td>{{ event.by }}</td> + <td>{{ event.on }}</td> + <td>{{ event.description }}</td> + <td>{{ event.by }}</td> </tr> {% endfor %} + </tbody> </table> diff --git a/scipost_django/colleges/templates/colleges/_voting_results_box.html b/scipost_django/colleges/templates/colleges/_voting_results_box.html index 577d2c8c461aafa56bb037b96feeb5df9e0f21cd..4d3c5de6e50ffdb8a5b32200d825ef61cf03a415 100644 --- a/scipost_django/colleges/templates/colleges/_voting_results_box.html +++ b/scipost_django/colleges/templates/colleges/_voting_results_box.html @@ -1,9 +1,7 @@ -<div class="border border-2 p-2"> - <h3>Voting results summary</h3> - <ul class="list-inline m-2"> - <li class="list-inline-item p-2">Eligible: {{ voting_round.eligible_to_vote.count }}</li> - <li class="list-inline-item p-2 text-success">Agree: {{ voting_round.votes.agree.count }}</li> - <li class="list-inline-item p-2 text-warning">Abstain: {{ voting_round.votes.abstain.count }}</li> - <li class="list-inline-item p-2 text-danger">Disagree: {{ voting_round.votes.disagree.count }}</li> - </ul> -</div> +<h3>Summary</h3> +<ul class="list-inline m-2"> + <li class="list-inline-item p-2">Eligible: {{ voting_round.eligible_to_vote.count }}</li> + <li class="list-inline-item p-2 text-success">Agree: {{ voting_round.votes.agree.count }}</li> + <li class="list-inline-item p-2 text-warning">Abstain: {{ voting_round.votes.abstain.count }}</li> + <li class="list-inline-item p-2 text-danger">Disagree: {{ voting_round.votes.disagree.count }}</li> +</ul> diff --git a/scipost_django/colleges/templates/colleges/nominations.html b/scipost_django/colleges/templates/colleges/nominations.html index 47dc3a937191affd4c2fa88cdee24449a18346a0..bfabf3fb51cb342b6ad682ee246bbf01645681fd 100644 --- a/scipost_django/colleges/templates/colleges/nominations.html +++ b/scipost_django/colleges/templates/colleges/nominations.html @@ -1,5 +1,4 @@ {% extends 'colleges/base.html' %} - {% load user_groups %} {% load crispy_forms_tags %} @@ -9,16 +8,19 @@ <span class="breadcrumb-item">Nominations</span> {% endblock %} -{% block meta_description %}{{ block.super }} Nominations{% endblock meta_description %} -{% block pagetitle %}: Nominations{% endblock pagetitle %} +{% block meta_description %} + {{ block.super }} Nominations +{% endblock meta_description %} -{% block content %} +{% block pagetitle %} + : Nominations +{% endblock pagetitle %} +{% block content %} {% is_ed_admin request.user as is_ed_admin %} - <h1 class="highlight">Fellowship Nominations</h1> - - <p>Consult the + <p> + Consult the <a href="{% url 'submissions:monitor' %}" target="_blank">Submissions Monitor</a> page. Any <span class="text-danger">red-highlighted</span> specialty is in need of more Fellows @@ -27,150 +29,163 @@ </p> <details class="border border-warning border-2 mt-4"> - <summary class="bg-warning bg-opacity-10 p-2"> - <h2 class="ms-2">Nominate</h2> + <summary class="bg-warning bg-opacity-10 p-2 d-flex list-triangle"> + <div class="fs-5">Nominate</div> </summary> + <div class="p-2"> <div class="row"> - <div class="col-lg-6"> - <h3>Procedure</h3> - <ul> - <li>Type your search query in the search form</li> - <li>When the name you're looking for appears in the - <em>Matching profiles</em> list, double-click on it</li> - <li>The nomination form will appear below</li> - <li>Non-eligibility flags (if any) will appear</li> - <li>If eligible, fill the form in (comments are optional)</li> - <li>Submit! (the vote will be arranged by EdAdmin)</li> - </ul> - <div class="row"> - <div class="col-8"> - <form - hx-post="{% url 'profiles:_hx_profile_dynsel_list' %}" - hx-trigger="keyup delay:200ms, change" - hx-target="#profile_dynsel_results" - hx-indicator="#profile_dynsel_results-indicator" - > - <div id="profile_dynsel_form">{% crispy profile_dynsel_form %}</div> - </form> - </div> - <div class="col-2"> - <div id="nomination_form_response-indicator" class="htmx-indicator"> - <button class="btn btn-sm btn-warning" type="button" disabled> - <strong>Loading form...</strong> - <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div> - </button> - </div> - </div> - <div class="col-2"> - <div id="profile_dynsel_results-indicator" class="htmx-indicator"> - <button class="btn btn-sm btn-warning" type="button" disabled> - <strong>Loading results...</strong> - <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div> - </button> - </div> - </div> - </div> - <h3 class="mb-2">Not found?</h3> - <p>Then add to our database by <a href="{% url 'profiles:profile_create' %}" target="_blank">creating a new Profile</a> (opens in new window).</p> - </div> - <div class="col-lg-6"> - <h3>Matching profiles</h3> - <div id="profile_dynsel_results" class="border border-light m-2 p-1"></div> - </div> + + <div class="col-lg-6"> + <h3>Procedure</h3> + <ul> + <li>Type your search query in the search form</li> + <li> + When the name you're looking for appears in the + <em>Matching profiles</em> list, double-click on it + </li> + <li>The nomination form will appear below</li> + <li>Non-eligibility flags (if any) will appear</li> + <li>If eligible, fill the form in (comments are optional)</li> + <li>Submit! (the vote will be arranged by EdAdmin)</li> + </ul> + <div class="row"> + + <div class="col-8"> + <form hx-post="{% url 'profiles:_hx_profile_dynsel_list' %}" + hx-trigger="keyup delay:200ms, change" + hx-target="#profile_dynsel_results" + hx-indicator="#profile_dynsel_results-indicator"> + <div id="profile_dynsel_form">{% crispy profile_dynsel_form %}</div> + </form> + </div> + + <div class="col-2"> + <div id="nomination_form_response-indicator" class="htmx-indicator"> + <button class="btn btn-sm btn-warning" type="button" disabled> + <strong>Loading form...</strong> + <div class="spinner-grow spinner-grow-sm ms-2" + role="status" + aria-hidden="true"></div> + </button> + </div> + </div> + + <div class="col-2"> + <div id="profile_dynsel_results-indicator" class="htmx-indicator"> + <button class="btn btn-sm btn-warning" type="button" disabled> + <strong>Loading results...</strong> + <div class="spinner-grow spinner-grow-sm ms-2" + role="status" + aria-hidden="true"></div> + </button> + </div> + </div> + + </div> + + <h3 class="mb-2">Not found?</h3> + <p> + Then add to our database by <a href="{% url 'profiles:profile_create' %}" target="_blank">creating a new Profile</a> (opens in new window). + </p> + </div> + + <div class="col-lg-6"> + <h3>Matching profiles</h3> + <div id="profile_dynsel_results" class="border border-light m-2 p-1"></div> + </div> + </div> + <div id="nomination_form_response"></div> + </div> </details> {% if "edadmin" in user_roles or "active_senior_fellow" in user_roles %} <details id="ensure-specialties-details" - class="border border-danger border-2 mt-4" - > - <summary class="bg-danger bg-opacity-10 p-2"> - <h2 class="ms-2"> - <strong class="text-danger">EdAdmin/Senior Fellows</strong>: - ensure specialties in each nominee's profile</h2> + class="border border-danger border-2 mt-4"> + <summary class="bg-danger bg-opacity-10 p-2 d-flex list-triangle"> + <div class="fs-5">Ensure specialties</div> </summary> - <div class="p-2 mt-2"> - <div id="nominations_needing_specialties" - hx-get="{% url 'colleges:_hx_nominations_needing_specialties' %}" - hx-trigger="toggle from:#ensure-specialties-details" - > - </div> + + <div class="p-2"> + <div id="nominations_needing_specialties" + hx-get="{% url 'colleges:_hx_nominations_needing_specialties' %}" + hx-trigger="toggle from:#ensure-specialties-details"></div> </div> </details> {% endif %} - <details id="voting-details" - class="border border-primary border-2 mt-4" - > - <summary class="bg-primary bg-opacity-10 p-2"> - <h2 class="ms-2 text-primary">Vote{% if 'edadmin' in user_roles %} <span class="text-danger">(EdAdmin: manage voting)</span>{% endif %}</h2> - </summary> - <div class="p-2 mt-2"> - <div id="voting_tablist" - hx-get="{% url 'colleges:_hx_voting_rounds' %}?tab={% if 'edadmin' in user_roles %}ongoing{% else %}ongoing-vote_required{% endif %}" - hx-trigger="toggle from:#voting-details" - hx-target="this" - hx-swap="innerHTML" - > + <details id="voting-details" class="border border-primary border-2 mt-4"> + <summary class="bg-primary bg-opacity-10 p-2 d-flex list-triangle"> + <div class="fs-5"> + + {% if 'edadmin' not in user_roles %} + Vote + {% else %} + Manage voting + {% endif %} + </div> + </summary> + + <div class="p-2"> + <div id="voting_tablist" hx-get="{% url 'colleges:_hx_voting_rounds' %}?tab= + {% if 'edadmin' in user_roles %}ongoing{% else %}ongoing-vote_required{% endif %} + " hx-trigger="toggle from:#voting-details" hx-target="this" hx-swap="innerHTML"></div> </div> </details> {% if "edadmin" in user_roles %} - <details id="invitations-details" - class="border border-success border-2 mt-4" - > - <summary class="bg-success bg-opacity-10 p-2"> - <h2 class="ms-2"> - <strong class="text-success">EdAdmin</strong>: - (for elected) invitations</h2> + <details id="invitations-details" class="border border-success border-2 mt-4"> + <summary class="bg-success bg-opacity-10 p-2 d-flex list-triangle"> + <div class="fs-5">Manage invitations</div> </summary> + <div class="p-2 mt-2"> - <div id="invitations_tablist" - hx-get="{% url 'colleges:_hx_nominations_invitations' %}?response=notyetinvited" - hx-trigger="toggle from:#invitations-details" - hx-target="this" - hx-swap="innerHTML" - > - </div> + <div id="invitations_tablist" + hx-get="{% url 'colleges:_hx_nominations_invitations' %}?response=notyetinvited" + hx-trigger="toggle from:#invitations-details" + hx-target="this" + hx-swap="innerHTML"></div> </div> </details> {% endif %} - <details id="list-details" - class="border border-2 mt-4" - > - <summary class="bg-light p-2"> - <h2 class="ms-2">List / filter</h2> + <details id="list-details" class="border border-2 mt-4"> + <summary class="bg-light p-2 d-flex list-triangle"> + <div class="fs-5">List / filter</div> </summary> + <div class="p-2 mt-2"> - <form - hx-post="{% url 'colleges:_hx_nominations' %}" - hx-trigger="toggle from:#list-details, keyup delay:500ms, change" - hx-target="#search-nominations-results" - hx-indicator="#indicator-search" - > - <div id="search-nominations-form">{% crispy search_nominations_form %}</div> + <form hx-post="{% url 'colleges:_hx_nominations' %}" + hx-trigger="toggle from:#list-details, keyup delay:500ms, change" + hx-target="#search-nominations-results" + hx-indicator="#indicator-search"> + <div id="search-nominations-form">{% crispy search_nominations_form %}</div> </form> <div class="row"> - <div class="col"> - <h3>Nominations list</h3> - </div> - <div class="col"> - <div id="indicator-search-nominations" class="htmx-indicator"> - <button class="btn btn-sm btn-warning" type="button" disabled> - <strong>Loading...</strong> - <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div> - </button> - </div> - </div> + <div class="col"> + <h3>Nominations list</h3> + </div> + + <div class="col"> + <div id="indicator-search-nominations" class="htmx-indicator"> + <button class="btn btn-sm btn-warning" type="button" disabled> + <strong>Loading...</strong> + <div class="spinner-grow spinner-grow-sm ms-2" + role="status" + aria-hidden="true"></div> + </button> + </div> + </div> </div> - <ul id="search-nominations-results" class="list-unstyled mt-2"></ul> + + <ul id="search-nominations-results" class="list-unstyled mt-2"> + </ul> + </div> </details> - {% endblock content %} diff --git a/scipost_django/colleges/urls.py b/scipost_django/colleges/urls.py index e1195b5d3ccc043314e97ddfd8a4c2f51df0301b..11e17f1a86e27ff8634415fecb6bbb48bc5579a0 100644 --- a/scipost_django/colleges/urls.py +++ b/scipost_django/colleges/urls.py @@ -174,6 +174,11 @@ urlpatterns = [ views._hx_nomination_li_contents, name="_hx_nomination_li_contents", ), + path( + "_hx_nomination_voter_table/<int:round_id>", + views._hx_nomination_voter_table, + name="_hx_nomination_voter_table", + ), path( "_hx_nomination_comments/<int:nomination_id>", views._hx_nomination_comments, diff --git a/scipost_django/colleges/views.py b/scipost_django/colleges/views.py index c99eb44880ee65dd55ff888c9789804366158d49..7650a34b3f8d5390b809eb4a34dc2e052385b818 100644 --- a/scipost_django/colleges/views.py +++ b/scipost_django/colleges/views.py @@ -848,7 +848,7 @@ def _hx_voting_rounds(request): voting_rounds = voting_rounds.filter(eligible_to_vote=fellowship).exclude( votes__fellow=fellowship ) - if "voted" in selected: + if "-voted" in selected: voting_rounds = voting_rounds.filter(votes__fellow=fellowship) context = { "tab_choices": tab_choices, @@ -991,3 +991,18 @@ def _hx_fellowship_invitation_update_response(request, invitation_id): "colleges/_hx_nomination_invitation_update_response.html", context, ) + + +@login_required +@user_passes_test(is_edadmin) +def _hx_nomination_voter_table(request, round_id): + round = get_object_or_404(FellowshipNominationVotingRound, pk=round_id) + voters = round.eligible_to_vote.all() + + for voter in voters: + voter.vote = round.votes.filter(fellow=voter).first() + + context = { + "voters": voters, + } + return render(request, "colleges/_hx_nomination_voter_table.html", context) diff --git a/scipost_django/profiles/templates/profiles/_affiliations_table.html b/scipost_django/profiles/templates/profiles/_affiliations_table.html index dc981e2ebf9693e2be638a51921f6aa721a3be19..2900c0bb3487a03a08dd4e671575ada8427268de 100644 --- a/scipost_django/profiles/templates/profiles/_affiliations_table.html +++ b/scipost_django/profiles/templates/profiles/_affiliations_table.html @@ -1,20 +1,24 @@ -<table class="table"> - <thead class="table-light"> +<table class="table mb-0"> + <thead> <tr> <th>Organization</th> <th>Category</th> <th>From</th> <th>Until</th> - {% if actions %} - <td>Actions</td> - {% endif %} + + {% if actions %}<th>Actions</th>{% endif %} + </tr> </thead> <tbody> + {% for aff in profile.affiliations.all %} {% include 'profiles/_affiliations_table_row.html' with affiliation=aff actions=actions %} {% empty %} - <tr><td colspan="4">No Affiliation has been defined</td></tr> + <tr> + <td colspan="4">No Affiliation has been defined</td> + </tr> {% endfor %} + </tbody> </table>