Skip to content
8 changes: 8 additions & 0 deletions hypha/apply/activity/adapters/activity_feed.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ class ActivityAdapter(AdapterBase):
MESSAGES.CREATED_PROJECT: _(
'Created project with initial status of "{status}"'
),
MESSAGES.CREATED_SOW: _('Created SOW for project "{related.project}"'),
MESSAGES.EDITED_SOW: _('Edited SOW for project "{related.project}"'),
MESSAGES.CREATED_PF: _('Created project form for project "{related.project}"'),
MESSAGES.EDITED_PF: _('Edited project form for project "{related.project}"'),
MESSAGES.PROJECT_TRANSITION: "handle_project_transition",
MESSAGES.UPDATE_PROJECT_TITLE: _(
"updated the project title from {old_title} to {source.title}"
Expand Down Expand Up @@ -94,6 +98,10 @@ def extra_kwargs(self, message_type, source, sources, **kwargs):
MESSAGES.DELETE_REVIEW_OPINION,
MESSAGES.BATCH_REVIEWERS_UPDATED,
MESSAGES.APPROVE_PROJECT,
MESSAGES.CREATED_SOW,
MESSAGES.EDITED_SOW,
MESSAGES.CREATED_PF,
MESSAGES.EDITED_PF,
MESSAGES.REQUEST_PROJECT_CHANGE,
MESSAGES.SEND_FOR_APPROVAL,
MESSAGES.APPROVE_PAF,
Expand Down
4 changes: 4 additions & 0 deletions hypha/apply/activity/adapters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
MESSAGES.DELETE_REVIEW_OPINION: "review_opinion",
MESSAGES.EDIT_REVIEW: "review",
MESSAGES.CREATED_PROJECT: "submission",
MESSAGES.CREATED_SOW: "sow",
MESSAGES.EDITED_SOW: "sow",
MESSAGES.EDITED_PF: "pfp",
MESSAGES.CREATED_PF: "pfp",
MESSAGES.PROJECT_TRANSITION: "old_stage",
MESSAGES.APPROVE_PAF: "paf_approvals", # expect a list
MESSAGES.UPDATE_PROJECT_LEAD: "old_lead",
Expand Down
26 changes: 21 additions & 5 deletions hypha/apply/activity/forms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django import forms
from django.db import transaction
from django.forms.widgets import Textarea
from django.utils.translation import gettext_lazy as _
from django_file_form.forms import FileFormMixin

Expand All @@ -24,11 +25,16 @@ class CommentForm(FileFormMixin, forms.ModelForm):

class Meta:
model = Activity
fields = (
"message",
"visibility",
"assign_to",

# Fields that should only be included when the mini comment form is used
# as the mini form can be put anywhere and associated to any object.
mini_fields = (
"related_content_type",
"related_object_id",
"source_content_type",
"source_object_id",
Comment thread
wes-otf marked this conversation as resolved.
)
fields = ("message", "visibility", "assign_to", *mini_fields)
labels = {
"visibility": _("Visible to"),
"message": _("Message"),
Expand All @@ -41,9 +47,10 @@ class Meta:
widgets = {
"visibility": forms.RadioSelect(),
"message": PagedownWidget(),
**{field: forms.HiddenInput() for field in mini_fields},
}

def __init__(self, *args, user=None, has_coapplicants=False, **kwargs):
def __init__(self, *args, user=None, has_coapplicants=False, mini=False, **kwargs):
super().__init__(*args, **kwargs)
self.visibility_choices = self._meta.model.visibility_choices_for(
user, has_coapplicants
Expand All @@ -61,6 +68,15 @@ def __init__(self, *args, user=None, has_coapplicants=False, **kwargs):
if not user.is_apply_staff:
self.fields["assign_to"].widget = forms.HiddenInput()

if mini:
self.fields["message"].widget = Textarea(
attrs={"rows": 2, "placeholder": _("Write a comment...")}
)
else:
# If not mini, remove the unneeded fields from the form.
for key in self.Meta.mini_fields:
del self.fields[key]

@transaction.atomic
def save(self, commit=True):
instance = super().save(commit=True)
Expand Down
93 changes: 93 additions & 0 deletions hypha/apply/activity/migrations/0096_alter_event_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Generated by Django 5.2.17 on 2026-08-05 16:25

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("activity", "0095_alter_event_type"),
]

operations = [
migrations.AlterField(
model_name="event",
name="type",
field=models.CharField(
choices=[
("UPDATE_LEAD", "updated lead"),
("BATCH_UPDATE_LEAD", "batch updated lead"),
("EDIT_SUBMISSION", "edited submission"),
("APPLICANT_EDIT", "edited applicant"),
("NEW_SUBMISSION", "submitted new submission"),
("DRAFT_SUBMISSION", "submitted new draft submission"),
("SCREENING", "screened"),
("TRANSITION", "transitioned"),
("BATCH_TRANSITION", "batch transitioned"),
("DETERMINATION_OUTCOME", "sent determination outcome"),
("BATCH_DETERMINATION_OUTCOME", "sent batch determination outcome"),
("INVITED_TO_PROPOSAL", "invited to proposal"),
("REVIEWERS_UPDATED", "updated reviewers"),
("BATCH_REVIEWERS_UPDATED", "batch updated reviewers"),
("READY_FOR_REVIEW", "marked ready for review"),
("BATCH_READY_FOR_REVIEW", "marked batch ready for review"),
("NEW_REVIEW", "added new review"),
("COMMENT", "added comment"),
("PROPOSAL_SUBMITTED", "submitted proposal"),
("OPENED_SEALED", "opened sealed submission"),
("REVIEW_OPINION", "reviewed opinion"),
("DELETE_SUBMISSION", "deleted submission"),
("ANONYMIZE_SUBMISSION", "anonymized submission"),
("DELETE_REVIEW", "deleted review"),
("DELETE_REVIEW_OPINION", "deleted review opinion"),
("CREATED_PROJECT", "created project"),
("CREATED_SOW", "created a project SOW"),
("EDITED_SOW", "edited a project SOW"),
("CREATED_PF", "created a project form"),
("EDITED_PF", "edited a project form"),
("UPDATE_PROJECT_LEAD", "updated project lead"),
("UPDATE_PROJECT_TITLE", "updated project title"),
(
"UPDATE_PROJECT_CONTRACT_NUMBER",
"updated project contract number",
),
("EDIT_REVIEW", "edited review"),
("SEND_FOR_APPROVAL", "sent for approval"),
("APPROVE_PROJECT", "approved project"),
("ASSIGN_PAF_APPROVER", "assign project form approver"),
("APPROVE_PAF", "approved project form"),
("PROJECT_TRANSITION", "transitioned project"),
("REQUEST_PROJECT_CHANGE", "requested project change"),
("SUBMIT_CONTRACT_DOCUMENTS", "submitted contract documents"),
("UPLOAD_DOCUMENT", "uploaded document to project"),
("UPLOAD_CONTRACT", "uploaded contract to project"),
("APPROVE_CONTRACT", "approved contract"),
("CREATE_INVOICE", "created invoice for project"),
("UPDATE_INVOICE_STATUS", "updated invoice status"),
("APPROVE_INVOICE", "approve invoice"),
("DELETE_INVOICE", "deleted invoice"),
("SENT_TO_COMPLIANCE", "sent project to compliance"),
("UPDATE_INVOICE", "updated invoice"),
("SUBMIT_REPORT", "submitted report"),
("DELETE_REPORT", "deleted report"),
("SKIPPED_REPORT", "skipped report"),
("REPORT_FREQUENCY_CHANGED", "changed report frequency"),
("DISABLED_REPORTING", "disabled reporting"),
("REPORT_NOTIFY", "notified report"),
("REVIEW_REMINDER", "reminder to review"),
("BATCH_DELETE_SUBMISSION", "batch deleted submissions"),
("BATCH_ANONYMIZE_SUBMISSION", "batch anonymized submissions"),
("BATCH_ARCHIVE_SUBMISSION", "batch archive submissions"),
("BATCH_INVOICE_STATUS_UPDATE", "batch update invoice status"),
("STAFF_ACCOUNT_CREATED", "created new account"),
("STAFF_ACCOUNT_EDITED", "edited account"),
("ARCHIVE_SUBMISSION", "archived submission"),
("UNARCHIVE_SUBMISSION", "unarchived submission"),
("REMOVE_TASK", "remove task"),
("INVITE_COAPPLICANT", "invite co-applicant"),
("UPDATE_AUTHOR", "updated author"),
],
max_length=50,
verbose_name="verb",
),
),
]
4 changes: 4 additions & 0 deletions hypha/apply/activity/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class MESSAGES(TextChoices):
DELETE_REVIEW = "DELETE_REVIEW", _("deleted review")
DELETE_REVIEW_OPINION = "DELETE_REVIEW_OPINION", _("deleted review opinion")
CREATED_PROJECT = "CREATED_PROJECT", _("created project")
CREATED_SOW = "CREATED_SOW", _("created a project SOW")
EDITED_SOW = "EDITED_SOW", _("edited a project SOW")
CREATED_PF = "CREATED_PF", _("created a project form")
EDITED_PF = "EDITED_PF", _("edited a project form")
UPDATE_PROJECT_LEAD = "UPDATE_PROJECT_LEAD", _("updated project lead")
UPDATE_PROJECT_TITLE = "UPDATE_PROJECT_TITLE", _("updated project title")
UPDATE_PROJECT_CONTRACT_NUMBER = (
Expand Down
37 changes: 37 additions & 0 deletions hypha/apply/activity/templates/activity/partials/comment_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{% comment %}
Renders the sidebar comments form.

Params:
form – the CommentForm form
{% endcomment %}

{% load i18n static heroicons %}

<form hx-post="{% url 'activity:post-comment' %}" class="flex flex-col gap-2 p-2 card-body" hx-on::after-request="if(event.detail.successful) this.reset()">
<h2 class="card-title">Comment</h2>
{% csrf_token %}

{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div>
{% include "forms/includes/field.html" with field=form.message label_classes="sr-only" %}
</div>

<details class="mb-1 collapse bg-base-100 group">
<summary class="flex gap-1.5 items-center text-sm collapse-title"><span>{% trans 'Additional options' %}</span>{% heroicon_mini 'chevron-down' class="size-5 group-open:-rotate-180" %}</summary>
{# Some small modifications to django-file-form to make it fit better with the smaller modal #}
<div class="collapse-content [&_.dff-uploader]:hidden [&_.btn-upload]:w-full">
{% include "forms/includes/field.html" with field=form.visibility %}
{% include "forms/includes/field.html" with field=form.assign_to %}
{% include "forms/includes/field.html" with field=form.attachments %}
{{ form.related_content_type }}
</div>
</details>
<button
class="btn btn-primary"
type="submit"
>
{% trans "Add Comment" %}
</button>
</form>
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
{% comment %}
Renders a line item of activity including the message attached to the activity & an icon based on the message.

Params:
activity – an Activity object to render into a timeline
no_timeline - bool of should the line item be styled as a piece of a larger timeline
mini - bool that will force including only essential elements of the action item
{% endcomment %}

{% load i18n activity_tags heroicons %}

{% with activity|display_for:request.user as activity_text %}
<div class="relative h-timeline-item" id="communications#{{ activity.id }}">
<div class="{% if not no_timeline %}relative h-timeline-item{% endif %}" id="communications#{{ activity.id }}">
<div
class="flex items-center py-2 -ml-3 before:block before:absolute before:top-0 before:bottom-0 before:left-0 before:w-(--border) before:bg-base-300"
>
Expand All @@ -22,6 +31,12 @@
{% heroicon_micro "lock-closed" class="inline" aria_hidden=true size=14 %}
{% elif 'lead' in activity_text.lower or 'author' in activity_text.lower %}
{% heroicon_micro "users" class="inline" aria_hidden=true size=14 %}
{% elif 'approved by' in activity_text.lower %}
Comment thread
wes-otf marked this conversation as resolved.
{% heroicon_micro "check-circle" class="inline" aria_hidden=true size=14 %}
{% elif 'changes requested' in activity_text.lower %}
{% heroicon_micro "exclamation-circle" class="inline" aria_hidden=true size=14 %}
{% elif 'created' in activity_text.lower %}
{% heroicon_micro "folder-plus" class="inline" aria_hidden=true size=14 %}
{% else %}
{% heroicon_micro "eye" class="inline" aria_hidden=true size=15 %}
{% endif %}
Expand All @@ -39,7 +54,7 @@
{{ activity.timestamp|date:'SHORT_DATETIME_FORMAT' }}
</relative-time>
</span>
{% if not submission_title and activity|user_can_see_related:request.user %}
{% if not submission_title and activity|user_can_see_related:request.user and not mini %}
{% with url=activity.related_object.get_absolute_url %}
{% if url %}
<a href="{{ url }}" class="link">
Expand Down
Loading