Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Icf cpheapm61 customizable mgmt dashboard #1112

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions hawc/apps/mgmt/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,53 @@ class TaskAdmin(admin.ModelAdmin):
"type",
"owner",
"status",
"open",
"notes",
"due_date",
"started",
"completed",
)
list_select_related = ("study", "owner")
list_select_related = ("study", "owner", "type", "status")


@admin.register(models.TaskType)
class TaskTypeAdmin(admin.ModelAdmin):
search_fields = ("assessment__name", "assessment__id", "name")
list_display = (
"assessment",
"name",
"order",
"description",
"created",
"last_updated",
)
list_select_related = ("assessment",)


@admin.register(models.TaskStatus)
class TaskStatusAdmin(admin.ModelAdmin):
search_fields = ("assessment__name", "assessment__id", "name")
list_display = (
"assessment",
"name",
"value",
"description",
"order",
"color",
"terminal_status",
"created",
"last_updated",
)


@admin.register(models.TaskTrigger)
class TaskTriggerAdmin(admin.ModelAdmin):
search_fields = ("task_type__name", "current_status__name", "event")
list_display = (
"task_type",
"current_status",
"next_status",
"event",
"created",
"last_updated",
)
list_select_related = ("task_type", "current_status", "next_status")
23 changes: 20 additions & 3 deletions hawc/apps/mgmt/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,30 @@ class TaskStatus(models.IntegerChoices):

@classmethod
def extra_choices(cls):
return [(990, "Active"), (995, "Inactive"), *cls.choices]
return [(990, "Active"), (995, "Inactive")]

@classmethod
def filter_extra(cls, value: int) -> models.Q:
if value == 990:
return models.Q(status__in=[10, 20])
return models.Q(status__terminal_status=False)
elif value == 995:
return models.Q(status__in=[30, 40])
return models.Q(status__terminal_status=True)
else:
return models.Q(status=value)

@classmethod
def status_colors(cls, value: int):
colors = {
10: "#CFCFCF",
20: "#FFCC00",
30: "#00CC00",
40: "#CC3333",
}
return colors.get(value)


