feat(nimbus): Enrollment and complete days (#11711)

Because

- We are not showing days (enrollment days and total duration of the
experiment) on the new summary page

This commit

- Add enrollment days
- Add total duration of the experiment

Fixes #1
![Screenshot 2024-11-06 at 12 45
37 PM](https://github.com/user-attachments/assets/5f0580bf-947a-418c-96f3-4c170d46c5c4)
1710
This commit is contained in:
Yashika Khurana 2024-11-18 16:13:07 -08:00 коммит произвёл GitHub
Родитель b52694d7a8
Коммит ab212df776
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
4 изменённых файлов: 59 добавлений и 15 удалений

Просмотреть файл

@ -818,7 +818,8 @@ Optional - We believe this outcome will <describe impact> on <core metric>
WARNING_PREF_FLIPS_PREF_CONTROLLED_BY_FEATURE = (
"Pref '{pref}' is controlled by a variable in feature {feature_config_slug}'"
)
ENROLLMENT_END = "Enrollment End"
OBSERVATION = "Observation"
ENROLLMENT = "Enrollment"
RISK_QUESTIONS = {

Просмотреть файл

@ -628,24 +628,34 @@ class NimbusExperiment(NimbusConstants, TargetingConstants, FilterMixin, models.
@property
def is_draft(self):
return self.status == self.Status.DRAFT
return (
self.status == self.Status.DRAFT
and self.publish_status == self.PublishStatus.IDLE
)
@property
def is_review(self):
return self.is_draft and self.publish_status == self.PublishStatus.REVIEW
return self.status == self.Status.DRAFT and self.publish_status in [
self.PublishStatus.REVIEW,
self.PublishStatus.WAITING,
]
@property
def is_preview(self):
return self.status == self.Status.PREVIEW
@property
def is_live(self):
return self.status == self.Status.LIVE
def is_enrollment(self):
return self.status == self.Status.LIVE and not self.is_paused_published
@property
def is_complete(self):
return self.status == self.Status.COMPLETE
@property
def is_observation(self):
return self._enrollment_end_date is not None and not self.is_complete
@property
def is_started(self):
return self.status in (self.Status.LIVE, self.Status.COMPLETE)
@ -806,41 +816,57 @@ class NimbusExperiment(NimbusConstants, TargetingConstants, FilterMixin, models.
return (self.computed_end_date - self.enrollment_start_date).days
return self.proposed_duration
@property
def computed_observations_days(self):
if (
enrollment_end_date := (
self.actual_enrollment_end_date or self.computed_enrollment_end_date
)
) and self.computed_end_date:
return (self.computed_end_date - enrollment_end_date).days
return None
def timeline(self):
timeline_entries = [
{
"label": self.Status.DRAFT,
"date": self.draft_date,
"is_active": self.is_draft,
"days": None,
},
{
"label": self.Status.PREVIEW,
"date": self.preview_date,
"is_active": self.is_preview,
"days": None,
},
{
"label": self.PublishStatus.REVIEW,
"date": self.review_date,
"is_active": self.is_review,
"days": None,
},
{
"label": self.Status.LIVE,
"label": NimbusConstants.ENROLLMENT,
"date": self.start_date,
"is_active": self.is_live,
"is_active": self.is_enrollment,
"days": self.computed_enrollment_days,
},
{
"label": self.Status.COMPLETE,
"date": self.computed_end_date,
"is_active": self.is_complete,
"days": self.computed_duration_days,
},
]
if not self.is_rollout:
timeline_entries.insert(
4,
{
"label": NimbusConstants.ENROLLMENT_END,
"label": NimbusConstants.OBSERVATION,
"date": self._enrollment_end_date,
"is_active": self._enrollment_end_date is not None,
"is_active": self.is_observation,
"days": self.computed_observations_days,
},
)

Просмотреть файл

@ -1689,7 +1689,11 @@ class TestNimbusExperiment(TestCase):
def test_timeline_dates_includes_correct_status_dates_and_flags(self):
experiment = NimbusExperimentFactory.create_with_lifecycle(
lifecycle=NimbusExperimentFactory.Lifecycles.LIVE_APPROVE,
lifecycle=NimbusExperimentFactory.Lifecycles.ENDING_APPROVE_APPROVE,
proposed_enrollment=2,
start_date=datetime.date(2023, 1, 4),
_enrollment_end_date=datetime.date(2023, 1, 6),
end_date=datetime.date(2023, 1, 8),
)
NimbusChangeLogFactory.create(
experiment=experiment,
@ -1701,14 +1705,14 @@ class TestNimbusExperiment(TestCase):
experiment=experiment,
old_status=NimbusExperiment.Status.DRAFT,
new_status=NimbusExperiment.Status.PREVIEW,
changed_on=datetime.datetime(2023, 3, 1),
changed_on=datetime.datetime(2023, 1, 2),
)
NimbusChangeLogFactory.create(
experiment=experiment,
old_publish_status=NimbusExperiment.Status.PREVIEW,
new_publish_status=NimbusExperiment.PublishStatus.REVIEW,
changed_on=datetime.datetime(2023, 4, 1),
changed_on=datetime.datetime(2023, 1, 3),
)
timeline = experiment.timeline()
expected_timeline = [
@ -1716,33 +1720,45 @@ class TestNimbusExperiment(TestCase):
"label": "Draft",
"date": experiment.draft_date,
"is_active": False,
"days": None,
},
{
"label": "Preview",
"date": experiment.preview_date,
"is_active": False,
"days": None,
},
{
"label": "Review",
"date": experiment.review_date,
"is_active": False,
"days": None,
},
{"label": "Live", "date": experiment.start_date, "is_active": True},
{
"label": NimbusConstants.ENROLLMENT_END,
"label": NimbusConstants.ENROLLMENT,
"date": experiment.start_date,
"is_active": False,
"days": 2,
},
{
"label": NimbusConstants.OBSERVATION,
"date": experiment._enrollment_end_date,
"is_active": False,
"days": 2,
},
{
"label": "Complete",
"date": experiment.computed_end_date,
"is_active": False,
"is_active": True,
"days": 4,
},
]
for i, expected in enumerate(expected_timeline):
self.assertEqual(timeline[i]["label"], expected["label"])
self.assertEqual(timeline[i]["date"], expected["date"])
self.assertEqual(timeline[i]["is_active"], expected["is_active"])
self.assertEqual(timeline[i].get("days"), expected["days"])
def test_timeline_dates_complete_is_active_when_status_is_complete(self):
experiment = NimbusExperimentFactory.create_with_lifecycle(

Просмотреть файл

@ -4,6 +4,7 @@
<li class="list-group-item flex-fill text-center d-flex flex-column justify-content-center {% if status.is_active %}bg-primary text-white{% endif %}">
<strong>{{ status.label }}</strong>
<small>{{ status.date|default:'---' }}</small>
{% if status.days is not None %}<small>{{ status.days }} day{{ status.days|pluralize }}</small>{% endif %}
</li>
{% endfor %}
</ul>