Skip to content

Commit 124a44f

Browse files
feat(nimbus): add results to new nimbus ui (#12732)
Because * We need to add a results page to the new Nimbus UI * We can use the existing results page until we have a more suitable replacement This commit * Makes a copy of the nimbus-ui React app called results * Removes all components except those necessary for the results page * Adds all of the Makefile entry points to test, lint, etc the new results app * Adds all of the build/copy steps for the new results app to the Dockerfile * Adds a new url/view for the results page in nimbus_ui_new fixes #12707 ![Screenshot 2025-06-05 at 16-27-51 Desktop Credit Card Autofill Global Enablement Holdback (Release) Experimenter](https://github.com/user-attachments/assets/e7aa3efa-ae30-4a4a-a16c-74fe04833624) --------- Co-authored-by: Yashika Khurana <yashikakhuranayashika@gmail.com>
1 parent 3a9367f commit 124a44f

File tree

157 files changed

+25393
-25
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

157 files changed

+25393
-25
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ experimenter/experimenter/reporting/reporting-ui/assets/
9494
.tmontmp
9595
experimenter/coverage_html_report/
9696
experimenter/tests/integration/test-reports/
97+
junit.xml
98+
**/coverage_report/
9799

98100
# Dependencies
99101
node_modules

Makefile

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,22 @@ PYTHON_MIGRATE = python manage.py migrate
3939
ESLINT_LEGACY = yarn workspace @experimenter/core lint
4040
ESLINT_FIX_CORE = yarn workspace @experimenter/core lint-fix
4141
ESLINT_NIMBUS_UI = yarn workspace @experimenter/nimbus-ui lint
42+
ESLINT_RESULTS = yarn workspace @experimenter/results lint
4243
ESLINT_FIX_NIMBUS_UI = yarn workspace @experimenter/nimbus-ui lint-fix
44+
ESLINT_FIX_RESULTS = yarn workspace @experimenter/results lint-fix
4345
ESLINT_NIMBUS_UI_NEW = yarn workspace @experimenter/nimbus_ui_new lint
4446
ESLINT_FIX_NIMBUS_UI_NEW = yarn workspace @experimenter/nimbus_ui_new format
4547
TYPECHECK_NIMBUS_UI = yarn workspace @experimenter/nimbus-ui lint:tsc
48+
TYPECHECK_RESULTS = yarn workspace @experimenter/results lint:tsc
4649
DJLINT_CHECK = djlint --check experimenter/nimbus_ui_new/
4750
DJLINT_FIX = djlint --reformat experimenter/nimbus_ui_new/
4851
JS_TEST_LEGACY = yarn workspace @experimenter/core test
4952
JS_TEST_NIMBUS_UI = DEBUG_PRINT_LIMIT=999999 CI=yes yarn workspace @experimenter/nimbus-ui test:cov
53+
JS_TEST_RESULTS = DEBUG_PRINT_LIMIT=999999 CI=yes yarn workspace @experimenter/results test:cov
5054
NIMBUS_SCHEMA_CHECK = python manage.py graphql_schema --out experimenter/nimbus-ui/test_schema.graphql&&diff experimenter/nimbus-ui/test_schema.graphql experimenter/nimbus-ui/schema.graphql || (echo GraphQL Schema is out of sync please run make generate_types;exit 1)
55+
RESULTS_SCHEMA_CHECK = python manage.py graphql_schema --out experimenter/results/test_schema.graphql&&diff experimenter/results/test_schema.graphql experimenter/results/schema.graphql || (echo GraphQL Schema is out of sync please run make generate_types;exit 1)
5156
NIMBUS_TYPES_GENERATE = python manage.py graphql_schema --out experimenter/nimbus-ui/schema.graphql&&yarn workspace @experimenter/nimbus-ui generate-types
57+
RESULTS_TYPES_GENERATE = python manage.py graphql_schema --out experimenter/results/schema.graphql&&yarn workspace @experimenter/results generate-types
5258
RUFF_CHECK = ruff check experimenter/ tests/
5359
RUFF_FIX = ruff check --fix experimenter/ tests/
5460
RUFF_FORMAT_CHECK = ruff format --check --diff . --exclude node_modules
@@ -166,7 +172,7 @@ kill: compose_stop compose_rm docker_prune ## Stop, remove, and prune container
166172

167173
lint: build_test ## Running linting on source code
168174
-docker rm experimenter_test;
169-
$(COMPOSE_TEST_RUN) experimenter sh -c '$(WAIT_FOR_DB) (${PARALLEL} "$(NIMBUS_SCHEMA_CHECK)" "$(PYTHON_CHECK_MIGRATIONS)" "$(CHECK_DOCS)" "$(RUFF_FORMAT_CHECK)" "$(RUFF_CHECK)" "$(DJLINT_CHECK)" "$(ESLINT_LEGACY)" "$(ESLINT_NIMBUS_UI)" "$(ESLINT_NIMBUS_UI_NEW)" "$(TYPECHECK_NIMBUS_UI)" "$(PYTHON_TYPECHECK)" "$(PYTHON_TEST)" "$(JS_TEST_LEGACY)" "$(JS_TEST_NIMBUS_UI)") ${COLOR_CHECK}'
175+
$(COMPOSE_TEST_RUN) experimenter sh -c '$(WAIT_FOR_DB) (${PARALLEL} "$(NIMBUS_SCHEMA_CHECK)" "$(PYTHON_CHECK_MIGRATIONS)" "$(CHECK_DOCS)" "$(RUFF_FORMAT_CHECK)" "$(RUFF_CHECK)" "$(DJLINT_CHECK)" "$(ESLINT_LEGACY)" "$(ESLINT_NIMBUS_UI)" "$(ESLINT_RESULTS)" "$(ESLINT_NIMBUS_UI_NEW)" "$(TYPECHECK_NIMBUS_UI)" "$(PYTHON_TYPECHECK)" "$(PYTHON_TEST)" "$(JS_TEST_LEGACY)" "$(JS_TEST_NIMBUS_UI)" "$(JS_TEST_RESULTS)" "$(RESULTS_SCHEMA_CHECK)") ${COLOR_CHECK}'
170176

171177
check: lint
172178

@@ -212,10 +218,10 @@ generate_docs: build_dev
212218
$(COMPOSE_RUN) experimenter sh -c "$(GENERATE_DOCS)"
213219

214220
generate_types: build_dev
215-
$(COMPOSE_RUN) experimenter sh -c "$(NIMBUS_TYPES_GENERATE)"
221+
$(COMPOSE_RUN) experimenter sh -c "$(NIMBUS_TYPES_GENERATE); $(RESULTS_TYPES_GENERATE)"
216222

217223
format: build_dev ## Format source tree
218-
$(COMPOSE_RUN) experimenter sh -c '${PARALLEL} "$(RUFF_FIX);$(DJLINT_FIX);$(RUFF_FORMAT_FIX)" "$(ESLINT_FIX_CORE)" "$(ESLINT_FIX_NIMBUS_UI)" "$(ESLINT_FIX_NIMBUS_UI_NEW)"'
224+
$(COMPOSE_RUN) experimenter sh -c '${PARALLEL} "$(RUFF_FIX);$(DJLINT_FIX);$(RUFF_FORMAT_FIX)" "$(ESLINT_FIX_CORE)" "$(ESLINT_FIX_NIMBUS_UI)" "$(ESLINT_FIX_RESULTS)" "$(ESLINT_FIX_NIMBUS_UI_NEW)"'
219225
code_format: format
220226

221227
makemigrations: build_dev

docker-compose.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,32 @@ services:
5757
- /experimenter/experimenter/legacy/legacy-ui/core/.cache/
5858
- /experimenter/experimenter/legacy/legacy-ui/core/node_modules/
5959
- /experimenter/experimenter/nimbus-ui/node_modules/
60+
- /experimenter/experimenter/results/node_modules/
6061
- /experimenter/experimenter/nimbus_ui_new/static/node_modules/
6162
- /experimenter/experimenter/served/
6263
- /experimenter/node_modules/
6364
- ${GOOGLE_ADC_FILE}:${GOOGLE_APPLICATION_CREDENTIALS}:ro
6465
command: bash -c "FORCE_COLOR=true yarn workspace @experimenter/nimbus-ui start | cat"
6566

67+
yarn-results:
68+
image: experimenter:dev
69+
env_file: .env
70+
tty: true
71+
ports:
72+
- "3001:3000"
73+
volumes:
74+
- ./experimenter:/experimenter
75+
- media_volume:/experimenter/experimenter/media
76+
- /experimenter/experimenter/legacy/legacy-ui/core/.cache/
77+
- /experimenter/experimenter/legacy/legacy-ui/core/node_modules/
78+
- /experimenter/experimenter/nimbus-ui/node_modules/
79+
- /experimenter/experimenter/results/node_modules/
80+
- /experimenter/experimenter/nimbus_ui_new/static/node_modules/
81+
- /experimenter/experimenter/served/
82+
- /experimenter/node_modules/
83+
- ${GOOGLE_ADC_FILE}:${GOOGLE_APPLICATION_CREDENTIALS}:ro
84+
command: bash -c "FORCE_COLOR=true yarn workspace @experimenter/results start | cat"
85+
6686
worker:
6787
image: experimenter:dev
6888
env_file: .env

experimenter/Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@ COPY ./package.json /experimenter/package.json
5252
COPY ./yarn.lock /experimenter/yarn.lock
5353
COPY ./experimenter/legacy/legacy-ui/core/package.json /experimenter/experimenter/legacy/legacy-ui/core/package.json
5454
COPY ./experimenter/nimbus-ui/package.json /experimenter/experimenter/nimbus-ui/package.json
55+
COPY ./experimenter/results/package.json /experimenter/experimenter/results/package.json
5556
COPY ./experimenter/nimbus_ui_new/static/package.json /experimenter/experimenter/nimbus_ui_new/static/package.json
5657
RUN python3 -m pip install setuptools
5758
RUN yarn install --frozen-lockfile
5859
COPY ./experimenter/legacy/legacy-ui/core/ /experimenter/experimenter/legacy/legacy-ui/core/
5960
COPY ./experimenter/nimbus-ui/ /experimenter/experimenter/nimbus-ui/
61+
COPY ./experimenter/results/ /experimenter/experimenter/results/
6062
COPY ./experimenter/nimbus_ui_new/ /experimenter/experimenter/nimbus_ui_new/
6163

6264

@@ -76,6 +78,7 @@ COPY --from=python-builder /usr/local/lib/python3.13/site-packages/ /usr/local/l
7678
# Node packages
7779
COPY --from=node-builder /experimenter/experimenter/legacy/legacy-ui/core/node_modules/ /experimenter/experimenter/legacy/legacy-ui/core/node_modules/
7880
COPY --from=node-builder /experimenter/experimenter/nimbus-ui/node_modules/ /experimenter/experimenter/nimbus-ui/node_modules/
81+
COPY --from=node-builder /experimenter/experimenter/results/node_modules/ /experimenter/experimenter/results/node_modules/
7982
COPY --from=node-builder /experimenter/experimenter/nimbus_ui_new/static/node_modules/ /experimenter/experimenter/nimbus_ui_new/static/node_modules/
8083
COPY --from=node-builder /experimenter/node_modules/ /experimenter/node_modules/
8184

@@ -107,6 +110,10 @@ RUN yarn workspace @experimenter/core build
107110
COPY ./experimenter/nimbus-ui/ /experimenter/experimenter/nimbus-ui/
108111
RUN yarn workspace @experimenter/nimbus-ui build
109112

113+
# Build results assets
114+
COPY ./experimenter/results/ /experimenter/experimenter/results/
115+
RUN yarn workspace @experimenter/results build
116+
110117
# Build nimbus_ui_new assets
111118
COPY ./experimenter/nimbus_ui_new/ /experimenter/experimenter/nimbus_ui_new/
112119
RUN yarn workspace @experimenter/nimbus_ui_new build
@@ -140,6 +147,7 @@ COPY ./experimenter/ /experimenter/experimenter/
140147
COPY ./manifesttool/ /experimenter/manifesttool/
141148
COPY --from=ui /experimenter/experimenter/legacy/legacy-ui/assets/ /experimenter/experimenter/legacy/legacy-ui/assets/
142149
COPY --from=ui /experimenter/experimenter/nimbus-ui/build/ /experimenter/experimenter/nimbus-ui/build/
150+
COPY --from=ui /experimenter/experimenter/results/build/ /experimenter/experimenter/results/build/
143151
COPY --from=ui /experimenter/experimenter/nimbus_ui_new/static/dist/ /experimenter/experimenter/nimbus_ui_new/static/dist/
144152

145153
ENV PYTHONPATH=$PYTHONPATH:/application-services/

experimenter/experimenter/experiments/models.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,9 @@ def get_update_audience_url(self):
488488
def get_detail_preview_recipe_json_url(self):
489489
return f"{self.get_detail_url()}#preview-recipe-json"
490490

491+
def get_results_url(self):
492+
return reverse("nimbus-new-results", kwargs={"slug": self.slug})
493+
491494
@property
492495
def experiment_url(self):
493496
return urljoin(f"https://{settings.HOSTNAME}", self.get_absolute_url())
@@ -1062,10 +1065,10 @@ def sidebar_links(self, current_path):
10621065
},
10631066
{
10641067
"title": "Results",
1065-
"link": "",
1068+
"link": self.get_results_url(),
10661069
"icon": "fa-solid fa-chart-column",
1067-
"active": False,
1068-
"disabled": True,
1070+
"active": current_path == self.get_results_url(),
1071+
"disabled": self.disable_results_link,
10691072
},
10701073
{"title": "Edit", "is_header": True},
10711074
{
@@ -1463,6 +1466,10 @@ def show_results_url(self):
14631466
# (the dates may have been overridden in metric-hub)
14641467
return not self.is_rollout and self.has_displayable_results
14651468

1469+
@property
1470+
def disable_results_link(self):
1471+
return not self.show_results_url
1472+
14661473
@property
14671474
def results_expected_date(self):
14681475
if not self.is_rollout:

experimenter/experimenter/nimbus-ui/src/types/globalTypes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ export enum NimbusExperimentFirefoxVersionEnum {
7979
FIREFOX_114_3_0 = "FIREFOX_114_3_0",
8080
FIREFOX_115 = "FIREFOX_115",
8181
FIREFOX_115_0_2 = "FIREFOX_115_0_2",
82-
FIREFOX_115_7 = "FIREFOX_115_7",
8382
FIREFOX_115_25 = "FIREFOX_115_25",
83+
FIREFOX_115_7 = "FIREFOX_115_7",
8484
FIREFOX_116 = "FIREFOX_116",
8585
FIREFOX_116_0_1 = "FIREFOX_116_0_1",
8686
FIREFOX_116_2_0 = "FIREFOX_116_2_0",

experimenter/experimenter/nimbus_ui_new/templates/experimenter_base.html

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,27 @@
1515
| Experimenter
1616
</title>
1717
<script src="{% static 'nimbus_ui_new/app.bundle.js' %}"></script>
18+
{% block extra_head %}
19+
{% endblock extra_head %}
20+
1821
</head>
19-
<body
20-
{# djlint:off #}
21-
id="{% block page_id %}{% endblock %}"
22-
{# djlint:on #}
23-
class="bg-body-tertiary">
24-
<div class="container-fluid bg-body border-bottom border-1 mb-4 py-1">
25-
{% include "common/header.html" %}
22+
<body {# djlint:off #}
23+
id="{% block page_id %}{% endblock %}"
24+
{# djlint:on #}
25+
class="bg-body-tertiary">
26+
<div class="container-fluid bg-body border-bottom border-1 mb-4 py-1">
27+
{% include "common/header.html" %}
2628

27-
</div>
28-
<div class="container-fluid">
29-
{% block content %}
30-
{% endblock content %}
29+
</div>
30+
<div class="container-fluid">
31+
{% block content %}
32+
{% endblock content %}
3133

32-
{% include "common/footer.html" %}
34+
{% include "common/footer.html" %}
3335

34-
</div>
35-
{% block extrascripts %}
36-
{% endblock extrascripts %}
36+
</div>
37+
{% block extrascripts %}
38+
{% endblock extrascripts %}
3739

38-
</body>
40+
</body>
3941
</html>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{% extends "nimbus_experiments/experiment_base.html" %}
2+
3+
{% load static %}
4+
{% load nimbus_extras %}
5+
6+
{% block title %}{{ experiment.name }}{% endblock %}
7+
8+
{% block extra_head %}
9+
{% if not USE_YARN_DEV %}
10+
<link rel="stylesheet" href="{% static 'results/static/css/main.css' %}" />
11+
{% endif %}
12+
{% endblock extra_head %}
13+
14+
{% block main_content %}
15+
<div id="root" data-config="{{ APP_CONFIG }}"></div>
16+
{% endblock main_content %}
17+
18+
{% block extrascripts %}
19+
{% if USE_YARN_DEV %}
20+
<script src="http://localhost:3001/static/js/main.js"></script>
21+
{% else %}
22+
<script src="{% static 'results/static/js/main.js' %}"></script>
23+
{% endif %}
24+
{% endblock extrascripts %}

experimenter/experimenter/nimbus_ui_new/tests/test_views.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2606,3 +2606,17 @@ def test_get_redirects_to_next_step(self, current_url, next_url, data):
26062606
response.headers["HX-Redirect"],
26072607
reverse(next_url, kwargs={"slug": experiment.slug}),
26082608
)
2609+
2610+
2611+
class TestResultsView(AuthTestCase):
2612+
def test_render_to_response(self):
2613+
experiment = NimbusExperimentFactory.create_with_lifecycle(
2614+
NimbusExperimentFactory.Lifecycles.ENDING_APPROVE_APPROVE,
2615+
)
2616+
2617+
response = self.client.get(
2618+
reverse("nimbus-new-results", kwargs={"slug": experiment.slug}),
2619+
)
2620+
self.assertEqual(response.status_code, 200)
2621+
self.assertEqual(response.context["experiment"], experiment)
2622+
self.assertTemplateUsed(response, "nimbus_experiments/results.html")

experimenter/experimenter/nimbus_ui_new/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
PreviewToDraftView,
3434
PreviewToReviewView,
3535
QAStatusUpdateView,
36+
ResultsView,
3637
ReviewToApproveView,
3738
ReviewToDraftView,
3839
SignoffUpdateView,
@@ -244,4 +245,9 @@
244245
ApproveUpdateRolloutView.as_view(),
245246
name="nimbus-new-approve-update-rollout",
246247
),
248+
re_path(
249+
r"^(?P<slug>[\w-]+)/results/.*",
250+
ResultsView.as_view(),
251+
name="nimbus-new-results",
252+
),
247253
]

0 commit comments

Comments
 (0)