-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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(shared-views): Add groupsearchview starred endpoint for reordering #87347
feat(shared-views): Add groupsearchview starred endpoint for reordering #87347
Conversation
Codecov ReportAttention: Patch coverage is ✅ All tests successful. No failed tests found.
Additional details and impacted files@@ Coverage Diff @@
## master #87347 +/- ##
===========================================
+ Coverage 33.16% 87.75% +54.58%
===========================================
Files 8358 9881 +1523
Lines 466166 560388 +94222
Branches 22076 22075 -1
===========================================
+ Hits 154616 491745 +337129
+ Misses 311146 68239 -242907
Partials 404 404 |
try: | ||
gsvs = GroupSearchView.objects.filter( | ||
organization=self.context["organization"], id__in=view_ids | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could use .values(...)
here to make the query a bit more efficient by returning less data.
it is also probably good to do validation here that all the gsvs exist. that is, check the length of view_ids against the returned query.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh i guess it not existing is valid input, since we create it below
src/sentry/issues/endpoints/organization_group_search_view_starred_order.py
Outdated
Show resolved
Hide resolved
return Response(status=status.HTTP_204_NO_CONTENT) | ||
|
||
|
||
def _update_view_positions(organization: Organization, user_id: int, view_positions: list[int]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method might make sense to live on the object manager of GroupSearchViewStarred
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, but I don't want to add that abstraction if this will be the only place that uses this functionality, which I suspect will be the case. I'll definitely keep the model managers abstraction in mind in the future though, i agree they can be very useful.
starred_view.group_search_view_id: starred_view for starred_view in existing_starred_views | ||
} | ||
|
||
for idx, view_id in enumerate(view_positions): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at some point we'll probably want to do bulk operations instead of creating / updating one by one, as if you have 100+ views this could end up being a bit slow. on a related note, is there a cap to how many starred views someone could have?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PUT
groupsearchview
endpoint enforces a max of 50 views, which I think should be well below the threshold at which this would cause slowdowns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
worth thinking about what is considered "fast" or "snappy" and can observe endpoint to make sure it's within parameters after releasing!
src/sentry/issues/endpoints/organization_group_search_view_starred_order.py
Outdated
Show resolved
Hide resolved
existing_starred_views_dict[view_id].save() | ||
else: | ||
try: | ||
GroupSearchViewStarred.objects.create( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding rows here seems unexpected. If I reorder some starred views I wouldn't want to star anything due to that action. IMO in this case we should either respond with a 400 or filter out the starred rows that don't exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reordering your starred views shouldn't cause this create to fire. This would only fire if someone an existing view is starred.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO reordering and starring/unstarring should be handled in separate endpoints. I think that what you've written here is great for reordering, but I'd rather have a separate endpoint that just stars/unstars a single view at a time (for a couple reasons):
- The frontend may want to star/unstar a view from a page where we don't have the full list of starred views available
- When reordering, you may be coming back to a tab where you can out of date data (for example, maybe you unstarred something in one tab, then went back to an old tab). If you reorder the views in this state, it would re-star views that you previously unstarred
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not saying I totally disagree with you or that I'm adamant about keeping it this way (I could actually see a world where we have both endpoints), but to your two points:
-
When would this happen, realistically? I imagined that starred views would be among the first things the frontend fetches, at least when visiting Issues. And I can't think of a place outside of Issues where you would star/unstar an Issue view, especially without context into what views are already starred.
-
To me at least, this seems like the expected behavior — if we only allow reordering, we'd have to probably throw an error if the list of
view_id
s doesn't match the list of already starred views. So in your secnario, if you reorder a stale view state in a separate browser tab, we'd probably have to revert the reorder and display an error message, which seems unexpected. Similar to the old PUT/group-search-view/
endpoint, I feel like this endpoint should be pretty forgiving.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- You're right that in the current world we will always be starring/unstarring in places where the views should already be fetched. Ergonomically, it would be better though if clicking a star icon you could just call POST
/views/<view_id/star
and not need to grab the rest of the starred items from the cache (and need to assume that the data is not stale). It's also good to design APIs for usages you can't yet anticipate and not require additional information. - The reason that we made the old endpoint so forgiving was that we allowed the user to do things like rename, new tab, reorder, etc all without waiting for the previous request to complete. This isn't as necessary for the new experience since you can only star/unstar and reorder (and we could put a loading state on star/unstar). I do agree that throwing an error would be a bad experience, but we could probably mitigate that by only throwing the error when there is no way to assume the correct ordering (and in that case doing an immediate refetch).
I think my stance would be that we should at the very least add a "dumb" star/unstar endpoint (in a separate PR of course). I think locking down this endpoint to only ordering would overall save users from some unexpected behavior, but it's not the worst thing either
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, I do agree that needing every other starred views' id to simply star a view is a bad api design, even if we can get away with it for now. I'll update this to just reorder in that case, thanks for the discussion and helping me think through this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for being so receptive to feedback! Looks great 💯
self, organization: Organization, user_id: int, new_view_positions: list[int] | ||
): | ||
""" | ||
Reorders the positions of starred views for a user in an organization. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice explanatory comment!
@@ -61,33 +61,14 @@ def put(self, request: Request, organization: Organization) -> Response: | |||
|
|||
try: | |||
with transaction.atomic(using=router.db_for_write(GroupSearchViewStarred)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I wonder if this transaction is necessary anymore since we are just doing a single bulk update
b4a786c
to
34d48df
Compare
…rred_order.py Co-authored-by: Josh Ferge <[email protected]>
34d48df
to
903e82e
Compare
This PR adds the
PUT
/group-search-views-starred-order/
endpoint.This endpoint is akin to a pared down version of the old
PUT
/group-search-views/
endpoint, which used to bulk update every aspect of the view, including filter parameters like query, sort, and projects. This new endpoint no longer handles any filter parameter changes (that will be delegated to aPUT
/group-search-views/:viewId
endpoint), but does handle bulk adding, removing, and reordering starred views.The logic at a high level is: