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(nimbus): Approval and rejection flow #12090

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2ab1754
feat(nimbus): Summary page actions
yashikakhurana Nov 21, 2024
611c393
feat(nimbus): Cancel review flow
yashikakhurana Dec 11, 2024
cf977c6
feat(nimbus): Cancel review flow
yashikakhurana Dec 11, 2024
e1260b9
feat(nimbus): Cancel review flow
yashikakhurana Dec 11, 2024
9696f4a
feat(nimbus): Update urls
yashikakhurana Dec 11, 2024
0c770c3
test(nimbus): Test cases
yashikakhurana Dec 11, 2024
eefc8e1
test(nimbus): Test cases
yashikakhurana Dec 11, 2024
9d4eea5
Merge branch 'main' into 11757/draft_preview_flow
yashikakhurana Dec 11, 2024
0064d56
test(nimbus): Test cases
yashikakhurana Dec 11, 2024
47137d1
test(nimbus): Test cases
yashikakhurana Dec 11, 2024
84d22e5
test(nimbus): Test cases
yashikakhurana Dec 12, 2024
aa6e85d
test(nimbus): Test cases
yashikakhurana Dec 12, 2024
1c9e951
test(nimbus): Test cases
yashikakhurana Dec 12, 2024
6067e0b
Merge branch 'main' into 11757/draft_preview_flow
yashikakhurana Dec 12, 2024
fab606b
Some ideas from jared
jaredlockhart Dec 12, 2024
c98ad23
feat(nimbus): Launch control flow
yashikakhurana Dec 24, 2024
7cb83f2
Merge branch 'main' into 11757/draft_preview_flow
yashikakhurana Dec 24, 2024
30cd3f1
feat(nimbus): Launch control flow
yashikakhurana Dec 24, 2024
5fa331d
feat(nimbus): Launch control flow
yashikakhurana Dec 24, 2024
8e26539
feat(nimbus): Launch control flow
yashikakhurana Dec 24, 2024
b4a0153
feat(nimbus): Launch control flow
yashikakhurana Dec 24, 2024
c83735d
feat(nimbus): format
yashikakhurana Dec 24, 2024
9dcf31b
feat(nimbus)
yashikakhurana Jan 14, 2025
58f0c26
Merge branch 'main' into 11757/draft_preview_flow
yashikakhurana Jan 14, 2025
7b6eb7c
feat(nimbus): fix formating
yashikakhurana Jan 14, 2025
2e6f4ae
Merge branch 'main' into 11757/draft_preview_flow
yashikakhurana Jan 16, 2025
598a79c
feat(nimbus): Approval rejection flow
yashikakhurana Jan 22, 2025
3819ef9
feat(nimbus): Test approve and reject
yashikakhurana Jan 22, 2025
783d53b
feat(nimbus): Test approve and reject
yashikakhurana Jan 22, 2025
842d00d
Merge branch 'main' into 12072/approval_rejection
yashikakhurana Jan 28, 2025
cdb149d
feat(nimbus): Update status
yashikakhurana Jan 29, 2025
b98fa23
feat(nimbus): Sync remote settings
yashikakhurana Feb 3, 2025
8c81c43
Merge branch 'main' into 12072/approval_rejection
yashikakhurana Feb 5, 2025
b51b5eb
feat(nimbus): Change prefix
yashikakhurana Feb 22, 2025
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
Next Next commit
feat(nimbus): Summary page actions
  • Loading branch information
yashikakhurana committed Nov 21, 2024
commit 2ab1754066cfca7a2725f7d2f49abd0fc19c3468
7 changes: 5 additions & 2 deletions experimenter/experimenter/experiments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,11 +628,14 @@ def treatment_branches(self):

@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 == self.PublishStatus.REVIEW
)

@property
def is_preview(self):
Expand Down
90 changes: 90 additions & 0 deletions experimenter/experimenter/nimbus_ui_new/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ class Meta:
def save(self, commit=True):
experiment = super().save(commit=commit)
experiment.subscribers.add(self.request.user)
# Generate the changelog after all updates
generate_nimbus_changelog(
experiment, self.request.user, self.get_changelog_message()
)
return experiment