class StartTaskTriggerEvent(models.IntegerChoices):
STUDY_CREATION = 10, "Create Study"
DATA_EXTRACTION = 20, "Data Extraction"
MODIFY_ROB = 30, "Modify Study Evaluation"
COMPLETE_ROB = 40, "Complete Study Evaluation"
1 change: 0 additions & 1 deletion hawc/apps/mgmt/exports.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ def get_value_map(self):
"type_display": "type_display",
"status": "status",
"status_display": "status_display",
"open": "open",
"due_date": "due_date",
"started": "started",
"completed": "completed",
Expand Down
21 changes: 18 additions & 3 deletions hawc/apps/mgmt/filterset.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,21 @@ class TaskFilterSet(BaseFilterSet):
help_text="Data type for full-text extraction",
empty_label="- Data Type -",
)
type = df.ChoiceFilter(
type = df.ModelChoiceFilter(
queryset=models.TaskType.objects.none(),
method="filter_type",
empty_label="- Type -",
choices=constants.TaskType.choices,
)
owner = df.ModelChoiceFilter(
label="Assigned user",
queryset=HAWCUser.objects.none(),
help_text="Includes all tasks for a study where a user has at least one assignment",
empty_label="- User -",
)
# The status search filter is now dynamic. To continue displaying the 'active' and 'inactive'
# search options, it can't use the ModelChoiceFilter that 'type' now uses.
status = df.ChoiceFilter(
empty_label="- Status -",
choices=constants.TaskStatus.extra_choices(),
method="filter_status",
)
order_by = TaskOrderingFilter(
Expand All @@ -75,10 +77,23 @@ def filter_search(self, queryset, name, value):
def filter_data_type(self, queryset, name, value):
return queryset.filter(**{f"study__{value}": True})

def filter_type(self, queryset, name, value):
return queryset.filter(type=value)

def filter_status(self, queryset, name, value):
return queryset.filter(constants.TaskStatus.filter_extra(int(value)))

def get_status_choices(self, assessment):
model_choices = models.TaskStatus.objects.filter(assessment=assessment).values_list(
"id", "name"
)
extra_choices = constants.TaskStatus.extra_choices()
return list(model_choices) + extra_choices

def create_form(self):
self.filters["status"].extra.update({"choices": self.get_status_choices(self.assessment)})

form = super().create_form()
form.fields["type"].queryset = models.TaskType.objects.filter(assessment=self.assessment)
form.fields["owner"].queryset = self.assessment.pms_and_team_users()
return form
125 changes: 123 additions & 2 deletions hawc/apps/mgmt/forms.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
from crispy_forms import layout as cfl
from django import forms
from django.forms.widgets import DateInput
from django.forms.widgets import DateInput, TextInput
from django.urls import reverse

from hawc.apps.assessment.models import Assessment

from ..common.forms import BaseFormHelper
from . import models
from . import constants, models
from .actions import clone_approach


class TaskForm(forms.ModelForm):
Expand All @@ -15,6 +20,13 @@ class Meta:

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
status_names = [
(status.id, status.name)
for status in models.TaskStatus.objects.filter(
assessment=self.instance.study.assessment
)
]
self.fields["status"].widget = forms.Select(choices=status_names)
self.fields["owner"].queryset = self.instance.study.assessment.pms_and_team_users()

@property
Expand All @@ -23,3 +35,112 @@ def helper(self):
helper.form_tag = False
helper.add_row("owner", 3, "col-md-4")
return helper


class TypeForm(forms.ModelForm):
class Meta:
model = models.TaskType
fields = ("name", "order", "description")

def __init__(self, *args, **kwargs):
assessment = kwargs.pop("parent", None)
super().__init__(*args, **kwargs)
if assessment:
self.instance.assessment = assessment

@property
def helper(self):
helper = BaseFormHelper(self)
helper.form_tag = False
helper.add_row("name", 3, ["col-md-3", "col-md-3", "col-md-6"])
helper.set_textarea_height(("description",), 3)

return helper


class StatusForm(forms.ModelForm):
class Meta:
model = models.TaskStatus
fields = ("name", "order", "color", "terminal_status", "description")
widgets = {"color": TextInput(attrs={"type": "color"})}

def __init__(self, *args, **kwargs):
assessment = kwargs.pop("parent", None)
super().__init__(*args, **kwargs)
if assessment:
self.instance.assessment = assessment
self.instance.value = self.instance.order

@property
def helper(self):
helper = BaseFormHelper(self)
helper.form_tag = False
helper.add_row(
"name", 6, ["col-md-2", "col-md-2", "col-md-2", "col-md-2", "col-md-4", "col-md-0"]
)
helper.set_textarea_height(("description",), 3)

return helper


class TriggerForm(forms.ModelForm):
class Meta:
model = models.TaskTrigger
fields = ("task_type", "current_status", "next_status", "event")

def __init__(self, *args, **kwargs):
assessment = kwargs.pop("parent", None)
super().__init__(*args, **kwargs)
if assessment:
self.instance.assessment = assessment
status_names = [
(status.id, status.name)
for status in models.TaskStatus.objects.filter(assessment=self.instance.assessment)
]
type_names = [
(type.id, type.name)
for type in models.TaskType.objects.filter(assessment=self.instance.assessment)
]
self.fields["task_type"].widget = forms.Select(choices=type_names)
self.fields["current_status"].widget = forms.Select(choices=status_names)
self.fields["next_status"].widget = forms.Select(choices=status_names)
self.fields["event"].widget = forms.Select(choices=constants.StartTaskTriggerEvent)

@property
def helper(self):
helper = BaseFormHelper(self)
helper.form_tag = False
helper.add_row("task_type", 4, ["col-md-3", "col-md-3", "col-md-3", "col-md-3"])
return helper


class TaskSetupCopyForm(forms.Form):
assessment = forms.ModelChoiceField(
label="Select an assessment", queryset=Assessment.objects.all(), empty_label=None
)

def __init__(self, *args, **kwargs):
kwargs.pop("instance")
self.user = kwargs.pop("user")
self.assessment = kwargs.pop("assessment")
super().__init__(*args, **kwargs)
self.fields["assessment"].widget.attrs["class"] = "col-md-12"
self.fields["assessment"].queryset = Assessment.objects.filter(
enable_project_management=True
).user_can_view(self.user, exclusion_id=self.assessment.id)

@property
def helper(self):
helper = BaseFormHelper(
self,
legend_text="Copy task managment approach from another assessment",
help_text="Copy task types, statuses, and triggers from an existing HAWC assessment which you have access to.",
cancel_url=reverse("mgmt:task-setup-list", args=(self.assessment.id,)),
submit_text="Copy from assessment",
)
helper.layout.insert(3, cfl.Div(css_id="approach"))
helper.layout.insert(2, cfl.Div(css_id="extra_content_insertion"))
return helper

def evaluate(self):
clone_approach(self.assessment, self.cleaned_data["assessment"], self.user.id)
Loading