-
Notifications
You must be signed in to change notification settings - Fork 201
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
Add logic to load focused group members #6756
base: main
Are you sure you want to change the base?
Conversation
fe38a72
to
1054a69
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #6756 +/- ##
=======================================
Coverage 99.43% 99.43%
=======================================
Files 270 270
Lines 10235 10267 +32
Branches 2447 2455 +8
=======================================
+ Hits 10177 10209 +32
Misses 58 58 ☔ View full report in Codecov by Sentry. |
fc1e41b
to
4bac1dc
Compare
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.
I took an initial pass over this. A few notes:
- I think we should defer fetching group members until either the point they are needed or shortly before (eg. when beginning to edit). That way we avoid these requests in sessions where no annotation editing happens. I think we could assume that any time an annotation is edited, the user may have need for at-mentions.
- Open groups can have members in the data model. We just haven't finished the work within h to enable non-admin users to invite them yet. Even though membership isn't needed to write in these groups, they will still be able to have members who are moderators. In general I think it would be a good idea to minimize the amount of special-casing we do for different group types, as this is liable to get out of date as Hypothesis group functionality evolves.
- Make sure we handle the case where the focused group is changed while group members are being fetched
|
||
if ( | ||
// For now, group members are going to be used for at-mentions only, so we | ||
// can skip loading them if the feature is not enabled |
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 feature flag is just a temporary measure in development. We plan to ship a version of this where the flag is enabled for everyone. At that point we'll be fetching group members regardless of whether the user edits any annotations in the session.
* Fetch members for focused group from the API and load them into the store. | ||
*/ | ||
private async _loadFocusedGroupMembers(groupId: string): Promise<void> { | ||
// Open groups do not have members, so we can save the API calls |
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.
All group types can have members in the data model. There isn't a way for the owner of an open group to invite members to join yet, but the intent is that will be added.
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.
Good. Then I'll simplify it so that the call is always done. If an empty list is returned for whatever reason, so be it.
this._store.isFeatureEnabled('at_mentions') && | ||
this._store.getFocusedGroupMembers() === null | ||
) { | ||
this._loadFocusedGroupMembers(groupId).catch(e => console.error(e)); |
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 starts an async process to fetch focused group members, but this request is not canceled if the focused group is changed while it is in-flight. In general, code for dealing with async requests should assume:
- Requests can take an arbitrary amount of time (up to any explicit timeout)
- Requests may not finish in the order they are started
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.
Yeah, good point.
} | ||
|
||
private async _fetchAllMembers(groupId: string): Promise<GroupMember[]> { | ||
// Fetch first page of members, to determine how many more pages there are |
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.
There is a race condition here that if group members are added while we are paging through, we will end up with duplicates. Unlikely, but possible in principle.
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.
True. Something similar could happen if a member that's already fetched in a previous page is removed. That could cause a member from a subsequent page to not be fetched since it has moved a position "up" and is now part of a page which is supposedly fetched already.
None of these issues are easy to handle with current API contract though, where pagination is not done via cursor, but good to have in mind.
@@ -18,12 +18,16 @@ export type State = { | |||
groups: Group[]; | |||
/** ID of currently selected group. */ | |||
focusedGroupId: string | null; | |||
|
|||
/** Members of currently selected group */ | |||
focusedGroupMembers: GroupMember[] | null; |
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.
Since only members for the current group are stored, this means we'll be reloading members each time you switch back and forth. That's OK to start with, as long as we ensure that this is cleared and in-flight requests are canceled when switching groups, but in future we might want to cache members from groups you've selected in the current session.
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.
I'd prefer not to do client-side caching for now, as it could lead to things changing in the server and having to find a way to invalidate the cache remotely, or risk having outdated lists of users until you reload.
For annotations we do not do caching, for example. Every time the group changes we fetch all annotations for that group. Although it's true that group members will usually change less frequently than annotations, and annotations are loaded in one go.
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.
That's fine, we can skip caching for an initial implementation.
4bac1dc
to
3616880
Compare
Thanks! I'll do the changes. |
3616880
to
5b4b46c
Compare
Implement logic to call members API for focused group, and load all its members in the store.
The loaded members are not used yet. They will be used in a follow-up PR to improve the at-mentions suggestions when focused group is not a public group.
Considerations
The group members API is paginated, so we load members in batches. This has two implications:
I'll try to check some real numbers of groups in production, to adjust this based on that.
We could probably parallelize these calls, loading 3 or 4 pages at a time. I'll explore this option separately, once I have the numbers.
Test steps
at_mentions
feature in http://localhost:5000/admin/features