def get_changelog_message(self):
Expand All @@ -215,7 +219,93 @@ class Meta:
def save(self, commit=True):
experiment = super().save(commit=commit)
experiment.subscribers.remove(self.request.user)
# Generate the changelog after all updates
generate_nimbus_changelog(
experiment, self.request.user, self.get_changelog_message()
)
return experiment

def get_changelog_message(self):
return f"{self.request.user} removed subscriber"


class LaunchToPreviewForm(NimbusChangeLogFormMixin, forms.ModelForm):
class Meta:
model = NimbusExperiment
fields = []

def save(self, commit=True):
experiment = super().save(commit=commit)
# Update experiment status or other relevant fields
experiment.status = NimbusExperiment.Status.PREVIEW
experiment.save()
# Generate the changelog after all updates
generate_nimbus_changelog(
experiment, self.request.user, self.get_changelog_message()
)
return experiment

def get_changelog_message(self):
return f"{self.request.user} launched experiment to Preview"


class LaunchWithoutPreviewForm(NimbusChangeLogFormMixin, forms.ModelForm):
class Meta:
model = NimbusExperiment
fields = []

def save(self, commit=True):
experiment = super().save(commit=commit)
# Update experiment status or other relevant fields
experiment.publish_status = NimbusExperiment.PublishStatus.REVIEW
experiment.status = NimbusExperiment.Status.DRAFT
experiment.status_next = NimbusExperiment.Status.LIVE
experiment.save()
# Generate the changelog after all updates
generate_nimbus_changelog(
experiment, self.request.user, self.get_changelog_message()
)
return experiment

def get_changelog_message(self):
return f"{self.request.user} requested launch without Preview"


class LaunchPreviewToReviewForm(NimbusChangeLogFormMixin, forms.ModelForm):
class Meta:
model = NimbusExperiment
fields = []

def save(self, commit=True):
experiment = super().save(commit=commit)
experiment.publish_status = NimbusExperiment.PublishStatus.REVIEW
experiment.status_next = NimbusExperiment.Status.LIVE
experiment.save()
# Generate the changelog after all updates
generate_nimbus_changelog(
experiment, self.request.user, self.get_changelog_message()
)
return experiment

def get_changelog_message(self):
return f"{self.request.user} requested launch from Preview"


class LaunchPreviewToDraftForm(NimbusChangeLogFormMixin, forms.ModelForm):
class Meta:
model = NimbusExperiment
fields = []

def save(self, commit=True):
experiment = super().save(commit=commit)
experiment.status = NimbusExperiment.Status.DRAFT
experiment.status_next = None
experiment.save()
# Generate the changelog after all updates
generate_nimbus_changelog(
experiment, self.request.user, self.get_changelog_message()
)
return experiment

def get_changelog_message(self):
return f"{self.request.user} moved the experiment back to Draft"
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,20 @@ <h4 class="mb-0">{{ experiment.name }}</h4>
</span>
<p class="text-secondary">{{ experiment.slug }}</p>
</div>
{% include "nimbus_experiments/timeline.html" %}

</div>
<div id="experiment-container">
<div id="experiment-timeline"
>
{% include "nimbus_experiments/timeline.html" %}
</div>
<div id="launch-controls">
{% if experiment.is_draft %}
{% include "nimbus_experiments/launch_controls.html" %}
{% elif experiment.is_preview %}
{% include "nimbus_experiments/preview_controls.html" %}
{% endif %}
</div>
</div>
</div>
<!-- Takeaways Card -->
{% include "nimbus_experiments/takeaways_card.html" %}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{# templates/nimbus_experiments/launch_controls.html #}
<div class="alert alert-secondary">
<p>Do you want to test this experiment before launching to production?
<a href="https://experimenter.info/previewing-experiments/" target="_blank" class="mr-1">Learn more</a>

</p>

<div class="d-flex">
<form method="post"
action="{% url 'launch-to-preview' slug=experiment.slug %}"
hx-post="{% url 'launch-to-preview' slug=experiment.slug %}"
hx-target="#experiment-container"
hx-swap="innerHTML">
{% csrf_token %}
<button type="submit" class="btn btn-primary mr-2" {% if is_loading %}disabled{% endif %}>Preview for Testing</button>
</form>

<form method="post"
action="{% url 'launch-without-preview' slug=experiment.slug %}"
hx-post="{% url 'launch-without-preview' slug=experiment.slug %}"
hx-target="#experiment-container"
hx-swap="outerHTML">
{% csrf_token %}
<button type="submit" class="btn btn-secondary" {% if is_loading %}disabled{% endif %}>Request Launch without Preview</button>
</form>
</div>
</div>

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{# templates/nimbus_experiments/preview_success.html #}
<div class="alert alert-success bg-transparent text-success">
<p class="my-1">
<svg class="align-top" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 16 16" width="16" height="16">
<path d="M13.485 1.4a.5.5 0 0 1 .035.71L6.543 9.793 3.379 6.93a.5.5 0 1 1 .708-.707l2.1 2.1 6.514-7.1a.5.5 0 0 1 .707-.035z"/>
</svg>
All set! Your experiment is in Preview mode and you can test it now.
</p>
</div>

<div class="alert alert-secondary">
<form method="post" action="{% url 'launch-preview-to-review' slug=experiment.slug %}" hx-post="{% url 'launch-preview-to-review' slug=experiment.slug %}" hx-target="#launch-controls" hx-swap="outerHTML" id="preview-controls-form">
{% csrf_token %}
<p class="my-1">
This experiment is currently <strong>live for testing</strong>, but you will need to let QA know in your
<a href="https://example.com/qa-pi-doc" target="_blank">PI request</a>. When you have received a sign-off, click “Request Launch” to launch the experiment.
<strong>Note: It can take up to an hour before clients receive a preview experiment.</strong>
</p>

<!-- Confirmation Checkboxes -->
<div class="form-check">
<input type="checkbox" class="form-check-input" id="checkbox-1" onchange="toggleSubmitButton()">
<label class="form-check-label" for="checkbox-1">Checkbox 1</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="checkbox-2" onchange="toggleSubmitButton()">
<label class="form-check-label" for="checkbox-2">Checkbox 2</label>
</div>

<!-- Action Buttons -->
<div class="d-flex bd-highlight py-2">
<button type="submit" class="btn btn-primary mr-3" id="request-launch-button" hx-post="{% url 'launch-preview-to-review' slug=experiment.slug %}"
hx-target="#experiment-container"
hx-swap="innerHTML"disabled>
Request Launch
</button>
<button
type="button"
class="btn btn-secondary"
hx-post="{% url 'launch-preview-to-draft' slug=experiment.slug %}"
hx-target="#experiment-container"
hx-swap="innerHTML">
Go Back to Draft
</button>
</div>
</form>
</div>

<script>
function toggleSubmitButton() {
const checkboxes = document.querySelectorAll(".form-check-input");
const submitButton = document.getElementById("request-launch-button");
const allChecked = Array.from(checkboxes).every(checkbox => checkbox.checked);
submitButton.disabled = !allChecked;
}
</script>
25 changes: 25 additions & 0 deletions experimenter/experimenter/nimbus_ui_new/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from django.urls import re_path

from experimenter.nimbus_ui_new.views import (
LaunchPreviewToDraftView,
LaunchPreviewToReviewView,
LaunchToPreviewView,
LaunchWithoutPreviewView,
MetricsUpdateView,
NimbusChangeLogsView,
NimbusExperimentDetailView,
Expand Down Expand Up @@ -64,4 +68,25 @@
UnsubscribeView.as_view(),
name="nimbus-new-unsubscribe",
),
re_path(
r"^(?P<slug>[\w-]+)/launch-to-preview/$",
LaunchToPreviewView.as_view(),
name="launch-to-preview",
),
re_path(
r"^(?P<slug>[\w-]+)/launch-without-preview/$",
LaunchWithoutPreviewView.as_view(),
name="launch-without-preview",
),
re_path(
r"^(?P<slug>[\w-]+)/launch-preview-to-review/$",
LaunchPreviewToReviewView.as_view(),
name="launch-preview-to-review",
),
re_path(
r"^(?P<slug>[\w-]+)/launch-preview-to-draft/$",
LaunchPreviewToDraftView.as_view(),
name="launch-preview-to-draft",
),

]
Loading