From fe38a72664ba6aaef4d8a963fd41f29fb331921b Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Wed, 15 Jan 2025 16:00:14 +0100 Subject: [PATCH] Add logic to load focused group members --- src/sidebar/services/api.ts | 23 ++++++++++++++++++ src/sidebar/services/groups.ts | 44 +++++++++++++++++++++++++++++++++- src/types/api.ts | 20 ++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/sidebar/services/api.ts b/src/sidebar/services/api.ts index 7d3cc97bd0d..59a049f2892 100644 --- a/src/sidebar/services/api.ts +++ b/src/sidebar/services/api.ts @@ -4,6 +4,7 @@ import type { RouteMap, RouteMetadata, Profile, + GroupMembers, } from '../../types/api'; import { stripInternalProperties } from '../helpers/strip-internal-properties'; import type { SidebarStore } from '../store'; @@ -218,6 +219,17 @@ export class APIService { member: { delete: APICall<{ pubid: string; userid: string }>; }; + members: { + read: APICall< + { + pubid: string; + 'page[number]'?: number; + 'page[size]'?: number; + }, + void, + GroupMembers + >; + }; read: APICall<{ id: string; expand: string[] }, void, Group>; }; groups: { @@ -287,6 +299,17 @@ export class APIService { userid: string; }>, }, + members: { + read: apiCall('group.members.read') as APICall< + { + pubid: string; + 'page[number]'?: number; + 'page[size]'?: number; + }, + void, + GroupMembers + >, + }, read: apiCall('group.read') as APICall< { id: string; expand: string[] }, void, diff --git a/src/sidebar/services/groups.ts b/src/sidebar/services/groups.ts index bedfb667b55..a88dd23269b 100644 --- a/src/sidebar/services/groups.ts +++ b/src/sidebar/services/groups.ts @@ -2,7 +2,7 @@ import shallowEqual from 'shallowequal'; // @ts-ignore - TS doesn't know about SVG files. import { default as logo } from '../../images/icons/logo.svg'; -import type { Group } from '../../types/api'; +import type { Group, GroupMember, GroupMembers } from '../../types/api'; import type { SidebarSettings } from '../../types/config'; import type { Service } from '../../types/config'; import { serviceConfig } from '../config/service-config'; @@ -478,4 +478,46 @@ export class GroupsService { userid: 'me', }); } + + /** + * Fetch members for focused group from the API and load them into the store. + */ + async loadMembers(): Promise { + const groupId = this._store.focusedGroupId(); + if (!groupId) { + throw new Error('A group is not focused yet'); + } + + const members = await this._fetchAllMembers(groupId); + + return members; + } + + private async _fetchAllMembers(groupId: string): Promise { + // Fetch first page of members, to determine how many more pages there are + const firstPage = await this._fetchMembers(groupId); + const remainingMembers = firstPage.meta.page.total - 100; + let members = firstPage.data; + + if (remainingMembers <= 0) { + return members; + } + + const pages = Math.ceil(remainingMembers / 100); + for (let i = 1; i < pages; i++) { + // TODO Consider parallelizing requests + const groupMembers = await this._fetchMembers(groupId, i + 1); + members = members.concat(groupMembers.data); + } + + return members; + } + + private _fetchMembers(groupId: string, page = 1): Promise { + return this._api.group.members.read({ + pubid: groupId, + 'page[number]': page, + 'page[size]': 100, + }); + } } diff --git a/src/types/api.ts b/src/types/api.ts index 60f7895f554..637f9d634fc 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -294,6 +294,26 @@ export type Group = { */ export type GroupIdentifier = NonNullable; +export type GroupMember = { + authority: string; + userid: string; + username: string; + display_name: string; + roles: string[]; + actions: string[]; + created: string; + updated: string; +}; + +export type GroupMembers = { + meta: { + page: { + total: number; + }; + }; + data: GroupMember[]; +}; + /** * Query parameters for an `/api/search` API call. *