-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: various dashboard template fixes (#19799)
* add a loading spinner while getting templates * limit what filters the api accepts * add text search to API * refactor a little * fix scoped display and add UI filtering * prettier * Update query snapshots * Update UI snapshots for `chromium` (2) * Update UI snapshots for `chromium` (1) * Update UI snapshots for `chromium` (2) * fix * Update UI snapshots for `webkit` (2) * fix * Update UI snapshots for `webkit` (2) * Update UI snapshots for `webkit` (2) * obey mypy --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
- Loading branch information
1 parent
fb0562d
commit 7a037b4
Showing
15 changed files
with
227 additions
and
59 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+1.27 KB
(100%)
frontend/__snapshots__/scenes-app-dashboards--new--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+770 Bytes
(100%)
frontend/__snapshots__/scenes-app-dashboards--new--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+193 Bytes
(100%)
...s__/scenes-app-insights--funnel-left-to-right-breakdown-edit--light--webkit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
+173 Bytes
(100%)
frontend/__snapshots__/scenes-app-insights--lifecycle-edit--light--webkit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
from typing import Dict, Optional, List | ||
|
||
from rest_framework import status | ||
|
||
from posthog.models import User | ||
from posthog.models.dashboard_templates import DashboardTemplate | ||
from posthog.models.organization import Organization | ||
from posthog.models.team.team import Team | ||
|
@@ -444,19 +447,120 @@ def test_cant_make_templates_without_teamid_private(self) -> None: | |
assert response.status_code == status.HTTP_200_OK | ||
assert response.json()["results"][0]["scope"] == "global" | ||
|
||
def test_search_when_listing_templates(self): | ||
# ensure there are no templates | ||
DashboardTemplate.objects.all().delete() | ||
|
||
self.create_template({"scope": DashboardTemplate.Scope.GLOBAL, "template_name": "pony template"}) | ||
self.create_template( | ||
{ | ||
"scope": DashboardTemplate.Scope.GLOBAL, | ||
"template_name": "wat template", | ||
"dashboard_description": "description with pony", | ||
} | ||
) | ||
self.create_template( | ||
{"scope": DashboardTemplate.Scope.GLOBAL, "template_name": "tagged wat template", "tags": ["pony", "horse"]} | ||
) | ||
self.create_template( | ||
{ | ||
"scope": DashboardTemplate.Scope.GLOBAL, | ||
"template_name": "tagged ponies template", | ||
"tags": ["goat", "horse"], | ||
} | ||
) | ||
not_pony_template_id = self.create_template( | ||
{"scope": DashboardTemplate.Scope.GLOBAL, "template_name": "goat template"} | ||
) | ||
|
||
default_response = self.client.get(f"/api/projects/{self.team.pk}/dashboard_templates/") | ||
assert default_response.status_code == status.HTTP_200_OK | ||
assert len(default_response.json()["results"]) == 5 | ||
|
||
# will match pony and ponies | ||
pony_response = self.client.get(f"/api/projects/{self.team.pk}/dashboard_templates/?search=pony") | ||
assert pony_response.status_code == status.HTTP_200_OK | ||
assert len(pony_response.json()["results"]) == 4 | ||
assert not_pony_template_id not in [r["id"] for r in pony_response.json()["results"]] | ||
|
||
def test_filter_template_list_by_scope(self): | ||
# ensure there are no templates | ||
DashboardTemplate.objects.all().delete() | ||
|
||
# create a flag and a global scoped template | ||
flag_template_id = self.create_template( | ||
{"scope": DashboardTemplate.Scope.FEATURE_FLAG, "template_name": "flag scoped template"} | ||
) | ||
global_template_id = self.create_template( | ||
{"scope": DashboardTemplate.Scope.GLOBAL, "template_name": "globally scoped template"} | ||
) | ||
|
||
default_response = self.client.get(f"/api/projects/{self.team.pk}/dashboard_templates/") | ||
assert default_response.status_code == status.HTTP_200_OK | ||
assert [(r["id"], r["scope"]) for r in default_response.json()["results"]] == [ | ||
(flag_template_id, "feature_flag"), | ||
(global_template_id, "global"), | ||
] | ||
|
||
global_response = self.client.get(f"/api/projects/{self.team.pk}/dashboard_templates/?scope=global") | ||
assert global_response.status_code == status.HTTP_200_OK | ||
assert [(r["id"], r["scope"]) for r in global_response.json()["results"]] == [(global_template_id, "global")] | ||
|
||
flag_response = self.client.get(f"/api/projects/{self.team.pk}/dashboard_templates/?scope=feature_flag") | ||
assert flag_response.status_code == status.HTTP_200_OK | ||
assert [(r["id"], r["scope"]) for r in flag_response.json()["results"]] == [(flag_template_id, "feature_flag")] | ||
|
||
def create_template(self, overrides: Dict[str, str | List[str]], team_id: Optional[int] = None) -> str: | ||
template = {**variable_template, **overrides} | ||
response = self.client.post( | ||
f"/api/projects/{self.team.pk}/dashboard_templates", | ||
variable_template, | ||
f"/api/projects/{team_id or self.team.pk}/dashboard_templates", | ||
template, | ||
) | ||
assert response.status_code == status.HTTP_201_CREATED | ||
id = response.json()["id"] | ||
|
||
self.client.patch( | ||
f"/api/projects/{self.team.pk}/dashboard_templates/{id}", | ||
{"scope": "feature_flag"}, | ||
return id | ||
|
||
def test_cannot_escape_team_when_filtering_template_list(self): | ||
# create another team, and log in as a user from that team | ||
another_team = Team.objects.create(name="Another Team", organization=self.organization) | ||
another_team_user = User.objects.create_and_join( | ||
organization=self.organization, first_name="Another", email="[email protected]", password="wat" | ||
) | ||
another_team_user.current_team = another_team | ||
another_team_user.is_staff = True | ||
another_team_user.save() | ||
|
||
response = self.client.get(f"/api/projects/{self.team.pk}/dashboard_templates/?scope=feature_flag") | ||
self.client.force_login(another_team_user) | ||
|
||
assert response.status_code == status.HTTP_200_OK | ||
assert response.json()["results"][0]["scope"] == "feature_flag" | ||
# create a dashboard template in that other team | ||
id = self.create_template( | ||
{"scope": DashboardTemplate.Scope.ONLY_TEAM, "template_name": "other teams template"}, | ||
team_id=another_team.pk, | ||
) | ||
|
||
# the user from another_team can access the new dashboard via the API on their own team | ||
list_response = self.client.get(f"/api/projects/{another_team.pk}/dashboard_templates/") | ||
assert list_response.status_code == status.HTTP_200_OK | ||
assert id in [r["id"] for r in list_response.json()["results"]] | ||
|
||
# the user from the home team cannot see the dashboard by default | ||
self.client.force_login(self.user) | ||
home_list_response = self.client.get(f"/api/projects/{self.team.pk}/dashboard_templates") | ||
|
||
assert home_list_response.status_code == status.HTTP_200_OK | ||
assert id not in [r["id"] for r in home_list_response.json()["results"]] | ||
|
||
# the user form the home team cannot escape their permissions by passing filters | ||
attempted_escape_response = self.client.get( | ||
f"/api/projects/{self.team.pk}/dashboard_templates/?team_id={another_team.pk}" | ||
) | ||
assert attempted_escape_response.status_code == status.HTTP_200_OK | ||
assert id not in [r["id"] for r in attempted_escape_response.json()["results"]] | ||
|
||
# searching by text doesn't get around the team filtering | ||
another_attempted_escape_response = self.client.get( | ||
f"/api/projects/{self.team.pk}/dashboard_templates/?search=other" | ||
) | ||
assert another_attempted_escape_response.status_code == status.HTTP_200_OK | ||
assert id not in [r["id"] for r in another_attempted_escape_response.json()["results"]] |
Oops, something went wrong.