From 6312bbb19e3eab842c653f89a0b6accbec021e0e Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Mon, 3 Jun 2024 13:37:45 -0700 Subject: [PATCH 01/10] Create endpoint, serializer, and tests --- .../api/serializers/models/groupsearchview.py | 16 ++++ .../organization_group_search_views.py | 45 ++++++++++ .../test_organization_group_search_views.py | 84 +++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 src/sentry/api/serializers/models/groupsearchview.py create mode 100644 src/sentry/issues/endpoints/organization_group_search_views.py create mode 100644 tests/sentry/issues/endpoints/test_organization_group_search_views.py diff --git a/src/sentry/api/serializers/models/groupsearchview.py b/src/sentry/api/serializers/models/groupsearchview.py new file mode 100644 index 00000000000000..ccec673ee935b0 --- /dev/null +++ b/src/sentry/api/serializers/models/groupsearchview.py @@ -0,0 +1,16 @@ +from sentry.api.serializers import Serializer, register +from sentry.models.groupsearchview import GroupSearchView + + +@register(GroupSearchView) +class GroupSearchViewSerializer(Serializer): + def serialize(self, obj, attrs, user): + return { + "id": str(obj.id), + "name": obj.name, + "query": obj.query, + "querySort": obj.query_sort, + "position": obj.position, + "dateCreated": obj.date_added, + "dateUpdated": obj.date_updated, + } diff --git a/src/sentry/issues/endpoints/organization_group_search_views.py b/src/sentry/issues/endpoints/organization_group_search_views.py new file mode 100644 index 00000000000000..2c0e62fcb65cbd --- /dev/null +++ b/src/sentry/issues/endpoints/organization_group_search_views.py @@ -0,0 +1,45 @@ +from rest_framework.request import Request +from rest_framework.response import Response + +from sentry.api.api_owners import ApiOwner +from sentry.api.api_publish_status import ApiPublishStatus +from sentry.api.base import region_silo_endpoint +from sentry.api.bases.organization import OrganizationEndpoint, OrganizationPermission +from sentry.api.serializers import serialize +from sentry.api.serializers.models.groupsearchview import GroupSearchViewSerializer +from sentry.models.groupsearchview import GroupSearchView +from sentry.models.organization import Organization + + +class MemberPermission(OrganizationPermission): + scope_map = { + "GET": ["member:read", "member:write"], + "PUT": ["member:read", "member:write"], + } + + +@region_silo_endpoint +class OrganizationGroupSearchViewsEndpoint(OrganizationEndpoint): + publish_status = { + "GET": ApiPublishStatus.EXPERIMENTAL, + "POST": ApiPublishStatus.EXPERIMENTAL, + } + owner = ApiOwner.ISSUES + permission_classes = (MemberPermission,) + + def get(self, request: Request, organization: Organization) -> Response: + """ + List a organization member's custom views + ````````````````````````````````````````` + + Retrieve a list of custom views for a given organization member. + """ + + query = GroupSearchView.objects.filter(organization=organization, user_id=request.user.id) + + return self.paginate( + request=request, + queryset=query, + order_by="position", + on_results=lambda x: serialize(x, request.user, serializer=GroupSearchViewSerializer()), + ) diff --git a/tests/sentry/issues/endpoints/test_organization_group_search_views.py b/tests/sentry/issues/endpoints/test_organization_group_search_views.py new file mode 100644 index 00000000000000..23f84f27e270ab --- /dev/null +++ b/tests/sentry/issues/endpoints/test_organization_group_search_views.py @@ -0,0 +1,84 @@ +from sentry.api.serializers.base import serialize +from sentry.models.groupsearchview import GroupSearchView +from sentry.testutils.cases import APITestCase + + +class OrganizationGroupSearchViewsTest(APITestCase): + endpoint = "sentry-api-0-organization-group-search-views" + + def create_base_data(self): + user_1 = self.user + user_2 = self.create_user() + + self.user_2 = self.create_member(organization=self.organization, user=user_2) + + first_custom_view_user_one = GroupSearchView.objects.create( + name="Custom View One", + organization=self.organization, + user_id=user_1.id, + query="is:unresolved", + query_sort="date", + position=0, + ) + + # This is out of order to test that the endpoint returns the views in the correct order + third_custom_view_user_one = GroupSearchView.objects.create( + name="Custom View Three", + organization=self.organization, + user_id=user_1.id, + query="is:ignored", + query_sort="freq", + position=2, + ) + + second_custom_view_user_one = GroupSearchView.objects.create( + name="Custom View Two", + organization=self.organization, + user_id=user_1.id, + query="is:resolved", + query_sort="new", + position=1, + ) + + first_custom_view_user_two = GroupSearchView.objects.create( + name="Custom View One", + organization=self.organization, + user_id=self.user_2.id, + query="is:unresolved", + query_sort="date", + position=0, + ) + + second_custom_view_user_two = GroupSearchView.objects.create( + name="Custom View Two", + organization=self.organization, + user_id=self.user_2.id, + query="is:resolved", + query_sort="new", + position=1, + ) + + return { + "user_one_views": [ + first_custom_view_user_one, + second_custom_view_user_one, + third_custom_view_user_one, + ], + "user_two_views": [first_custom_view_user_two, second_custom_view_user_two], + } + + def test_get_user_one_custom_views(self): + objs = self.create_base_data() + + self.login_as(self.user) + response = self.get_success_response(self.organization.slug) + + assert response.data == serialize(objs["user_one_views"]) + + def test_get_user_two_custom_views(self): + objs = self.create_base_data() + + self.login_as(self.user_2) + response = self.get_success_response(self.organization.slug) + + assert response.data == serialize(objs["user_two_views"]) From f4a126e44f912d45ce3f368390b32de0ac4f6fe8 Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Mon, 3 Jun 2024 13:41:08 -0700 Subject: [PATCH 02/10] Added url and export --- src/sentry/api/urls.py | 6 ++++++ src/sentry/issues/endpoints/__init__.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/sentry/api/urls.py b/src/sentry/api/urls.py index 50378033204b90..c004989222c1a8 100644 --- a/src/sentry/api/urls.py +++ b/src/sentry/api/urls.py @@ -115,6 +115,7 @@ GroupEventsEndpoint, OrganizationActivityEndpoint, OrganizationGroupIndexEndpoint, + OrganizationGroupSearchViewsEndpoint, OrganizationReleasePreviousCommitsEndpoint, OrganizationSearchesEndpoint, ProjectStacktraceLinkEndpoint, @@ -1703,6 +1704,11 @@ def create_group_urls(name_prefix: str) -> list[URLPattern | URLResolver]: ), name="sentry-api-0-organization-monitor-check-in-attachment", ), + re_path( + r"^(?P[^\/]+)/group-search-views/$", + OrganizationGroupSearchViewsEndpoint.as_view(), + name="sentry-api-0-organization-group-search-views", + ), # Pinned and saved search re_path( r"^(?P[^\/]+)/pinned-searches/$", diff --git a/src/sentry/issues/endpoints/__init__.py b/src/sentry/issues/endpoints/__init__.py index d8f10edf83a16b..811a8ded212ef7 100644 --- a/src/sentry/issues/endpoints/__init__.py +++ b/src/sentry/issues/endpoints/__init__.py @@ -2,6 +2,7 @@ from .group_events import GroupEventsEndpoint from .organization_activity import OrganizationActivityEndpoint from .organization_group_index import OrganizationGroupIndexEndpoint +from .organization_group_search_views import OrganizationGroupSearchViewsEndpoint from .organization_release_previous_commits import OrganizationReleasePreviousCommitsEndpoint from .organization_searches import OrganizationSearchesEndpoint from .project_stacktrace_link import ProjectStacktraceLinkEndpoint @@ -12,6 +13,7 @@ "GroupEventsEndpoint", "OrganizationActivityEndpoint", "OrganizationGroupIndexEndpoint", + "OrganizationGroupSearchViewsEndpoint", "OrganizationReleasePreviousCommitsEndpoint", "OrganizationSearchesEndpoint", "ProjectStacktraceLinkEndpoint", From f078be3a1c32b609e6438b6e7e4fb94a91268383 Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Mon, 3 Jun 2024 14:03:56 -0700 Subject: [PATCH 03/10] Add method to tests --- .../issues/endpoints/test_organization_group_search_views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/sentry/issues/endpoints/test_organization_group_search_views.py b/tests/sentry/issues/endpoints/test_organization_group_search_views.py index 23f84f27e270ab..858a7c5fe23541 100644 --- a/tests/sentry/issues/endpoints/test_organization_group_search_views.py +++ b/tests/sentry/issues/endpoints/test_organization_group_search_views.py @@ -5,6 +5,7 @@ class OrganizationGroupSearchViewsTest(APITestCase): endpoint = "sentry-api-0-organization-group-search-views" + method = "get" def create_base_data(self): user_1 = self.user From 0ab095796eebdd4dc45696685bcf94dc9db5fd44 Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Mon, 3 Jun 2024 14:31:57 -0700 Subject: [PATCH 04/10] Fix broken test --- .../endpoints/test_organization_group_search_views.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/sentry/issues/endpoints/test_organization_group_search_views.py b/tests/sentry/issues/endpoints/test_organization_group_search_views.py index 858a7c5fe23541..637a7746709231 100644 --- a/tests/sentry/issues/endpoints/test_organization_group_search_views.py +++ b/tests/sentry/issues/endpoints/test_organization_group_search_views.py @@ -9,9 +9,9 @@ class OrganizationGroupSearchViewsTest(APITestCase): def create_base_data(self): user_1 = self.user - user_2 = self.create_user() + self.user_2 = self.create_user() - self.user_2 = self.create_member(organization=self.organization, user=user_2) + self.create_member(organization=self.organization, user=self.user_2) first_custom_view_user_one = GroupSearchView.objects.create( name="Custom View One", @@ -71,7 +71,7 @@ def create_base_data(self): def test_get_user_one_custom_views(self): objs = self.create_base_data() - self.login_as(self.user) + self.login_as(user=self.user) response = self.get_success_response(self.organization.slug) assert response.data == serialize(objs["user_one_views"]) @@ -79,7 +79,7 @@ def test_get_user_one_custom_views(self): def test_get_user_two_custom_views(self): objs = self.create_base_data() - self.login_as(self.user_2) + self.login_as(user=self.user_2) response = self.get_success_response(self.organization.slug) assert response.data == serialize(objs["user_two_views"]) From aa9de106f94a2f62f01b77bbbac220c05f9c9749 Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Mon, 3 Jun 2024 15:00:40 -0700 Subject: [PATCH 05/10] Remove references to Put/post endpoint --- src/sentry/issues/endpoints/organization_group_search_views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sentry/issues/endpoints/organization_group_search_views.py b/src/sentry/issues/endpoints/organization_group_search_views.py index 2c0e62fcb65cbd..5cf89911e7c933 100644 --- a/src/sentry/issues/endpoints/organization_group_search_views.py +++ b/src/sentry/issues/endpoints/organization_group_search_views.py @@ -14,7 +14,6 @@ class MemberPermission(OrganizationPermission): scope_map = { "GET": ["member:read", "member:write"], - "PUT": ["member:read", "member:write"], } @@ -22,7 +21,6 @@ class MemberPermission(OrganizationPermission): class OrganizationGroupSearchViewsEndpoint(OrganizationEndpoint): publish_status = { "GET": ApiPublishStatus.EXPERIMENTAL, - "POST": ApiPublishStatus.EXPERIMENTAL, } owner = ApiOwner.ISSUES permission_classes = (MemberPermission,) From 066b6f6dd530097e41459f3dba355c37df6e1ac1 Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Mon, 3 Jun 2024 15:35:29 -0700 Subject: [PATCH 06/10] gate endpoint behind feature flag, add decorator to tests --- .../issues/endpoints/organization_group_search_views.py | 8 ++++++-- .../endpoints/test_organization_group_search_views.py | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/sentry/issues/endpoints/organization_group_search_views.py b/src/sentry/issues/endpoints/organization_group_search_views.py index 5cf89911e7c933..3711f419e7728a 100644 --- a/src/sentry/issues/endpoints/organization_group_search_views.py +++ b/src/sentry/issues/endpoints/organization_group_search_views.py @@ -1,6 +1,8 @@ +from rest_framework import status from rest_framework.request import Request from rest_framework.response import Response +from sentry import features from sentry.api.api_owners import ApiOwner from sentry.api.api_publish_status import ApiPublishStatus from sentry.api.base import region_silo_endpoint @@ -27,11 +29,13 @@ class OrganizationGroupSearchViewsEndpoint(OrganizationEndpoint): def get(self, request: Request, organization: Organization) -> Response: """ - List a organization member's custom views + List the current organization member's custom views ````````````````````````````````````````` - Retrieve a list of custom views for a given organization member. + Retrieve a list of custom views for the current organization member. """ + if not features.has("organizations:issue-stream-custom-views", organization): + return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) query = GroupSearchView.objects.filter(organization=organization, user_id=request.user.id) diff --git a/tests/sentry/issues/endpoints/test_organization_group_search_views.py b/tests/sentry/issues/endpoints/test_organization_group_search_views.py index 637a7746709231..cd472203851daf 100644 --- a/tests/sentry/issues/endpoints/test_organization_group_search_views.py +++ b/tests/sentry/issues/endpoints/test_organization_group_search_views.py @@ -1,6 +1,7 @@ from sentry.api.serializers.base import serialize from sentry.models.groupsearchview import GroupSearchView from sentry.testutils.cases import APITestCase +from sentry.testutils.helpers.features import with_feature class OrganizationGroupSearchViewsTest(APITestCase): @@ -68,6 +69,7 @@ def create_base_data(self): "user_two_views": [first_custom_view_user_two, second_custom_view_user_two], } + @with_feature({"organizations:issue-stream-custom-views": True}) def test_get_user_one_custom_views(self): objs = self.create_base_data() @@ -76,6 +78,7 @@ def test_get_user_one_custom_views(self): assert response.data == serialize(objs["user_one_views"]) + @with_feature({"organizations:issue-stream-custom-views": True}) def test_get_user_two_custom_views(self): objs = self.create_base_data() From a4f03f3251a177ce649379ae9c9f8e1d89c68dde Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Wed, 12 Jun 2024 15:06:21 -0700 Subject: [PATCH 07/10] Return default view if user has none --- .../organization_group_search_views.py | 21 +++++++++++++++++++ .../test_organization_group_search_views.py | 17 +++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/sentry/issues/endpoints/organization_group_search_views.py b/src/sentry/issues/endpoints/organization_group_search_views.py index 3711f419e7728a..2fa8400cd962f5 100644 --- a/src/sentry/issues/endpoints/organization_group_search_views.py +++ b/src/sentry/issues/endpoints/organization_group_search_views.py @@ -7,11 +7,22 @@ from sentry.api.api_publish_status import ApiPublishStatus from sentry.api.base import region_silo_endpoint from sentry.api.bases.organization import OrganizationEndpoint, OrganizationPermission +from sentry.api.paginator import SequencePaginator from sentry.api.serializers import serialize from sentry.api.serializers.models.groupsearchview import GroupSearchViewSerializer from sentry.models.groupsearchview import GroupSearchView from sentry.models.organization import Organization +DEFAULT_VIEWS = [ + { + "id": "", + "name": "Prioritized", + "query": "is:unresolved issue.priority:[high, medium]", + "querySort": "date", + "position": 0, + } +] + class MemberPermission(OrganizationPermission): scope_map = { @@ -39,6 +50,16 @@ def get(self, request: Request, organization: Organization) -> Response: query = GroupSearchView.objects.filter(organization=organization, user_id=request.user.id) + # Return only the prioritized view if user has no custom views yet + if not query.exists(): + return self.paginate( + request=request, + paginator=SequencePaginator( + [(idx, view) for idx, view in enumerate(DEFAULT_VIEWS)] + ), + on_results=lambda results: serialize(results, request.user), + ) + return self.paginate( request=request, queryset=query, diff --git a/tests/sentry/issues/endpoints/test_organization_group_search_views.py b/tests/sentry/issues/endpoints/test_organization_group_search_views.py index cd472203851daf..609597f8ad5a10 100644 --- a/tests/sentry/issues/endpoints/test_organization_group_search_views.py +++ b/tests/sentry/issues/endpoints/test_organization_group_search_views.py @@ -11,8 +11,10 @@ class OrganizationGroupSearchViewsTest(APITestCase): def create_base_data(self): user_1 = self.user self.user_2 = self.create_user() + self.user_3 = self.create_user() self.create_member(organization=self.organization, user=self.user_2) + self.create_member(organization=self.organization, user=self.user_3) first_custom_view_user_one = GroupSearchView.objects.create( name="Custom View One", @@ -86,3 +88,18 @@ def test_get_user_two_custom_views(self): response = self.get_success_response(self.organization.slug) assert response.data == serialize(objs["user_two_views"]) + + @with_feature({"organizations:issue-stream-custom-views": True}) + def test_get_default_views(self): + self.create_base_data() + + self.login_as(user=self.user_3) + response = self.get_success_response(self.organization.slug) + assert len(response.data) == 1 + + view = response.data[0] + + assert view["name"] == "Prioritized" + assert view["query"] == "is:unresolved issue.priority:[high, medium]" + assert view["querySort"] == "date" + assert view["position"] == 0 From 2ec387c8ff14419bbc9f7d161fb35a03205672c5 Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Wed, 12 Jun 2024 15:24:09 -0700 Subject: [PATCH 08/10] Return 404 if no flag --- src/sentry/issues/endpoints/organization_group_search_views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sentry/issues/endpoints/organization_group_search_views.py b/src/sentry/issues/endpoints/organization_group_search_views.py index 2fa8400cd962f5..a150a3a0e1b0e5 100644 --- a/src/sentry/issues/endpoints/organization_group_search_views.py +++ b/src/sentry/issues/endpoints/organization_group_search_views.py @@ -46,7 +46,7 @@ def get(self, request: Request, organization: Organization) -> Response: Retrieve a list of custom views for the current organization member. """ if not features.has("organizations:issue-stream-custom-views", organization): - return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) + return Response(status=status.HTTP_404_NOT_FOUND) query = GroupSearchView.objects.filter(organization=organization, user_id=request.user.id) From 99d35cb7da4d39098f7540ab78b63232e5a8f099 Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Wed, 12 Jun 2024 16:39:46 -0700 Subject: [PATCH 09/10] better typing --- .../api/serializers/models/groupsearchview.py | 15 ++++++++++++++- .../endpoints/organization_group_search_views.py | 9 ++++++--- src/sentry/models/savedsearch.py | 8 ++++++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/sentry/api/serializers/models/groupsearchview.py b/src/sentry/api/serializers/models/groupsearchview.py index ccec673ee935b0..3aee2df02c1f08 100644 --- a/src/sentry/api/serializers/models/groupsearchview.py +++ b/src/sentry/api/serializers/models/groupsearchview.py @@ -1,10 +1,23 @@ +from typing import TypedDict + from sentry.api.serializers import Serializer, register from sentry.models.groupsearchview import GroupSearchView +from sentry.models.savedsearch import SORT_LITERALS + + +class View(TypedDict): + id: str + name: str + query: str + querySort: SORT_LITERALS + position: int + dateCreated: str | None + dateUpdated: str | None @register(GroupSearchView) class GroupSearchViewSerializer(Serializer): - def serialize(self, obj, attrs, user): + def serialize(self, obj, attrs, user) -> View: return { "id": str(obj.id), "name": obj.name, diff --git a/src/sentry/issues/endpoints/organization_group_search_views.py b/src/sentry/issues/endpoints/organization_group_search_views.py index a150a3a0e1b0e5..1ff0bc0b741e95 100644 --- a/src/sentry/issues/endpoints/organization_group_search_views.py +++ b/src/sentry/issues/endpoints/organization_group_search_views.py @@ -9,17 +9,20 @@ from sentry.api.bases.organization import OrganizationEndpoint, OrganizationPermission from sentry.api.paginator import SequencePaginator from sentry.api.serializers import serialize -from sentry.api.serializers.models.groupsearchview import GroupSearchViewSerializer +from sentry.api.serializers.models.groupsearchview import GroupSearchViewSerializer, View from sentry.models.groupsearchview import GroupSearchView from sentry.models.organization import Organization +from sentry.models.savedsearch import SortOptions -DEFAULT_VIEWS = [ +DEFAULT_VIEWS: list[View] = [ { "id": "", "name": "Prioritized", "query": "is:unresolved issue.priority:[high, medium]", - "querySort": "date", + "querySort": SortOptions.DATE.value, "position": 0, + "dateCreated": None, + "dateUpdated": None, } ] diff --git a/src/sentry/models/savedsearch.py b/src/sentry/models/savedsearch.py index 46df52d80d933d..40d6cc387e5caa 100644 --- a/src/sentry/models/savedsearch.py +++ b/src/sentry/models/savedsearch.py @@ -1,4 +1,5 @@ -from typing import Any +from enum import StrEnum +from typing import Any, Literal from django.db import models from django.db.models import Q, UniqueConstraint @@ -14,7 +15,7 @@ from sentry.models.search_common import SearchType -class SortOptions: +class SortOptions(StrEnum): DATE = "date" NEW = "new" TRENDS = "trends" @@ -34,6 +35,9 @@ def as_choices(cls): ) +SORT_LITERALS = Literal["date", "new", "trends", "freq", "user", "inbox"] + + class Visibility: ORGANIZATION = "organization" OWNER = "owner" From 94d7a723bf03e4d842525cea58b58f8aaca2528b Mon Sep 17 00:00:00 2001 From: MichaelSun48 Date: Thu, 13 Jun 2024 10:20:23 -0700 Subject: [PATCH 10/10] Change serialize return type, make type descriptions better --- src/sentry/api/serializers/models/groupsearchview.py | 4 ++-- .../issues/endpoints/organization_group_search_views.py | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/sentry/api/serializers/models/groupsearchview.py b/src/sentry/api/serializers/models/groupsearchview.py index 3aee2df02c1f08..ff97c11e9ac784 100644 --- a/src/sentry/api/serializers/models/groupsearchview.py +++ b/src/sentry/api/serializers/models/groupsearchview.py @@ -5,7 +5,7 @@ from sentry.models.savedsearch import SORT_LITERALS -class View(TypedDict): +class GroupSearchViewSerializerResponse(TypedDict): id: str name: str query: str @@ -17,7 +17,7 @@ class View(TypedDict): @register(GroupSearchView) class GroupSearchViewSerializer(Serializer): - def serialize(self, obj, attrs, user) -> View: + def serialize(self, obj, attrs, user, **kwargs) -> GroupSearchViewSerializerResponse: return { "id": str(obj.id), "name": obj.name, diff --git a/src/sentry/issues/endpoints/organization_group_search_views.py b/src/sentry/issues/endpoints/organization_group_search_views.py index 1ff0bc0b741e95..ceefe5a914124f 100644 --- a/src/sentry/issues/endpoints/organization_group_search_views.py +++ b/src/sentry/issues/endpoints/organization_group_search_views.py @@ -9,12 +9,15 @@ from sentry.api.bases.organization import OrganizationEndpoint, OrganizationPermission from sentry.api.paginator import SequencePaginator from sentry.api.serializers import serialize -from sentry.api.serializers.models.groupsearchview import GroupSearchViewSerializer, View +from sentry.api.serializers.models.groupsearchview import ( + GroupSearchViewSerializer, + GroupSearchViewSerializerResponse, +) from sentry.models.groupsearchview import GroupSearchView from sentry.models.organization import Organization from sentry.models.savedsearch import SortOptions -DEFAULT_VIEWS: list[View] = [ +DEFAULT_VIEWS: list[GroupSearchViewSerializerResponse] = [ { "id": "", "name": "Prioritized",