13
13
from sentry .api .helpers .group_index .validators import ValidationError
14
14
from sentry .api .paginator import SequencePaginator
15
15
from sentry .api .serializers import serialize
16
- from sentry .api .serializers .models .groupsearchview import (
17
- GroupSearchViewSerializer ,
18
- GroupSearchViewStarredSerializer ,
19
- )
16
+ from sentry .api .serializers .models .groupsearchview import GroupSearchViewStarredSerializer
20
17
from sentry .api .serializers .rest_framework .groupsearchview import (
21
18
GroupSearchViewValidator ,
22
19
GroupSearchViewValidatorResponse ,
23
20
)
24
21
from sentry .models .groupsearchview import DEFAULT_TIME_FILTER , GroupSearchView
22
+ from sentry .models .groupsearchviewlastvisited import GroupSearchViewLastVisited
25
23
from sentry .models .groupsearchviewstarred import GroupSearchViewStarred
26
24
from sentry .models .organization import Organization
27
25
from sentry .models .project import Project
@@ -157,7 +155,9 @@ def put(self, request: Request, organization: Organization) -> Response:
157
155
158
156
try :
159
157
with transaction .atomic (using = router .db_for_write (GroupSearchView )):
160
- bulk_update_views (organization , request .user .id , validated_data ["views" ])
158
+ new_view_state = bulk_update_views (
159
+ organization , request .user .id , validated_data ["views" ]
160
+ )
161
161
except IntegrityError as e :
162
162
if (
163
163
len (e .args ) > 0
@@ -171,13 +171,38 @@ def put(self, request: Request, organization: Organization) -> Response:
171
171
)
172
172
return Response (status = status .HTTP_500_INTERNAL_SERVER_ERROR )
173
173
174
- query = GroupSearchView .objects .filter (organization = organization , user_id = request .user .id )
174
+ last_visited_views = GroupSearchViewLastVisited .objects .filter (
175
+ organization = organization ,
176
+ user_id = request .user .id ,
177
+ group_search_view_id__in = [view .id for view in new_view_state ],
178
+ )
179
+ last_visited_map = {lv .group_search_view_id : lv for lv in last_visited_views }
175
180
176
181
return self .paginate (
177
182
request = request ,
178
- queryset = query ,
179
- order_by = "position" ,
180
- on_results = lambda x : serialize (x , request .user , serializer = GroupSearchViewSerializer ()),
183
+ paginator = SequencePaginator (
184
+ [
185
+ (
186
+ idx ,
187
+ {
188
+ "id" : str (view .id ),
189
+ "name" : view .name ,
190
+ "query" : view .query ,
191
+ "querySort" : view .query_sort ,
192
+ "projects" : list (view .projects .values_list ("id" , flat = True )),
193
+ "isAllProjects" : view .is_all_projects ,
194
+ "environments" : view .environments ,
195
+ "timeFilters" : view .time_filters ,
196
+ "dateCreated" : view .date_added ,
197
+ "dateUpdated" : view .date_updated ,
198
+ "lastVisited" : last_visited_map .get (view .id , None ),
199
+ "position" : idx ,
200
+ },
201
+ )
202
+ for idx , view in enumerate (new_view_state )
203
+ ]
204
+ ),
205
+ on_results = lambda results : serialize (results , request .user ),
181
206
)
182
207
183
208
@@ -198,16 +223,18 @@ def validate_projects(
198
223
199
224
def bulk_update_views (
200
225
org : Organization , user_id : int , views : list [GroupSearchViewValidatorResponse ]
201
- ) -> None :
226
+ ) -> list [ GroupSearchView ] :
202
227
existing_view_ids = [view ["id" ] for view in views if "id" in view ]
203
228
204
229
_delete_missing_views (org , user_id , view_ids_to_keep = existing_view_ids )
205
-
230
+ created_views = []
206
231
for idx , view in enumerate (views ):
207
232
if "id" not in view :
208
- _create_view (org , user_id , view , position = idx )
233
+ created_views . append ( _create_view (org , user_id , view , position = idx ) )
209
234
else :
210
- _update_existing_view (org , user_id , view , position = idx )
235
+ created_views .append (_update_existing_view (org , user_id , view , position = idx ))
236
+
237
+ return created_views
211
238
212
239
213
240
def pick_default_project (org : Organization , user : User | AnonymousUser ) -> int | None :
@@ -230,7 +257,7 @@ def _delete_missing_views(org: Organization, user_id: int, view_ids_to_keep: lis
230
257
231
258
def _update_existing_view (
232
259
org : Organization , user_id : int , view : GroupSearchViewValidatorResponse , position : int
233
- ) -> None :
260
+ ) -> GroupSearchView :
234
261
try :
235
262
gsv = GroupSearchView .objects .get (id = view ["id" ], user_id = user_id )
236
263
gsv .name = view ["name" ]
@@ -255,17 +282,18 @@ def _update_existing_view(
255
282
group_search_view = gsv ,
256
283
defaults = {"position" : position },
257
284
)
285
+ return gsv
258
286
except GroupSearchView .DoesNotExist :
259
287
# It is possible – though unlikely under normal circumstances – for a view to come in that
260
288
# doesn't exist anymore. If, for example, the user has the issue stream open in separate
261
289
# windows, deletes a view in one window, then updates it in the other before refreshing.
262
290
# In this case, we decide to recreate the tab instead of leaving it deleted.
263
- _create_view (org , user_id , view , position )
291
+ return _create_view (org , user_id , view , position )
264
292
265
293
266
294
def _create_view (
267
295
org : Organization , user_id : int , view : GroupSearchViewValidatorResponse , position : int
268
- ) -> None :
296
+ ) -> GroupSearchView :
269
297
gsv = GroupSearchView .objects .create (
270
298
organization = org ,
271
299
user_id = user_id ,
@@ -286,3 +314,4 @@ def _create_view(
286
314
group_search_view = gsv ,
287
315
position = position ,
288
316
)
317
+ return gsv
0 commit comments