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

feat: split start/end dates into separate columns on main list #11989

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
37 changes: 34 additions & 3 deletions experimenter/experimenter/nimbus_ui_new/filtersets.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from datetime import datetime

import django_filters
from django import forms
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Q
from django.db.models import Case, IntegerField, Q, Value, When
from django.db.models.functions import Concat

from experimenter.base.models import Country, Language, Locale
Expand Down Expand Up @@ -65,8 +67,10 @@ class SortChoices(models.TextChoices):
FEATURES_DOWN = "-feature_configs__slug"
VERSIONS_UP = "firefox_min_version"
VERSIONS_DOWN = "-firefox_min_version"
DATES_UP = "_start_date"
DATES_DOWN = "-_start_date"
START_DATE_UP = "_start_date"
START_DATE_DOWN = "-_start_date"
END_DATE_UP = "computed_end_date"
END_DATE_DOWN = "-computed_end_date"


class IconMultiSelectWidget(MultiSelectWidget):
Expand Down Expand Up @@ -258,6 +262,33 @@ class Meta:
]

def filter_sort(self, queryset, name, value):
if value in [SortChoices.END_DATE_UP, SortChoices.END_DATE_DOWN]:
reverse = value == SortChoices.END_DATE_DOWN
if value == SortChoices.END_DATE_UP:
default_date = datetime.max.date()
else:
default_date = datetime.min.date()

queryset_sorted = sorted(
queryset,
key=lambda exp: exp.computed_end_date
if exp.computed_end_date
else default_date,
reverse=reverse,
)

preserved_order = Case(
*[
When(pk=exp.id, then=Value(pos))
for pos, exp in enumerate(queryset_sorted)
],
output_field=IntegerField()
)
Comment on lines +280 to +286
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh! That's really interesting! I've always wondered how to do that, I've never seen this pattern before, but it makes perfect sense. Great job!


return queryset.filter(pk__in=[exp.id for exp in queryset_sorted]).order_by(
preserved_order
)

return queryset.order_by(value)

def filter_status(self, queryset, name, value):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ <h1 class="modal-title fs-5" id="createModalLabel">
{% include "nimbus_experiments/table_header.html" with field="Size" up=sort_choices.SIZE_UP down=sort_choices.SIZE_DOWN %}
{% include "nimbus_experiments/table_header.html" with field="Features" up=sort_choices.FEATURES_UP down=sort_choices.FEATURES_DOWN %}
{% include "nimbus_experiments/table_header.html" with field="Versions" up=sort_choices.VERSIONS_UP down=sort_choices.VERSIONS_DOWN %}
{% include "nimbus_experiments/table_header.html" with field="Dates" up=sort_choices.DATES_UP down=sort_choices.DATES_DOWN %}
{% include "nimbus_experiments/table_header.html" with field="Start" up=sort_choices.START_DATE_UP down=sort_choices.START_DATE_DOWN %}
{% include "nimbus_experiments/table_header.html" with field="End" up=sort_choices.END_DATE_UP down=sort_choices.END_DATE_DOWN %}

<th scope="col">Results</th>
</tr>
Expand Down Expand Up @@ -110,11 +111,14 @@ <h1 class="modal-title fs-5" id="createModalLabel">
</td>
<td>
{% if experiment.start_date %}
{{ experiment.start_date|date:"Y-m-d" }} -
<br>
{{ experiment.computed_end_date|date:"Y-m-d" }}
<br>
({{ experiment.computed_duration_days }} days)
{{ experiment.start_date|date:"Y-m-d" }}
{% else %}
N/A
{% endif %}
</td>
<td>
{% if experiment.computed_end_date %}
{{ experiment.computed_end_date|date:"Y-m-d" }}({{ experiment.computed_duration_days }} days)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this typo:

Suggested change
{{ experiment.computed_end_date|date:"Y-m-d" }}({{ experiment.computed_duration_days }} days)
{{ experiment.computed_end_date|date:"Y-m-d" }} ({{ experiment.computed_duration_days }} days)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrmmm I can't seem to apply this change, probably because it's on @RJAK11 's fork. Let's just land this and we can do that as a followup when @RJAK11 is back 🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's my fork so I could probably do it, but that's fine too -- it's just a space!

{% else %}
N/A
{% endif %}
Expand Down
60 changes: 57 additions & 3 deletions experimenter/experimenter/nimbus_ui_new/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ def test_sort_by_versions(self):
[experiment2.slug, experiment1.slug],
)

def test_sort_by_dates(self):
def test_sort_by_start_date(self):
experiment1 = NimbusExperimentFactory.create_with_lifecycle(
NimbusExperimentFactory.Lifecycles.LIVE_ENROLLING,
start_date=datetime.date(2024, 1, 1),
Expand All @@ -860,7 +860,7 @@ def test_sort_by_dates(self):
response = self.client.get(
reverse("nimbus-list"),
{
"sort": SortChoices.DATES_UP,
"sort": SortChoices.START_DATE_UP,
},
)

Expand All @@ -872,7 +872,7 @@ def test_sort_by_dates(self):
response = self.client.get(
reverse("nimbus-list"),
{
"sort": SortChoices.DATES_DOWN,
"sort": SortChoices.START_DATE_DOWN,
},
)

Expand All @@ -881,6 +881,60 @@ def test_sort_by_dates(self):
[experiment2.slug, experiment1.slug],
)

def test_sort_by_end_date(self):
experiment1 = NimbusExperimentFactory.create_with_lifecycle(
NimbusExperimentFactory.Lifecycles.ENDING_APPROVE,
start_date=datetime.date(2024, 1, 1),
end_date=datetime.date(2024, 2, 1),
)
experiment2 = NimbusExperimentFactory.create_with_lifecycle(
NimbusExperimentFactory.Lifecycles.ENDING_APPROVE,
start_date=datetime.date(2024, 1, 2),
end_date=datetime.date(2024, 2, 2),
)
experiment3 = NimbusExperimentFactory.create_with_lifecycle(
NimbusExperimentFactory.Lifecycles.LIVE_ENROLLING,
start_date=datetime.date(2024, 1, 2),
proposed_duration=10,
)
experiment4 = NimbusExperimentFactory.create(
status=NimbusExperiment.Status.LIVE,
)

response = self.client.get(
reverse("nimbus-list"),
{
"sort": SortChoices.END_DATE_UP,
},
)

expected_order_up = sorted(
[experiment1, experiment2, experiment3], key=lambda exp: exp.computed_end_date
)

self.assertEqual(
[e.slug for e in response.context["experiments"]],
([exp.slug for exp in expected_order_up] + [experiment4.slug]),
)

response = self.client.get(
reverse("nimbus-list"),
{
"sort": SortChoices.END_DATE_DOWN,
},
)

expected_order_down = sorted(
[experiment1, experiment2, experiment3],
key=lambda exp: exp.computed_end_date,
reverse=True,
)

self.assertEqual(
[e.slug for e in response.context["experiments"]],
([exp.slug for exp in expected_order_down] + [experiment4.slug]),
)


class NimbusExperimentsListTableViewTest(AuthTestCase):
def test_render_to_response(self):
Expand Down