Network metrics (#8390)
* Network metrics * update network-client ref * fix unit tests * missing catch error parsing * add client tracking unit tests * fix typos
This commit is contained in:
parent
640ff93e01
commit
fb57c423c7
47 changed files with 945 additions and 466 deletions
|
|
@ -376,12 +376,12 @@ export async function fetchChannelCreator(serverUrl: string, channelId: string,
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchChannelStats(serverUrl: string, channelId: string, fetchOnly = false) {
|
||||
export async function fetchChannelStats(serverUrl: string, channelId: string, fetchOnly = false, groupLabel?: string) {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const stats = await client.getChannelStats(channelId);
|
||||
const stats = await client.getChannelStats(channelId, groupLabel);
|
||||
if (!fetchOnly) {
|
||||
const channel = await getChannelById(database, channelId);
|
||||
if (channel) {
|
||||
|
|
@ -404,7 +404,11 @@ export async function fetchChannelStats(serverUrl: string, channelId: string, fe
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchMyChannelsForTeam(serverUrl: string, teamId: string, includeDeleted = true, since = 0, fetchOnly = false, excludeDirect = false, isCRTEnabled?: boolean): Promise<MyChannelsRequest> {
|
||||
export async function fetchMyChannelsForTeam(
|
||||
serverUrl: string, teamId: string, includeDeleted = true,
|
||||
since = 0, fetchOnly = false, excludeDirect = false,
|
||||
isCRTEnabled?: boolean, groupLabel?: string,
|
||||
): Promise<MyChannelsRequest> {
|
||||
try {
|
||||
if (!fetchOnly) {
|
||||
setTeamLoading(serverUrl, true);
|
||||
|
|
@ -412,9 +416,9 @@ export async function fetchMyChannelsForTeam(serverUrl: string, teamId: string,
|
|||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const [allChannels, channelMemberships, categoriesWithOrder] = await Promise.all([
|
||||
client.getMyChannels(teamId, includeDeleted, since),
|
||||
client.getMyChannelMembers(teamId),
|
||||
client.getCategories('me', teamId),
|
||||
client.getMyChannels(teamId, includeDeleted, since, groupLabel),
|
||||
client.getMyChannelMembers(teamId, groupLabel),
|
||||
client.getCategories('me', teamId, groupLabel),
|
||||
]);
|
||||
|
||||
let channels = allChannels;
|
||||
|
|
@ -453,13 +457,13 @@ export async function fetchMyChannelsForTeam(serverUrl: string, teamId: string,
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchMyChannel(serverUrl: string, teamId: string, channelId: string, fetchOnly = false): Promise<MyChannelsRequest> {
|
||||
export async function fetchMyChannel(serverUrl: string, teamId: string, channelId: string, fetchOnly = false, groupLabel?: string): Promise<MyChannelsRequest> {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
|
||||
const [channel, member] = await Promise.all([
|
||||
client.getChannel(channelId),
|
||||
client.getChannelMember(channelId, 'me'),
|
||||
client.getChannel(channelId, groupLabel),
|
||||
client.getChannelMember(channelId, 'me', groupLabel),
|
||||
]);
|
||||
|
||||
if (!fetchOnly) {
|
||||
|
|
@ -477,7 +481,11 @@ export async function fetchMyChannel(serverUrl: string, teamId: string, channelI
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchMissingDirectChannelsInfo(serverUrl: string, directChannels: Channel[], locale?: string, teammateDisplayNameSetting?: string, currentUserId?: string, fetchOnly = false) {
|
||||
export async function fetchMissingDirectChannelsInfo(
|
||||
serverUrl: string, directChannels: Channel[], locale?: string,
|
||||
teammateDisplayNameSetting?: string, currentUserId?: string,
|
||||
fetchOnly = false, groupLabel?: string,
|
||||
) {
|
||||
try {
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const displayNameByChannel: Record<string, string> = {};
|
||||
|
|
@ -510,8 +518,8 @@ export async function fetchMissingDirectChannelsInfo(serverUrl: string, directCh
|
|||
const membersCount = await getMembersCountByChannelsId(database, dmIds);
|
||||
const profileChannelsToFetch = dmIds.filter((id) => membersCount[id] <= 1 && dmWithoutDisplayName.has(id));
|
||||
const results = await Promise.all([
|
||||
profileChannelsToFetch.length ? fetchProfilesPerChannels(serverUrl, profileChannelsToFetch, currentUserId, false) : Promise.resolve({data: undefined}),
|
||||
fetchProfilesInGroupChannels(serverUrl, gms.map((c) => c.id), false),
|
||||
profileChannelsToFetch.length ? fetchProfilesPerChannels(serverUrl, profileChannelsToFetch, currentUserId, false, groupLabel) : Promise.resolve({data: undefined}),
|
||||
fetchProfilesInGroupChannels(serverUrl, gms.map((c) => c.id), false, groupLabel),
|
||||
]);
|
||||
|
||||
const profileRequests = results.flat();
|
||||
|
|
@ -654,10 +662,10 @@ export async function joinChannelIfNeeded(serverUrl: string, channelId: string)
|
|||
}
|
||||
}
|
||||
|
||||
export async function markChannelAsRead(serverUrl: string, channelId: string, updateLocal = false) {
|
||||
export async function markChannelAsRead(serverUrl: string, channelId: string, updateLocal = false, groupLabel?: string) {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
await client.viewMyChannel(channelId);
|
||||
await client.viewMyChannel(channelId, undefined, groupLabel);
|
||||
|
||||
if (updateLocal) {
|
||||
await markChannelAsViewed(serverUrl, channelId, true);
|
||||
|
|
@ -1039,7 +1047,7 @@ export async function getChannelTimezones(serverUrl: string, channelId: string)
|
|||
}
|
||||
}
|
||||
|
||||
export async function switchToChannelById(serverUrl: string, channelId: string, teamId?: string, skipLastUnread = false) {
|
||||
export async function switchToChannelById(serverUrl: string, channelId: string, teamId?: string, skipLastUnread = false, groupLabel?: string) {
|
||||
if (channelId === Screens.GLOBAL_THREADS) {
|
||||
return switchToGlobalThreads(serverUrl, teamId);
|
||||
}
|
||||
|
|
@ -1051,18 +1059,18 @@ export async function switchToChannelById(serverUrl: string, channelId: string,
|
|||
|
||||
DeviceEventEmitter.emit(Events.CHANNEL_SWITCH, true);
|
||||
|
||||
fetchPostsForChannel(serverUrl, channelId);
|
||||
fetchChannelBookmarks(serverUrl, channelId);
|
||||
fetchPostsForChannel(serverUrl, channelId, false, groupLabel);
|
||||
fetchChannelBookmarks(serverUrl, channelId, false, groupLabel);
|
||||
await switchToChannel(serverUrl, channelId, teamId, skipLastUnread);
|
||||
openChannelIfNeeded(serverUrl, channelId);
|
||||
markChannelAsRead(serverUrl, channelId);
|
||||
fetchChannelStats(serverUrl, channelId);
|
||||
fetchGroupsForChannelIfConstrained(serverUrl, channelId);
|
||||
openChannelIfNeeded(serverUrl, channelId, groupLabel);
|
||||
markChannelAsRead(serverUrl, channelId, false, groupLabel);
|
||||
fetchChannelStats(serverUrl, channelId, false, groupLabel);
|
||||
fetchGroupsForChannelIfConstrained(serverUrl, channelId, false, groupLabel);
|
||||
|
||||
DeviceEventEmitter.emit(Events.CHANNEL_SWITCH, false);
|
||||
|
||||
if (await AppsManager.isAppsEnabled(serverUrl)) {
|
||||
AppsManager.fetchBindings(serverUrl, channelId);
|
||||
AppsManager.fetchBindings(serverUrl, channelId, false, groupLabel);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {logError} from '@utils/log';
|
|||
|
||||
import {forceLogoutIfNecessary} from './session';
|
||||
|
||||
export async function fetchChannelBookmarks(serverUrl: string, channelId: string, fetchOnly = false) {
|
||||
export async function fetchChannelBookmarks(serverUrl: string, channelId: string, fetchOnly = false, groupLabel?: string) {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
|
@ -22,7 +22,7 @@ export async function fetchChannelBookmarks(serverUrl: string, channelId: string
|
|||
}
|
||||
|
||||
const since = await getBookmarksSince(database, channelId);
|
||||
const bookmarks = await client.getChannelBookmarksForChannel(channelId, since);
|
||||
const bookmarks = await client.getChannelBookmarksForChannel(channelId, since, groupLabel);
|
||||
|
||||
if (!fetchOnly && bookmarks.length) {
|
||||
await operator.handleChannelBookmark({bookmarks, prepareRecordsOnly: false});
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export async function appEntry(serverUrl: string, since = 0) {
|
|||
await operator.batchRecords(removeLastUnreadChannelId, 'appEntry - removeLastUnreadChannelId');
|
||||
}
|
||||
|
||||
WebsocketManager.openAll();
|
||||
WebsocketManager.openAll('entry');
|
||||
|
||||
verifyPushProxy(serverUrl);
|
||||
|
||||
|
|
|
|||
|
|
@ -66,14 +66,14 @@ export type EntryResponse = {
|
|||
error: unknown;
|
||||
}
|
||||
|
||||
export const entry = async (serverUrl: string, teamId?: string, channelId?: string, since = 0): Promise<EntryResponse> => {
|
||||
export const entry = async (serverUrl: string, teamId?: string, channelId?: string, since = 0, groupLabel?: string): Promise<EntryResponse> => {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const result = entryRest(serverUrl, teamId, channelId, since);
|
||||
const result = entryRest(serverUrl, teamId, channelId, since, groupLabel);
|
||||
|
||||
// Fetch data retention policies
|
||||
const isDataRetentionEnabled = await getIsDataRetentionEnabled(database);
|
||||
if (isDataRetentionEnabled) {
|
||||
fetchDataRetentionPolicy(serverUrl);
|
||||
fetchDataRetentionPolicy(serverUrl, false, groupLabel);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -82,10 +82,17 @@ export const entry = async (serverUrl: string, teamId?: string, channelId?: stri
|
|||
export async function deferredAppEntryActions(
|
||||
serverUrl: string, since: number, currentUserId: string, currentUserLocale: string, preferences: PreferenceType[] | undefined,
|
||||
config: ClientConfig, license: ClientLicense | undefined, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
|
||||
initialTeamId?: string, initialChannelId?: string) {
|
||||
const result = restDeferredAppEntryActions(serverUrl, since, currentUserId, currentUserLocale, preferences, config, license, teamData, chData, initialTeamId, initialChannelId);
|
||||
initialTeamId?: string, initialChannelId?: string,
|
||||
groupLabel?: string,
|
||||
) {
|
||||
const result = restDeferredAppEntryActions(
|
||||
serverUrl, since, currentUserId, currentUserLocale,
|
||||
preferences, config, license,
|
||||
teamData, chData, initialTeamId, initialChannelId,
|
||||
groupLabel,
|
||||
);
|
||||
|
||||
autoUpdateTimezone(serverUrl);
|
||||
autoUpdateTimezone(serverUrl, groupLabel);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -117,7 +124,7 @@ const teamsToRemove = async (serverUrl: string, removeTeamIds?: string[]) => {
|
|||
return [];
|
||||
};
|
||||
|
||||
const entryRest = async (serverUrl: string, teamId?: string, channelId?: string, since = 0): Promise<EntryResponse> => {
|
||||
const entryRest = async (serverUrl: string, teamId?: string, channelId?: string, since = 0, groupLabel?: string): Promise<EntryResponse> => {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
|
|
@ -126,7 +133,7 @@ const entryRest = async (serverUrl: string, teamId?: string, channelId?: string,
|
|||
|
||||
const lastDisconnectedAt = since || await getLastFullSync(database);
|
||||
|
||||
const fetchedData = await fetchAppEntryData(serverUrl, lastDisconnectedAt, teamId, channelId);
|
||||
const fetchedData = await fetchAppEntryData(serverUrl, lastDisconnectedAt, teamId, channelId, groupLabel);
|
||||
if ('error' in fetchedData) {
|
||||
return {error: fetchedData.error};
|
||||
}
|
||||
|
|
@ -143,7 +150,7 @@ const entryRest = async (serverUrl: string, teamId?: string, channelId?: string,
|
|||
return {error};
|
||||
}
|
||||
|
||||
const rolesData = await fetchRoles(serverUrl, teamData.memberships, chData?.memberships, meData.user, true);
|
||||
const rolesData = await fetchRoles(serverUrl, teamData.memberships, chData?.memberships, meData.user, true, false, groupLabel);
|
||||
|
||||
const initialChannelId = await entryInitialChannelId(database, fetchedChannelId, teamId, initialTeamId, meData?.user?.locale || '', chData?.channels, chData?.memberships);
|
||||
|
||||
|
|
@ -164,7 +171,7 @@ const entryRest = async (serverUrl: string, teamId?: string, channelId?: string,
|
|||
return {models: models.flat(), initialChannelId, initialTeamId, prefData, teamData, chData, meData, gmConverted};
|
||||
};
|
||||
|
||||
const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeamId = '', channelId?: string): Promise<AppEntryData | AppEntryError> => {
|
||||
const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeamId = '', channelId?: string, groupLabel?: string): Promise<AppEntryData | AppEntryError> => {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
|
||||
if (!database) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
|
|
@ -173,8 +180,8 @@ const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeam
|
|||
const includeDeletedChannels = true;
|
||||
const fetchOnly = true;
|
||||
|
||||
const confReq = await fetchConfigAndLicense(serverUrl);
|
||||
const prefData = await fetchMyPreferences(serverUrl, fetchOnly);
|
||||
const confReq = await fetchConfigAndLicense(serverUrl, false, groupLabel);
|
||||
const prefData = await fetchMyPreferences(serverUrl, fetchOnly, groupLabel);
|
||||
const isCRTEnabled = Boolean(prefData.preferences && processIsCRTEnabled(prefData.preferences, confReq.config?.CollapsedThreads, confReq.config?.FeatureFlagCollapsedThreads, confReq.config?.Version));
|
||||
if (prefData.preferences) {
|
||||
const crtToggled = await getHasCRTChanged(database, prefData.preferences);
|
||||
|
|
@ -193,8 +200,8 @@ const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeam
|
|||
|
||||
// Fetch in parallel teams / team membership / user preferences / user
|
||||
const promises: [Promise<MyTeamsRequest>, Promise<MyUserRequest>] = [
|
||||
fetchMyTeams(serverUrl, fetchOnly),
|
||||
fetchMe(serverUrl, fetchOnly),
|
||||
fetchMyTeams(serverUrl, fetchOnly, groupLabel),
|
||||
fetchMe(serverUrl, fetchOnly, groupLabel),
|
||||
];
|
||||
|
||||
const resolution = await Promise.all(promises);
|
||||
|
|
@ -214,7 +221,7 @@ const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeam
|
|||
// active team on mobile app after this point.
|
||||
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const serverChannel = await client.getChannel(channelId);
|
||||
const serverChannel = await client.getChannel(channelId, groupLabel);
|
||||
|
||||
// Although yon can convert GM only to a pirvate channel, a private channel can furthur be converted to a public channel.
|
||||
// So between the mobile app being on the GM and reconnecting,
|
||||
|
|
@ -228,7 +235,7 @@ const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeam
|
|||
}
|
||||
|
||||
if (initialTeamId) {
|
||||
chData = await fetchMyChannelsForTeam(serverUrl, initialTeamId, includeDeletedChannels, since, fetchOnly, false, isCRTEnabled);
|
||||
chData = await fetchMyChannelsForTeam(serverUrl, initialTeamId, includeDeletedChannels, since, fetchOnly, false, isCRTEnabled, groupLabel);
|
||||
}
|
||||
|
||||
if (!initialTeamId && teamData.teams?.length && teamData.memberships?.length) {
|
||||
|
|
@ -239,7 +246,7 @@ const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeam
|
|||
const myTeams = teamData.teams!.filter((t) => teamMembers.has(t.id));
|
||||
const defaultTeam = selectDefaultTeam(myTeams, meData.user?.locale || DEFAULT_LOCALE, teamOrderPreference, config?.ExperimentalPrimaryTeam);
|
||||
if (defaultTeam?.id) {
|
||||
chData = await fetchMyChannelsForTeam(serverUrl, defaultTeam.id, includeDeletedChannels, since, fetchOnly, false, isCRTEnabled);
|
||||
chData = await fetchMyChannelsForTeam(serverUrl, defaultTeam.id, includeDeletedChannels, since, fetchOnly, false, isCRTEnabled, groupLabel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +281,7 @@ const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeam
|
|||
}
|
||||
|
||||
const availableTeamIds = await getAvailableTeamIds(database, initialTeamId, teamData.teams, prefData.preferences, meData.user?.locale);
|
||||
const alternateTeamData = await fetchAlternateTeamData(serverUrl, availableTeamIds, removeTeamIds, includeDeletedChannels, since, fetchOnly, isCRTEnabled);
|
||||
const alternateTeamData = await fetchAlternateTeamData(serverUrl, availableTeamIds, removeTeamIds, includeDeletedChannels, since, fetchOnly, isCRTEnabled, groupLabel);
|
||||
|
||||
data = {
|
||||
...data,
|
||||
|
|
@ -304,12 +311,14 @@ const fetchAppEntryData = async (serverUrl: string, sinceArg: number, onLoadTeam
|
|||
|
||||
const fetchAlternateTeamData = async (
|
||||
serverUrl: string, availableTeamIds: string[], removeTeamIds: string[],
|
||||
includeDeleted = true, since = 0, fetchOnly = false, isCRTEnabled?: boolean) => {
|
||||
includeDeleted = true, since = 0, fetchOnly = false,
|
||||
isCRTEnabled?: boolean, groupLabel?: string,
|
||||
) => {
|
||||
let initialTeamId = '';
|
||||
let chData;
|
||||
|
||||
for await (const teamId of availableTeamIds) {
|
||||
chData = await fetchMyChannelsForTeam(serverUrl, teamId, includeDeleted, since, fetchOnly, false, isCRTEnabled);
|
||||
chData = await fetchMyChannelsForTeam(serverUrl, teamId, includeDeleted, since, fetchOnly, false, isCRTEnabled, groupLabel);
|
||||
const chError = chData.error;
|
||||
if (isErrorWithStatusCode(chError) && chError.status_code === 403) {
|
||||
removeTeamIds.push(teamId);
|
||||
|
|
@ -367,7 +376,7 @@ async function entryInitialChannelId(database: Database, requestedChannelId = ''
|
|||
async function restDeferredAppEntryActions(
|
||||
serverUrl: string, since: number, currentUserId: string, currentUserLocale: string, preferences: PreferenceType[] | undefined,
|
||||
config: ClientConfig, license: ClientLicense | undefined, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
|
||||
initialTeamId?: string, initialChannelId?: string,
|
||||
initialTeamId?: string, initialChannelId?: string, groupLabel?: string,
|
||||
) {
|
||||
const isCRTEnabled = (preferences && processIsCRTEnabled(preferences, config.CollapsedThreads, config.FeatureFlagCollapsedThreads, config.Version)) || false;
|
||||
const directChannels = chData?.channels?.filter(isDMorGM);
|
||||
|
|
@ -376,21 +385,21 @@ async function restDeferredAppEntryActions(
|
|||
// sidebar DM & GM profiles
|
||||
if (channelsToFetchProfiles.size) {
|
||||
const teammateDisplayNameSetting = getTeammateNameDisplaySetting(preferences || [], config.LockTeammateNameDisplay, config.TeammateNameDisplay, license);
|
||||
fetchMissingDirectChannelsInfo(serverUrl, Array.from(channelsToFetchProfiles), currentUserLocale, teammateDisplayNameSetting, currentUserId);
|
||||
fetchMissingDirectChannelsInfo(serverUrl, Array.from(channelsToFetchProfiles), currentUserLocale, teammateDisplayNameSetting, currentUserId, false, groupLabel);
|
||||
}
|
||||
|
||||
updateAllUsersSince(serverUrl, since);
|
||||
updateAllUsersSince(serverUrl, since, false, groupLabel);
|
||||
updateCanJoinTeams(serverUrl);
|
||||
|
||||
// defer fetch channels and unread posts for other teams
|
||||
setTimeout(async () => {
|
||||
if (chData?.channels?.length && chData.memberships?.length && initialTeamId) {
|
||||
if (isCRTEnabled && initialTeamId) {
|
||||
await syncTeamThreads(serverUrl, initialTeamId);
|
||||
await syncTeamThreads(serverUrl, initialTeamId, false, false, groupLabel);
|
||||
}
|
||||
fetchPostsForUnreadChannels(serverUrl, chData.channels, chData.memberships, initialChannelId);
|
||||
fetchPostsForUnreadChannels(serverUrl, chData.channels, chData.memberships, initialChannelId, false, groupLabel);
|
||||
}
|
||||
|
||||
// defer fetch channels and unread posts for other teams
|
||||
if (teamData.teams?.length && teamData.memberships?.length) {
|
||||
const teamsOrder = preferences?.find((p) => p.category === Preferences.CATEGORIES.TEAMS_ORDER);
|
||||
const sortedTeamIds = new Set(teamsOrder?.value.split(','));
|
||||
|
|
@ -418,16 +427,16 @@ async function restDeferredAppEntryActions(
|
|||
}
|
||||
|
||||
if (myTeams.length) {
|
||||
fetchTeamsChannelsThreadsAndUnreadPosts(serverUrl, since, myTeams, isCRTEnabled);
|
||||
fetchTeamsChannelsThreadsAndUnreadPosts(serverUrl, since, myTeams, isCRTEnabled, false, groupLabel + '-additional');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch groups for current user
|
||||
fetchGroupsForMember(serverUrl, currentUserId);
|
||||
fetchGroupsForMember(serverUrl, currentUserId, false, groupLabel);
|
||||
}
|
||||
|
||||
export const setExtraSessionProps = async (serverUrl: string) => {
|
||||
export const setExtraSessionProps = async (serverUrl: string, groupLabel?: string) => {
|
||||
try {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const serverVersion = await getConfigValue(database, 'Version');
|
||||
|
|
@ -441,7 +450,7 @@ export const setExtraSessionProps = async (serverUrl: string) => {
|
|||
const res = await checkNotifications();
|
||||
const granted = res.status === RESULTS.GRANTED || res.status === RESULTS.LIMITED;
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
client.setExtraSessionProps(deviceToken, !granted, nativeApplicationVersion);
|
||||
client.setExtraSessionProps(deviceToken, !granted, nativeApplicationVersion, groupLabel);
|
||||
}
|
||||
return {};
|
||||
} catch (error) {
|
||||
|
|
@ -450,7 +459,7 @@ export const setExtraSessionProps = async (serverUrl: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
export async function verifyPushProxy(serverUrl: string) {
|
||||
export async function verifyPushProxy(serverUrl: string, groupLabel?: string) {
|
||||
const deviceId = await getDeviceToken();
|
||||
if (!deviceId) {
|
||||
return;
|
||||
|
|
@ -468,7 +477,7 @@ export async function verifyPushProxy(serverUrl: string) {
|
|||
}
|
||||
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const response = await client.ping(deviceId);
|
||||
const response = await client.ping(deviceId, undefined, groupLabel);
|
||||
const canReceiveNotifications = response?.data?.CanReceiveNotifications;
|
||||
switch (canReceiveNotifications) {
|
||||
case PUSH_PROXY_RESPONSE_NOT_AVAILABLE:
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export async function loginEntry({serverUrl}: AfterLoginArgs): Promise<{error?:
|
|||
const credentials = await getServerCredentials(serverUrl);
|
||||
if (credentials?.token) {
|
||||
WebsocketManager.createClient(serverUrl, credentials.token);
|
||||
await WebsocketManager.initializeClient(serverUrl);
|
||||
await WebsocketManager.initializeClient(serverUrl, 'login');
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
|||
import type MyTeamModel from '@typings/database/models/servers/my_team';
|
||||
import type PostModel from '@typings/database/models/servers/post';
|
||||
|
||||
export async function pushNotificationEntry(serverUrl: string, notification: NotificationData) {
|
||||
export async function pushNotificationEntry(serverUrl: string, notification: NotificationData, groupLabel?: string) {
|
||||
// We only reach this point if we have a channel Id in the notification payload
|
||||
const channelId = notification.channel_id!;
|
||||
const rootId = notification.root_id!;
|
||||
|
|
@ -65,7 +65,7 @@ export async function pushNotificationEntry(serverUrl: string, notification: Not
|
|||
let myTeam: MyTeamModel | TeamMembership | undefined = await getMyTeamById(database, teamId);
|
||||
|
||||
if (!myTeam) {
|
||||
const resp = await fetchMyTeam(serverUrl, teamId);
|
||||
const resp = await fetchMyTeam(serverUrl, teamId, false, groupLabel);
|
||||
if (resp.error) {
|
||||
if (isErrorWithStatusCode(resp.error) && resp.error.status_code === 403) {
|
||||
emitNotificationError('Team');
|
||||
|
|
@ -78,7 +78,7 @@ export async function pushNotificationEntry(serverUrl: string, notification: Not
|
|||
}
|
||||
|
||||
if (!myChannel) {
|
||||
const resp = await fetchMyChannel(serverUrl, teamId, channelId);
|
||||
const resp = await fetchMyChannel(serverUrl, teamId, channelId, false, groupLabel);
|
||||
if (resp.error) {
|
||||
if (isErrorWithStatusCode(resp.error) && resp.error.status_code === 403) {
|
||||
emitNotificationError('Channel');
|
||||
|
|
@ -97,7 +97,7 @@ export async function pushNotificationEntry(serverUrl: string, notification: Not
|
|||
if (isThreadNotification) {
|
||||
let post: PostModel | Post | undefined = await getPostById(database, rootId);
|
||||
if (!post) {
|
||||
const resp = await fetchPostById(serverUrl, rootId);
|
||||
const resp = await fetchPostById(serverUrl, rootId, false, groupLabel);
|
||||
post = resp.post;
|
||||
}
|
||||
|
||||
|
|
@ -105,20 +105,20 @@ export async function pushNotificationEntry(serverUrl: string, notification: Not
|
|||
|
||||
if (actualRootId) {
|
||||
PerformanceMetricsManager.setLoadTarget('THREAD');
|
||||
await fetchAndSwitchToThread(serverUrl, actualRootId, true);
|
||||
await fetchAndSwitchToThread(serverUrl, actualRootId, true, groupLabel);
|
||||
} else if (post) {
|
||||
PerformanceMetricsManager.setLoadTarget('THREAD');
|
||||
await fetchAndSwitchToThread(serverUrl, rootId, true);
|
||||
await fetchAndSwitchToThread(serverUrl, rootId, true, groupLabel);
|
||||
} else {
|
||||
emitNotificationError('Post');
|
||||
}
|
||||
} else {
|
||||
PerformanceMetricsManager.setLoadTarget('CHANNEL');
|
||||
await switchToChannelById(serverUrl, channelId, teamId);
|
||||
await switchToChannelById(serverUrl, channelId, teamId, false, groupLabel);
|
||||
}
|
||||
}
|
||||
|
||||
WebsocketManager.openAll();
|
||||
WebsocketManager.openAll(groupLabel);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export const fetchGroupsByNames = async (serverUrl: string, names: string[], fet
|
|||
}
|
||||
};
|
||||
|
||||
export const fetchGroupsForChannel = async (serverUrl: string, channelId: string, fetchOnly = false) => {
|
||||
export const fetchGroupsForChannel = async (serverUrl: string, channelId: string, fetchOnly = false, groupLabel?: string) => {
|
||||
try {
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const license = await getLicense(database);
|
||||
|
|
@ -75,7 +75,7 @@ export const fetchGroupsForChannel = async (serverUrl: string, channelId: string
|
|||
}
|
||||
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const response = await client.getAllGroupsAssociatedToChannel(channelId);
|
||||
const response = await client.getAllGroupsAssociatedToChannel(channelId, undefined, groupLabel);
|
||||
|
||||
if (!response.groups.length) {
|
||||
return {groups: [], groupChannels: []};
|
||||
|
|
@ -129,7 +129,7 @@ export const fetchGroupsForTeam = async (serverUrl: string, teamId: string, fetc
|
|||
}
|
||||
};
|
||||
|
||||
export const fetchGroupsForMember = async (serverUrl: string, userId: string, fetchOnly = false) => {
|
||||
export const fetchGroupsForMember = async (serverUrl: string, userId: string, fetchOnly = false, groupLabel?: string) => {
|
||||
try {
|
||||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const license = await getLicense(database);
|
||||
|
|
@ -138,7 +138,7 @@ export const fetchGroupsForMember = async (serverUrl: string, userId: string, fe
|
|||
}
|
||||
|
||||
const client: Client = NetworkManager.getClient(serverUrl);
|
||||
const response = await client.getAllGroupsAssociatedToMembership(userId);
|
||||
const response = await client.getAllGroupsAssociatedToMembership(userId, false, groupLabel);
|
||||
|
||||
if (!response.length) {
|
||||
return {groups: [], groupMemberships: []};
|
||||
|
|
@ -191,13 +191,13 @@ export const fetchGroupsForTeamIfConstrained = async (serverUrl: string, teamId:
|
|||
}
|
||||
};
|
||||
|
||||
export const fetchGroupsForChannelIfConstrained = async (serverUrl: string, channelId: string, fetchOnly = false) => {
|
||||
export const fetchGroupsForChannelIfConstrained = async (serverUrl: string, channelId: string, fetchOnly = false, groupLabel?: string) => {
|
||||
try {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const channel = await getChannelById(database, channelId);
|
||||
|
||||
if (channel?.isGroupConstrained) {
|
||||
return fetchGroupsForChannel(serverUrl, channelId, fetchOnly);
|
||||
return fetchGroupsForChannel(serverUrl, channelId, fetchOnly, groupLabel);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -107,6 +107,11 @@ afterEach(async () => {
|
|||
await DatabaseManager.destroyServerDatabase(serverUrl);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
// This removes the timer set to log the results of the network metrics
|
||||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
describe('notifications', () => {
|
||||
it('fetchNotificationData - handle no channel id', async () => {
|
||||
const result = await fetchNotificationData(serverUrl, {} as NotificationWithData);
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ export const retryFailedPost = async (serverUrl: string, post: PostModel) => {
|
|||
return {};
|
||||
};
|
||||
|
||||
export async function fetchPostsForChannel(serverUrl: string, channelId: string, fetchOnly = false): Promise<PostsForChannel> {
|
||||
export async function fetchPostsForChannel(serverUrl: string, channelId: string, fetchOnly = false, groupLabel?: string): Promise<PostsForChannel> {
|
||||
try {
|
||||
if (!fetchOnly) {
|
||||
EphemeralStore.addLoadingMessagesForChannel(serverUrl, channelId);
|
||||
|
|
@ -296,10 +296,10 @@ export async function fetchPostsForChannel(serverUrl: string, channelId: string,
|
|||
const postsInChannel = await getRecentPostsInChannel(database, channelId);
|
||||
const since = myChannel?.lastFetchedAt || postsInChannel?.[0]?.createAt || 0;
|
||||
if (since) {
|
||||
postAction = fetchPostsSince(serverUrl, channelId, since, true);
|
||||
postAction = fetchPostsSince(serverUrl, channelId, since, true, groupLabel);
|
||||
actionType = ActionType.POSTS.RECEIVED_SINCE;
|
||||
} else {
|
||||
postAction = fetchPosts(serverUrl, channelId, 0, General.POST_CHUNK_SIZE, true);
|
||||
postAction = fetchPosts(serverUrl, channelId, 0, General.POST_CHUNK_SIZE, true, groupLabel);
|
||||
actionType = ActionType.POSTS.RECEIVED_IN_CHANNEL;
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +309,7 @@ export async function fetchPostsForChannel(serverUrl: string, channelId: string,
|
|||
}
|
||||
let authors: UserProfile[] = [];
|
||||
if (data.posts?.length && data.order?.length) {
|
||||
const {authors: fetchedAuthors} = await fetchPostAuthors(serverUrl, data.posts, true);
|
||||
const {authors: fetchedAuthors} = await fetchPostAuthors(serverUrl, data.posts, true, groupLabel);
|
||||
authors = fetchedAuthors || [];
|
||||
|
||||
if (!fetchOnly) {
|
||||
|
|
@ -332,7 +332,10 @@ export async function fetchPostsForChannel(serverUrl: string, channelId: string,
|
|||
}
|
||||
}
|
||||
|
||||
export const fetchPostsForUnreadChannels = async (serverUrl: string, channels: Channel[], memberships: ChannelMembership[], excludeChannelId?: string, fetchOnly = false): Promise<PostsForChannel[]> => {
|
||||
export const fetchPostsForUnreadChannels = async (
|
||||
serverUrl: string, channels: Channel[], memberships: ChannelMembership[],
|
||||
excludeChannelId?: string, fetchOnly = false, groupLabel?: string,
|
||||
): Promise<PostsForChannel[]> => {
|
||||
const membersMap = new Map<string, ChannelMembership>();
|
||||
for (const member of memberships) {
|
||||
membersMap.set(member.channel_id, member);
|
||||
|
|
@ -353,7 +356,7 @@ export const fetchPostsForUnreadChannels = async (serverUrl: string, channels: C
|
|||
for await (const channelIds of chunks) {
|
||||
const promises = [];
|
||||
for (const channelId of channelIds) {
|
||||
promises.push(fetchPostsForChannel(serverUrl, channelId, fetchOnly));
|
||||
promises.push(fetchPostsForChannel(serverUrl, channelId, fetchOnly, groupLabel));
|
||||
}
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
|
|
@ -362,7 +365,7 @@ export const fetchPostsForUnreadChannels = async (serverUrl: string, channels: C
|
|||
return postsForChannel;
|
||||
};
|
||||
|
||||
export async function fetchPosts(serverUrl: string, channelId: string, page = 0, perPage = General.POST_CHUNK_SIZE, fetchOnly = false): Promise<PostsRequest> {
|
||||
export async function fetchPosts(serverUrl: string, channelId: string, page = 0, perPage = General.POST_CHUNK_SIZE, fetchOnly = false, groupLabel?: string): Promise<PostsRequest> {
|
||||
try {
|
||||
if (!fetchOnly) {
|
||||
EphemeralStore.addLoadingMessagesForChannel(serverUrl, channelId);
|
||||
|
|
@ -370,7 +373,7 @@ export async function fetchPosts(serverUrl: string, channelId: string, page = 0,
|
|||
const {operator, database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const isCRTEnabled = await getIsCRTEnabled(database);
|
||||
const data = await client.getPosts(channelId, page, perPage, isCRTEnabled, isCRTEnabled);
|
||||
const data = await client.getPosts(channelId, page, perPage, isCRTEnabled, isCRTEnabled, groupLabel);
|
||||
const result = processPostsFetched(data);
|
||||
if (!fetchOnly && result.posts.length) {
|
||||
const models = await operator.handlePosts({
|
||||
|
|
@ -379,7 +382,7 @@ export async function fetchPosts(serverUrl: string, channelId: string, page = 0,
|
|||
prepareRecordsOnly: true,
|
||||
});
|
||||
|
||||
const {authors} = await fetchPostAuthors(serverUrl, result.posts, true);
|
||||
const {authors} = await fetchPostAuthors(serverUrl, result.posts, true, groupLabel);
|
||||
if (authors?.length) {
|
||||
const userModels = await operator.handleUsers({
|
||||
users: authors,
|
||||
|
|
@ -462,7 +465,7 @@ export async function fetchPostsBefore(serverUrl: string, channelId: string, pos
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchPostsSince(serverUrl: string, channelId: string, since: number, fetchOnly = false): Promise<PostsRequest> {
|
||||
export async function fetchPostsSince(serverUrl: string, channelId: string, since: number, fetchOnly = false, groupLabel?: string): Promise<PostsRequest> {
|
||||
try {
|
||||
if (!fetchOnly) {
|
||||
EphemeralStore.addLoadingMessagesForChannel(serverUrl, channelId);
|
||||
|
|
@ -471,7 +474,7 @@ export async function fetchPostsSince(serverUrl: string, channelId: string, sinc
|
|||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const isCRTEnabled = await getIsCRTEnabled(database);
|
||||
const data = await client.getPostsSince(channelId, since, isCRTEnabled, isCRTEnabled);
|
||||
const data = await client.getPostsSince(channelId, since, isCRTEnabled, isCRTEnabled, groupLabel);
|
||||
const result = processPostsFetched(data);
|
||||
if (!fetchOnly) {
|
||||
const models = await operator.handlePosts({
|
||||
|
|
@ -480,7 +483,7 @@ export async function fetchPostsSince(serverUrl: string, channelId: string, sinc
|
|||
prepareRecordsOnly: true,
|
||||
});
|
||||
|
||||
const {authors} = await fetchPostAuthors(serverUrl, result.posts, true);
|
||||
const {authors} = await fetchPostAuthors(serverUrl, result.posts, true, groupLabel);
|
||||
if (authors?.length) {
|
||||
const userModels = await operator.handleUsers({
|
||||
users: authors,
|
||||
|
|
@ -509,7 +512,7 @@ export async function fetchPostsSince(serverUrl: string, channelId: string, sinc
|
|||
}
|
||||
}
|
||||
|
||||
export const fetchPostAuthors = async (serverUrl: string, posts: Post[], fetchOnly = false): Promise<AuthorsRequest> => {
|
||||
export const fetchPostAuthors = async (serverUrl: string, posts: Post[], fetchOnly = false, groupLabel?: string): Promise<AuthorsRequest> => {
|
||||
try {
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
|
|
@ -537,11 +540,11 @@ export const fetchPostAuthors = async (serverUrl: string, posts: Post[], fetchOn
|
|||
}
|
||||
const promises: Array<Promise<UserProfile[]>> = [];
|
||||
if (userIdsToLoad.size) {
|
||||
promises.push(client.getProfilesByIds(Array.from(userIdsToLoad)));
|
||||
promises.push(client.getProfilesByIds(Array.from(userIdsToLoad), {}, groupLabel));
|
||||
}
|
||||
|
||||
if (usernamesToLoad.size) {
|
||||
promises.push(client.getProfilesByUsernames(Array.from(usernamesToLoad)));
|
||||
promises.push(client.getProfilesByUsernames(Array.from(usernamesToLoad), groupLabel));
|
||||
}
|
||||
|
||||
if (promises.length) {
|
||||
|
|
@ -572,7 +575,7 @@ export const fetchPostAuthors = async (serverUrl: string, posts: Post[], fetchOn
|
|||
}
|
||||
};
|
||||
|
||||
export async function fetchPostThread(serverUrl: string, postId: string, options?: FetchPaginatedThreadOptions, fetchOnly = false) {
|
||||
export async function fetchPostThread(serverUrl: string, postId: string, options?: FetchPaginatedThreadOptions, fetchOnly = false, groupLabel?: string) {
|
||||
try {
|
||||
setFetchingThreadState(postId, true);
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
|
|
@ -586,7 +589,7 @@ export async function fetchPostThread(serverUrl: string, postId: string, options
|
|||
collapsedThreads: isCRTEnabled,
|
||||
collapsedThreadsExtended: isCRTEnabled,
|
||||
...options,
|
||||
});
|
||||
}, groupLabel);
|
||||
const result = processPostsFetched(data);
|
||||
let posts: Model[] = [];
|
||||
if (result.posts.length && !fetchOnly) {
|
||||
|
|
@ -598,7 +601,7 @@ export async function fetchPostThread(serverUrl: string, postId: string, options
|
|||
});
|
||||
models.push(...posts);
|
||||
|
||||
const {authors} = await fetchPostAuthors(serverUrl, result.posts, true);
|
||||
const {authors} = await fetchPostAuthors(serverUrl, result.posts, true, groupLabel);
|
||||
if (authors?.length) {
|
||||
const userModels = await operator.handleUsers({
|
||||
users: authors,
|
||||
|
|
@ -743,14 +746,14 @@ export async function fetchMissingChannelsFromPosts(serverUrl: string, posts: Po
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchPostById(serverUrl: string, postId: string, fetchOnly = false) {
|
||||
export async function fetchPostById(serverUrl: string, postId: string, fetchOnly = false, groupLabel?: string) {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const post = await client.getPost(postId);
|
||||
const post = await client.getPost(postId, groupLabel);
|
||||
if (!fetchOnly) {
|
||||
const models: Model[] = [];
|
||||
const {authors} = await fetchPostAuthors(serverUrl, [post], true);
|
||||
const {authors} = await fetchPostAuthors(serverUrl, [post], true, groupLabel);
|
||||
const posts = await operator.handlePosts({
|
||||
actionType: ActionType.POSTS.RECEIVED_NEW,
|
||||
order: [post.id],
|
||||
|
|
|
|||
|
|
@ -28,12 +28,12 @@ export type MyPreferencesRequest = {
|
|||
error?: unknown;
|
||||
};
|
||||
|
||||
export const fetchMyPreferences = async (serverUrl: string, fetchOnly = false): Promise<MyPreferencesRequest> => {
|
||||
export const fetchMyPreferences = async (serverUrl: string, fetchOnly = false, groupLabel?: string): Promise<MyPreferencesRequest> => {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const preferences = await client.getMyPreferences();
|
||||
const preferences = await client.getMyPreferences(groupLabel);
|
||||
|
||||
if (!fetchOnly) {
|
||||
await operator.handlePreferences({
|
||||
|
|
@ -84,7 +84,7 @@ export const savePostPreference = async (serverUrl: string, postId: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const savePreference = async (serverUrl: string, preferences: PreferenceType[], prepareRecordsOnly = false) => {
|
||||
export const savePreference = async (serverUrl: string, preferences: PreferenceType[], prepareRecordsOnly = false, groupLabel?: string) => {
|
||||
try {
|
||||
if (!preferences.length) {
|
||||
return {preferences: []};
|
||||
|
|
@ -97,7 +97,7 @@ export const savePreference = async (serverUrl: string, preferences: PreferenceT
|
|||
const chunkSize = 100;
|
||||
const chunks = chunk(preferences, chunkSize);
|
||||
chunks.forEach((c: PreferenceType[]) => {
|
||||
client.savePreferences(userId, c);
|
||||
client.savePreferences(userId, c, groupLabel);
|
||||
});
|
||||
const preferenceModels = await operator.handlePreferences({
|
||||
preferences,
|
||||
|
|
@ -141,14 +141,14 @@ export const deleteSavedPost = async (serverUrl: string, postId: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const openChannelIfNeeded = async (serverUrl: string, channelId: string) => {
|
||||
export const openChannelIfNeeded = async (serverUrl: string, channelId: string, groupLabel?: string) => {
|
||||
try {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const channel = await getChannelById(database, channelId);
|
||||
if (!channel || !isDMorGM(channel)) {
|
||||
return {};
|
||||
}
|
||||
const res = await openChannels(serverUrl, [channel]);
|
||||
const res = await openChannels(serverUrl, [channel], groupLabel);
|
||||
return res;
|
||||
} catch (error) {
|
||||
forceLogoutIfNecessary(serverUrl, error);
|
||||
|
|
@ -156,11 +156,11 @@ export const openChannelIfNeeded = async (serverUrl: string, channelId: string)
|
|||
}
|
||||
};
|
||||
|
||||
export const openAllUnreadChannels = async (serverUrl: string) => {
|
||||
export const openAllUnreadChannels = async (serverUrl: string, groupLabel?: string) => {
|
||||
try {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const channels = await queryAllUnreadDMsAndGMsIds(database).fetch();
|
||||
const res = await openChannels(serverUrl, channels);
|
||||
const res = await openChannels(serverUrl, channels, groupLabel);
|
||||
return res;
|
||||
} catch (error) {
|
||||
forceLogoutIfNecessary(serverUrl, error);
|
||||
|
|
@ -168,7 +168,7 @@ export const openAllUnreadChannels = async (serverUrl: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
const openChannels = async (serverUrl: string, channels: ChannelModel[]) => {
|
||||
const openChannels = async (serverUrl: string, channels: ChannelModel[], groupLabel?: string) => {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const userId = await getCurrentUserId(database);
|
||||
|
||||
|
|
@ -202,7 +202,7 @@ const openChannels = async (serverUrl: string, channels: ChannelModel[]) => {
|
|||
);
|
||||
}
|
||||
|
||||
return savePreference(serverUrl, prefs);
|
||||
return savePreference(serverUrl, prefs, false, groupLabel);
|
||||
};
|
||||
|
||||
export const setDirectChannelVisible = async (serverUrl: string, channelId: string, visible = true) => {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@ export type RolesRequest = {
|
|||
roles?: Role[];
|
||||
}
|
||||
|
||||
export const fetchRolesIfNeeded = async (serverUrl: string, updatedRoles: string[], fetchOnly = false, force = false): Promise<RolesRequest> => {
|
||||
export const fetchRolesIfNeeded = async (
|
||||
serverUrl: string, updatedRoles: string[],
|
||||
fetchOnly = false, force = false, groupLabel?: string,
|
||||
): Promise<RolesRequest> => {
|
||||
if (!updatedRoles.length) {
|
||||
return {roles: []};
|
||||
}
|
||||
|
|
@ -46,7 +49,7 @@ export const fetchRolesIfNeeded = async (serverUrl: string, updatedRoles: string
|
|||
const getRolesRequests = [];
|
||||
for (let i = 0; i < newRoles.length; i += General.MAX_GET_ROLES_BY_NAMES) {
|
||||
const chunk = newRoles.slice(i, i + General.MAX_GET_ROLES_BY_NAMES);
|
||||
getRolesRequests.push(client.getRolesByNames(chunk));
|
||||
getRolesRequests.push(client.getRolesByNames(chunk, groupLabel));
|
||||
}
|
||||
|
||||
const roles = (await Promise.all(getRolesRequests)).flat();
|
||||
|
|
@ -65,7 +68,10 @@ export const fetchRolesIfNeeded = async (serverUrl: string, updatedRoles: string
|
|||
}
|
||||
};
|
||||
|
||||
export const fetchRoles = async (serverUrl: string, teamMembership?: TeamMembership[], channelMembership?: ChannelMembership[], user?: UserProfile, fetchOnly = false, force = false) => {
|
||||
export const fetchRoles = async (
|
||||
serverUrl: string, teamMembership?: TeamMembership[], channelMembership?: ChannelMembership[],
|
||||
user?: UserProfile, fetchOnly = false, force = false, groupLabel?: string,
|
||||
) => {
|
||||
const rolesToFetch = new Set<string>(user?.roles.split(' ') || []);
|
||||
|
||||
if (teamMembership?.length) {
|
||||
|
|
@ -87,7 +93,7 @@ export const fetchRoles = async (serverUrl: string, teamMembership?: TeamMembers
|
|||
|
||||
rolesToFetch.delete('');
|
||||
if (rolesToFetch.size > 0) {
|
||||
return fetchRolesIfNeeded(serverUrl, Array.from(rolesToFetch), fetchOnly, force);
|
||||
return fetchRolesIfNeeded(serverUrl, Array.from(rolesToFetch), fetchOnly, force, groupLabel);
|
||||
}
|
||||
|
||||
return {roles: []};
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ export type DataRetentionPoliciesRequest = {
|
|||
error?: unknown;
|
||||
}
|
||||
|
||||
export const fetchDataRetentionPolicy = async (serverUrl: string, fetchOnly = false): Promise<DataRetentionPoliciesRequest> => {
|
||||
const {data: globalPolicy, error: globalPolicyError} = await fetchGlobalDataRetentionPolicy(serverUrl);
|
||||
const {data: teamPolicies, error: teamPoliciesError} = await fetchAllGranularDataRetentionPolicies(serverUrl);
|
||||
export const fetchDataRetentionPolicy = async (serverUrl: string, fetchOnly = false, groupLabel?: string): Promise<DataRetentionPoliciesRequest> => {
|
||||
const {data: globalPolicy, error: globalPolicyError} = await fetchGlobalDataRetentionPolicy(serverUrl, groupLabel);
|
||||
const {data: teamPolicies, error: teamPoliciesError} = await fetchAllGranularDataRetentionPolicies(serverUrl, undefined, undefined, undefined, groupLabel);
|
||||
const {data: channelPolicies, error: channelPoliciesError} = await fetchAllGranularDataRetentionPolicies(serverUrl, true);
|
||||
|
||||
const error = globalPolicyError || teamPoliciesError || channelPoliciesError;
|
||||
|
|
@ -45,10 +45,10 @@ export const fetchDataRetentionPolicy = async (serverUrl: string, fetchOnly = fa
|
|||
return data;
|
||||
};
|
||||
|
||||
export const fetchGlobalDataRetentionPolicy = async (serverUrl: string): Promise<{data?: GlobalDataRetentionPolicy; error?: unknown}> => {
|
||||
export const fetchGlobalDataRetentionPolicy = async (serverUrl: string, groupLabel?: string): Promise<{data?: GlobalDataRetentionPolicy; error?: unknown}> => {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const data = await client.getGlobalDataRetentionPolicy();
|
||||
const data = await client.getGlobalDataRetentionPolicy(groupLabel);
|
||||
return {data};
|
||||
} catch (error) {
|
||||
logDebug('error on fetchGlobalDataRetentionPolicy', getFullErrorMessage(error));
|
||||
|
|
@ -62,6 +62,7 @@ export const fetchAllGranularDataRetentionPolicies = async (
|
|||
isChannel = false,
|
||||
page = 0,
|
||||
policies: Array<TeamDataRetentionPolicy | ChannelDataRetentionPolicy> = [],
|
||||
groupLabel?: string,
|
||||
): Promise<{data?: Array<TeamDataRetentionPolicy | ChannelDataRetentionPolicy>; error?: unknown}> => {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
|
|
@ -70,13 +71,13 @@ export const fetchAllGranularDataRetentionPolicies = async (
|
|||
const currentUserId = await getCurrentUserId(database);
|
||||
let data;
|
||||
if (isChannel) {
|
||||
data = await client.getChannelDataRetentionPolicies(currentUserId, page);
|
||||
data = await client.getChannelDataRetentionPolicies(currentUserId, page, undefined, groupLabel);
|
||||
} else {
|
||||
data = await client.getTeamDataRetentionPolicies(currentUserId, page);
|
||||
data = await client.getTeamDataRetentionPolicies(currentUserId, page, undefined, groupLabel);
|
||||
}
|
||||
policies.push(...data.policies);
|
||||
if (policies.length < data.total_count) {
|
||||
await fetchAllGranularDataRetentionPolicies(serverUrl, isChannel, page + 1, policies);
|
||||
await fetchAllGranularDataRetentionPolicies(serverUrl, isChannel, page + 1, policies, groupLabel);
|
||||
}
|
||||
return {data: policies};
|
||||
} catch (error) {
|
||||
|
|
@ -85,12 +86,12 @@ export const fetchAllGranularDataRetentionPolicies = async (
|
|||
}
|
||||
};
|
||||
|
||||
export const fetchConfigAndLicense = async (serverUrl: string, fetchOnly = false): Promise<ConfigAndLicenseRequest> => {
|
||||
export const fetchConfigAndLicense = async (serverUrl: string, fetchOnly = false, groupLabel?: string): Promise<ConfigAndLicenseRequest> => {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const [config, license]: [ClientConfig, ClientLicense] = await Promise.all([
|
||||
client.getClientConfigOld(),
|
||||
client.getClientLicenseOld(),
|
||||
client.getClientConfigOld(groupLabel),
|
||||
client.getClientLicenseOld(groupLabel),
|
||||
]);
|
||||
|
||||
if (!fetchOnly) {
|
||||
|
|
|
|||
|
|
@ -161,14 +161,14 @@ export async function sendEmailInvitesToTeam(serverUrl: string, teamId: string,
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchMyTeams(serverUrl: string, fetchOnly = false): Promise<MyTeamsRequest> {
|
||||
export async function fetchMyTeams(serverUrl: string, fetchOnly = false, groupLabel?: string): Promise<MyTeamsRequest> {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const [teams, memberships]: [Team[], TeamMembership[]] = await Promise.all([
|
||||
client.getMyTeams(),
|
||||
client.getMyTeamMembers(),
|
||||
client.getMyTeams(groupLabel),
|
||||
client.getMyTeamMembers(groupLabel),
|
||||
]);
|
||||
|
||||
if (!fetchOnly) {
|
||||
|
|
@ -207,14 +207,14 @@ export async function fetchMyTeams(serverUrl: string, fetchOnly = false): Promis
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchMyTeam(serverUrl: string, teamId: string, fetchOnly = false): Promise<MyTeamsRequest> {
|
||||
export async function fetchMyTeam(serverUrl: string, teamId: string, fetchOnly = false, groupLabel?: string): Promise<MyTeamsRequest> {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const [team, membership] = await Promise.all([
|
||||
client.getTeam(teamId),
|
||||
client.getTeamMember(teamId, 'me'),
|
||||
client.getTeam(teamId, groupLabel),
|
||||
client.getTeamMember(teamId, 'me', groupLabel),
|
||||
]);
|
||||
if (!fetchOnly) {
|
||||
const modelPromises = prepareMyTeams(operator, [team], [membership]);
|
||||
|
|
@ -247,14 +247,14 @@ export const fetchAllTeams = async (serverUrl: string, page = 0, perPage = PER_P
|
|||
}
|
||||
};
|
||||
|
||||
const recCanJoinTeams = async (client: Client, myTeamsIds: Set<string>, page: number): Promise<boolean> => {
|
||||
const fetchedTeams = await client.getTeams(page, PER_PAGE_DEFAULT);
|
||||
const recCanJoinTeams = async (client: Client, myTeamsIds: Set<string>, page: number, groupLabel?: string): Promise<boolean> => {
|
||||
const fetchedTeams = await client.getTeams(page, PER_PAGE_DEFAULT, false, groupLabel);
|
||||
if (fetchedTeams.find((t) => !myTeamsIds.has(t.id) && t.delete_at === 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fetchedTeams.length === PER_PAGE_DEFAULT) {
|
||||
return recCanJoinTeams(client, myTeamsIds, page + 1);
|
||||
return recCanJoinTeams(client, myTeamsIds, page + 1, groupLabel);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -298,7 +298,7 @@ export async function fetchTeamsForComponent(
|
|||
return {teams: alreadyLoaded, hasMore: false, page};
|
||||
}
|
||||
|
||||
export const updateCanJoinTeams = async (serverUrl: string) => {
|
||||
export const updateCanJoinTeams = async (serverUrl: string, groupLabel?: string) => {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
|
@ -306,7 +306,7 @@ export const updateCanJoinTeams = async (serverUrl: string) => {
|
|||
const myTeams = await queryMyTeams(database).fetch();
|
||||
const myTeamsIds = new Set(myTeams.map((m) => m.id));
|
||||
|
||||
const canJoin = await recCanJoinTeams(client, myTeamsIds, 0);
|
||||
const canJoin = await recCanJoinTeams(client, myTeamsIds, 0, groupLabel);
|
||||
|
||||
EphemeralStore.setCanJoinOtherTeams(serverUrl, canJoin);
|
||||
return {};
|
||||
|
|
@ -320,7 +320,7 @@ export const updateCanJoinTeams = async (serverUrl: string) => {
|
|||
|
||||
export const fetchTeamsChannelsThreadsAndUnreadPosts = async (
|
||||
serverUrl: string, since: number, teams: Team[],
|
||||
isCRTEnabled?: boolean, fetchOnly = false,
|
||||
isCRTEnabled?: boolean, fetchOnly = false, groupLabel?: string,
|
||||
) => {
|
||||
try {
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
|
@ -331,7 +331,7 @@ export const fetchTeamsChannelsThreadsAndUnreadPosts = async (
|
|||
for await (const myTeams of chunks) {
|
||||
const promises = [];
|
||||
for (const team of myTeams) {
|
||||
promises.push(fetchMyChannelsForTeam(serverUrl, team.id, true, since, true, true, isCRTEnabled));
|
||||
promises.push(fetchMyChannelsForTeam(serverUrl, team.id, true, since, true, true, isCRTEnabled, groupLabel));
|
||||
}
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
|
|
@ -356,8 +356,8 @@ export const fetchTeamsChannelsThreadsAndUnreadPosts = async (
|
|||
}
|
||||
}
|
||||
|
||||
const unreadPromise = fetchPostsForUnreadChannels(serverUrl, channels, members, undefined, true);
|
||||
const threadsPromise = syncThreadsIfNeeded(serverUrl, isCRTEnabled ?? false, myTeams, true);
|
||||
const unreadPromise = fetchPostsForUnreadChannels(serverUrl, channels, members, undefined, true, groupLabel);
|
||||
const threadsPromise = syncThreadsIfNeeded(serverUrl, isCRTEnabled ?? false, myTeams, true, groupLabel);
|
||||
const postPromises: [Promise<PostsForChannel[]>, Promise<{models?: Model[]; error?: unknown}>] = [
|
||||
unreadPromise,
|
||||
threadsPromise,
|
||||
|
|
|
|||
|
|
@ -39,14 +39,14 @@ enum Direction {
|
|||
Down,
|
||||
}
|
||||
|
||||
export const fetchAndSwitchToThread = async (serverUrl: string, rootId: string, isFromNotification = false) => {
|
||||
export const fetchAndSwitchToThread = async (serverUrl: string, rootId: string, isFromNotification = false, groupLabel?: string) => {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
|
||||
if (!database) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
// Load thread before we open to the thread modal
|
||||
fetchPostThread(serverUrl, rootId);
|
||||
fetchPostThread(serverUrl, rootId, undefined, false, groupLabel);
|
||||
|
||||
// Mark thread as read
|
||||
const isCRTEnabled = await getIsCRTEnabled(database);
|
||||
|
|
@ -71,7 +71,7 @@ export const fetchAndSwitchToThread = async (serverUrl: string, rootId: string,
|
|||
if (currentChannelId === post?.channelId) {
|
||||
AppsManager.copyMainBindingsToThread(serverUrl, currentChannelId);
|
||||
} else {
|
||||
AppsManager.fetchBindings(serverUrl, post.channelId, true);
|
||||
AppsManager.fetchBindings(serverUrl, post.channelId, true, groupLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,6 +214,7 @@ export const fetchThreads = async (
|
|||
options: FetchThreadsOptions,
|
||||
direction?: Direction,
|
||||
pages?: number,
|
||||
groupLabel?: string,
|
||||
) => {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
|
|
@ -243,7 +244,12 @@ export const fetchThreads = async (
|
|||
const {before, after, perPage = General.CRT_CHUNK_SIZE, deleted, unread, since, excludeDirect = false} = opts;
|
||||
|
||||
currentPage++;
|
||||
const {threads} = await client.getThreads(currentUser.id, teamId, before, after, perPage, deleted, unread, since, false, version, excludeDirect);
|
||||
const {threads} = await client.getThreads(
|
||||
currentUser.id, teamId,
|
||||
before, after, perPage,
|
||||
deleted, unread, since, false, version,
|
||||
excludeDirect, groupLabel,
|
||||
);
|
||||
if (threads.length) {
|
||||
// Mark all fetched threads as following
|
||||
for (const thread of threads) {
|
||||
|
|
@ -279,7 +285,10 @@ export const fetchThreads = async (
|
|||
return {error: false, threads: threadsData};
|
||||
};
|
||||
|
||||
export const syncThreadsIfNeeded = async (serverUrl: string, isCRTEnabled: boolean, teams?: Team[], fetchOnly = false) => {
|
||||
export const syncThreadsIfNeeded = async (
|
||||
serverUrl: string, isCRTEnabled: boolean, teams?: Team[],
|
||||
fetchOnly = false, groupLabel?: string,
|
||||
) => {
|
||||
try {
|
||||
if (!isCRTEnabled) {
|
||||
return {models: []};
|
||||
|
|
@ -291,7 +300,7 @@ export const syncThreadsIfNeeded = async (serverUrl: string, isCRTEnabled: boole
|
|||
|
||||
if (teams?.length) {
|
||||
for (const team of teams) {
|
||||
promises.push(syncTeamThreads(serverUrl, team.id, true, true));
|
||||
promises.push(syncTeamThreads(serverUrl, team.id, true, true, groupLabel));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -304,10 +313,9 @@ export const syncThreadsIfNeeded = async (serverUrl: string, isCRTEnabled: boole
|
|||
}
|
||||
}
|
||||
|
||||
const flat = models.flat();
|
||||
const flat = removeDuplicatesModels(models.flat());
|
||||
if (!fetchOnly && flat.length) {
|
||||
const uniqueArray = removeDuplicatesModels(flat);
|
||||
await operator.batchRecords(uniqueArray, 'syncThreadsIfNeeded');
|
||||
await operator.batchRecords(flat, 'syncThreadsIfNeeded');
|
||||
}
|
||||
|
||||
return {models: flat};
|
||||
|
|
@ -317,7 +325,10 @@ export const syncThreadsIfNeeded = async (serverUrl: string, isCRTEnabled: boole
|
|||
}
|
||||
};
|
||||
|
||||
export const syncTeamThreads = async (serverUrl: string, teamId: string, excludeDirect = false, fetchOnly = false) => {
|
||||
export const syncTeamThreads = async (
|
||||
serverUrl: string, teamId: string,
|
||||
excludeDirect = false, fetchOnly = false, groupLabel?: string,
|
||||
) => {
|
||||
try {
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const syncData = await getTeamThreadsSyncData(database, teamId);
|
||||
|
|
@ -341,6 +352,8 @@ export const syncTeamThreads = async (serverUrl: string, teamId: string, exclude
|
|||
teamId,
|
||||
{unread: true, excludeDirect},
|
||||
Direction.Down,
|
||||
undefined,
|
||||
groupLabel,
|
||||
),
|
||||
fetchThreads(
|
||||
serverUrl,
|
||||
|
|
@ -348,6 +361,7 @@ export const syncTeamThreads = async (serverUrl: string, teamId: string, exclude
|
|||
{excludeDirect},
|
||||
undefined,
|
||||
1,
|
||||
groupLabel,
|
||||
),
|
||||
]);
|
||||
if (allUnreadThreads.error || latestThreads.error) {
|
||||
|
|
@ -373,6 +387,9 @@ export const syncTeamThreads = async (serverUrl: string, teamId: string, exclude
|
|||
serverUrl,
|
||||
teamId,
|
||||
{deleted: true, since: syncData.latest + 1, excludeDirect},
|
||||
undefined,
|
||||
undefined,
|
||||
groupLabel,
|
||||
);
|
||||
if (allNewThreads.error) {
|
||||
return {error: allNewThreads.error};
|
||||
|
|
|
|||
|
|
@ -43,12 +43,12 @@ export type ProfilesInChannelRequest = {
|
|||
error?: unknown;
|
||||
}
|
||||
|
||||
export const fetchMe = async (serverUrl: string, fetchOnly = false): Promise<MyUserRequest> => {
|
||||
export const fetchMe = async (serverUrl: string, fetchOnly = false, groupLabel?: string): Promise<MyUserRequest> => {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const resultSettled = await Promise.allSettled([client.getMe(), client.getStatus('me')]);
|
||||
const resultSettled = await Promise.allSettled([client.getMe(groupLabel), client.getStatus('me', groupLabel)]);
|
||||
let user: UserProfile|undefined;
|
||||
let userStatus: UserStatus|undefined;
|
||||
for (const result of resultSettled) {
|
||||
|
|
@ -96,12 +96,15 @@ export const refetchCurrentUser = async (serverUrl: string, currentUserId: strin
|
|||
setCurrentUserId(operator, user.id);
|
||||
};
|
||||
|
||||
export async function fetchProfilesInChannel(serverUrl: string, channelId: string, excludeUserId?: string, options?: GetUsersOptions, fetchOnly = false): Promise<ProfilesInChannelRequest> {
|
||||
export async function fetchProfilesInChannel(
|
||||
serverUrl: string, channelId: string, excludeUserId?: string, options?: GetUsersOptions,
|
||||
fetchOnly = false, groupLabel?: string,
|
||||
): Promise<ProfilesInChannelRequest> {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const users = await client.getProfilesInChannel(channelId, options);
|
||||
const users = await client.getProfilesInChannel(channelId, options, groupLabel);
|
||||
const uniqueUsers = Array.from(new Set(users));
|
||||
const filteredUsers = uniqueUsers.filter((u) => u.id !== excludeUserId);
|
||||
if (!fetchOnly) {
|
||||
|
|
@ -131,7 +134,7 @@ export async function fetchProfilesInChannel(serverUrl: string, channelId: strin
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchProfilesInGroupChannels(serverUrl: string, groupChannelIds: string[], fetchOnly = false): Promise<ProfilesPerChannelRequest> {
|
||||
export async function fetchProfilesInGroupChannels(serverUrl: string, groupChannelIds: string[], fetchOnly = false, groupLabel?: string): Promise<ProfilesPerChannelRequest> {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
|
@ -147,7 +150,7 @@ export async function fetchProfilesInGroupChannels(serverUrl: string, groupChann
|
|||
const gms = chunk(channelsToFetch, 50);
|
||||
const data: ProfilesInChannelRequest[] = [];
|
||||
|
||||
const requests = gms.map((cIds) => client.getProfilesInGroupChannels(cIds));
|
||||
const requests = gms.map((cIds) => client.getProfilesInGroupChannels(cIds, groupLabel));
|
||||
const response = await Promise.all(requests);
|
||||
for (const r of response) {
|
||||
for (const id in r) {
|
||||
|
|
@ -194,7 +197,10 @@ export async function fetchProfilesInGroupChannels(serverUrl: string, groupChann
|
|||
}
|
||||
}
|
||||
|
||||
export async function fetchProfilesPerChannels(serverUrl: string, channelIds: string[], excludeUserId?: string, fetchOnly = false): Promise<ProfilesPerChannelRequest> {
|
||||
export async function fetchProfilesPerChannels(
|
||||
serverUrl: string, channelIds: string[], excludeUserId?: string,
|
||||
fetchOnly = false, groupLabel?: string,
|
||||
): Promise<ProfilesPerChannelRequest> {
|
||||
try {
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
|
|
@ -203,7 +209,7 @@ export async function fetchProfilesPerChannels(serverUrl: string, channelIds: st
|
|||
const data: ProfilesInChannelRequest[] = [];
|
||||
|
||||
for await (const cIds of channels) {
|
||||
const requests = cIds.map((id) => fetchProfilesInChannel(serverUrl, id, excludeUserId, undefined, true));
|
||||
const requests = cIds.map((id) => fetchProfilesInChannel(serverUrl, id, excludeUserId, undefined, true, groupLabel));
|
||||
const response = await Promise.all(requests);
|
||||
data.push(...response);
|
||||
}
|
||||
|
|
@ -244,12 +250,12 @@ export async function fetchProfilesPerChannels(serverUrl: string, channelIds: st
|
|||
}
|
||||
}
|
||||
|
||||
export const updateMe = async (serverUrl: string, user: Partial<UserProfile>) => {
|
||||
export const updateMe = async (serverUrl: string, user: Partial<UserProfile>, groupLabel?: string) => {
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const {operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
const data = await client.patchMe(user);
|
||||
const data = await client.patchMe(user, groupLabel);
|
||||
|
||||
if (data) {
|
||||
operator.handleUsers({prepareRecordsOnly: false, users: [data]});
|
||||
|
|
@ -422,7 +428,7 @@ export const fetchUserByIdBatched = async (serverUrl: string, userId: string) =>
|
|||
usersByIdBatch.timeout = setTimeout(processBatch, TIME_TO_BATCH);
|
||||
};
|
||||
|
||||
export const fetchUsersByIds = async (serverUrl: string, userIds: string[], fetchOnly = false) => {
|
||||
export const fetchUsersByIds = async (serverUrl: string, userIds: string[], fetchOnly = false, groupLabel?: string) => {
|
||||
if (!userIds.length) {
|
||||
return {users: [], existingUsers: []};
|
||||
}
|
||||
|
|
@ -444,7 +450,7 @@ export const fetchUsersByIds = async (serverUrl: string, userIds: string[], fetc
|
|||
if (usersToLoad.size === 0) {
|
||||
return {users: [], existingUsers};
|
||||
}
|
||||
const users = await client.getProfilesByIds([...new Set(usersToLoad)]);
|
||||
const users = await client.getProfilesByIds([...new Set(usersToLoad)], {}, groupLabel);
|
||||
if (!fetchOnly && users.length) {
|
||||
await operator.handleUsers({
|
||||
users,
|
||||
|
|
@ -626,7 +632,7 @@ export const fetchMissingProfilesByUsernames = async (serverUrl: string, usernam
|
|||
return {users};
|
||||
};
|
||||
|
||||
export async function updateAllUsersSince(serverUrl: string, since: number, fetchOnly = false) {
|
||||
export async function updateAllUsersSince(serverUrl: string, since: number, fetchOnly = false, groupLabel?: string) {
|
||||
if (!since) {
|
||||
return {users: []};
|
||||
}
|
||||
|
|
@ -638,7 +644,7 @@ export async function updateAllUsersSince(serverUrl: string, since: number, fetc
|
|||
|
||||
const currentUserId = await getCurrentUserId(database);
|
||||
const userIds = (await queryAllUsers(database).fetchIds()).filter((id) => id !== currentUserId);
|
||||
userUpdates = await client.getProfilesByIds(userIds, {since});
|
||||
userUpdates = await client.getProfilesByIds(userIds, {since}, groupLabel);
|
||||
if (userUpdates.length && !fetchOnly) {
|
||||
const modelsToBatch: Model[] = [];
|
||||
const userModels = await operator.handleUsers({users: userUpdates, prepareRecordsOnly: true});
|
||||
|
|
@ -801,7 +807,7 @@ export const buildProfileImageUrlFromUser = (serverUrl: string, user: UserModel
|
|||
return buildProfileImageUrl(serverUrl, user.id, lastPictureUpdate);
|
||||
};
|
||||
|
||||
export const autoUpdateTimezone = async (serverUrl: string) => {
|
||||
export const autoUpdateTimezone = async (serverUrl: string, groupLabel?: string) => {
|
||||
let database;
|
||||
try {
|
||||
const result = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
|
@ -824,7 +830,7 @@ export const autoUpdateTimezone = async (serverUrl: string) => {
|
|||
|
||||
if (currentTimezone.useAutomaticTimezone && newTimezoneExists) {
|
||||
const timezone = {useAutomaticTimezone: 'true', automaticTimezone: deviceTimezone, manualTimezone: currentTimezone.manualTimezone};
|
||||
await updateMe(serverUrl, {timezone});
|
||||
await updateMe(serverUrl, {timezone}, groupLabel);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -36,17 +36,17 @@ import {setTeamLoading} from '@store/team_load_store';
|
|||
import {isTablet} from '@utils/helpers';
|
||||
import {logDebug, logInfo} from '@utils/log';
|
||||
|
||||
export async function handleFirstConnect(serverUrl: string) {
|
||||
setExtraSessionProps(serverUrl);
|
||||
autoUpdateTimezone(serverUrl);
|
||||
return doReconnect(serverUrl);
|
||||
export async function handleFirstConnect(serverUrl: string, groupLabel?: string) {
|
||||
setExtraSessionProps(serverUrl, groupLabel);
|
||||
autoUpdateTimezone(serverUrl, groupLabel);
|
||||
return doReconnect(serverUrl, groupLabel);
|
||||
}
|
||||
|
||||
export async function handleReconnect(serverUrl: string) {
|
||||
return doReconnect(serverUrl);
|
||||
return doReconnect(serverUrl, 'reconnection');
|
||||
}
|
||||
|
||||
async function doReconnect(serverUrl: string) {
|
||||
async function doReconnect(serverUrl: string, groupLabel?: string) {
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
if (!operator) {
|
||||
return new Error('cannot find server database');
|
||||
|
|
@ -66,7 +66,7 @@ async function doReconnect(serverUrl: string) {
|
|||
const currentChannelId = await getCurrentChannelId(database);
|
||||
|
||||
setTeamLoading(serverUrl, true);
|
||||
const entryData = await entry(serverUrl, currentTeamId, currentChannelId, lastFullSync);
|
||||
const entryData = await entry(serverUrl, currentTeamId, currentChannelId, lastFullSync, groupLabel);
|
||||
if ('error' in entryData) {
|
||||
setTeamLoading(serverUrl, false);
|
||||
return entryData.error;
|
||||
|
|
@ -85,34 +85,34 @@ async function doReconnect(serverUrl: string) {
|
|||
const tabletDevice = isTablet();
|
||||
const isActiveServer = (await getActiveServerUrl()) === serverUrl;
|
||||
if (isActiveServer && tabletDevice && initialChannelId === currentChannelId) {
|
||||
await markChannelAsRead(serverUrl, initialChannelId);
|
||||
await markChannelAsRead(serverUrl, initialChannelId, false, groupLabel);
|
||||
markChannelAsViewed(serverUrl, initialChannelId);
|
||||
}
|
||||
|
||||
logInfo('WEBSOCKET RECONNECT MODELS BATCHING TOOK', `${Date.now() - dt}ms`);
|
||||
setTeamLoading(serverUrl, false);
|
||||
|
||||
await fetchPostDataIfNeeded(serverUrl);
|
||||
await fetchPostDataIfNeeded(serverUrl, groupLabel);
|
||||
|
||||
const {id: currentUserId, locale: currentUserLocale} = (await getCurrentUser(database))!;
|
||||
const license = await getLicense(database);
|
||||
const config = await getConfig(database);
|
||||
|
||||
if (isSupportedServerCalls(config?.Version)) {
|
||||
loadConfigAndCalls(serverUrl, currentUserId);
|
||||
loadConfigAndCalls(serverUrl, currentUserId, groupLabel);
|
||||
}
|
||||
|
||||
await deferredAppEntryActions(serverUrl, lastFullSync, currentUserId, currentUserLocale, prefData.preferences, config, license, teamData, chData, initialTeamId);
|
||||
await deferredAppEntryActions(serverUrl, lastFullSync, currentUserId, currentUserLocale, prefData.preferences, config, license, teamData, chData, initialTeamId, undefined, groupLabel);
|
||||
|
||||
openAllUnreadChannels(serverUrl);
|
||||
openAllUnreadChannels(serverUrl, groupLabel);
|
||||
|
||||
dataRetentionCleanup(serverUrl);
|
||||
|
||||
AppsManager.refreshAppBindings(serverUrl);
|
||||
AppsManager.refreshAppBindings(serverUrl, groupLabel);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function fetchPostDataIfNeeded(serverUrl: string) {
|
||||
async function fetchPostDataIfNeeded(serverUrl: string, groupLabel?: string) {
|
||||
try {
|
||||
const isActiveServer = (await getActiveServerUrl()) === serverUrl;
|
||||
if (!isActiveServer) {
|
||||
|
|
@ -139,15 +139,15 @@ async function fetchPostDataIfNeeded(serverUrl: string) {
|
|||
options.fromCreateAt = lastPost.createAt;
|
||||
options.fromPost = lastPost.id;
|
||||
options.direction = 'down';
|
||||
await fetchPostThread(serverUrl, rootId, options);
|
||||
await fetchPostThread(serverUrl, rootId, options, false, groupLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentChannelId && (isChannelScreenMounted || tabletDevice)) {
|
||||
await fetchPostsForChannel(serverUrl, currentChannelId);
|
||||
markChannelAsRead(serverUrl, currentChannelId);
|
||||
await fetchPostsForChannel(serverUrl, currentChannelId, false, groupLabel);
|
||||
markChannelAsRead(serverUrl, currentChannelId, false, groupLabel);
|
||||
if (!EphemeralStore.wasNotificationTapped()) {
|
||||
markChannelAsViewed(serverUrl, currentChannelId, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import type ClientBase from './base';
|
|||
|
||||
export interface ClientAppsMix {
|
||||
executeAppCall: <Res = unknown>(call: AppCallRequest, trackAsSubmit: boolean) => Promise<AppCallResponse<Res>>;
|
||||
getAppsBindings: (userID: string, channelID: string, teamID: string) => Promise<AppBinding[]>;
|
||||
getAppsBindings: (userID: string, channelID: string, teamID: string, groupLabel?: string) => Promise<AppBinding[]>;
|
||||
}
|
||||
|
||||
const ClientApps = <TBase extends Constructor<ClientBase>>(superclass: TBase) => class extends superclass {
|
||||
|
|
@ -27,7 +27,7 @@ const ClientApps = <TBase extends Constructor<ClientBase>>(superclass: TBase) =>
|
|||
);
|
||||
};
|
||||
|
||||
getAppsBindings = async (userID: string, channelID: string, teamID: string) => {
|
||||
getAppsBindings = async (userID: string, channelID: string, teamID: string, groupLabel?: string) => {
|
||||
const params = {
|
||||
user_id: userID,
|
||||
channel_id: channelID,
|
||||
|
|
@ -37,7 +37,7 @@ const ClientApps = <TBase extends Constructor<ClientBase>>(superclass: TBase) =>
|
|||
|
||||
return this.doFetch(
|
||||
`${this.getAppsProxyRoute()}/api/v1/bindings${buildQueryString(params)}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,33 +1,16 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DeviceEventEmitter} from 'react-native';
|
||||
|
||||
import {Events, Calls} from '@constants';
|
||||
import {t} from '@i18n';
|
||||
import {setServerCredentials} from '@init/credentials';
|
||||
import {semverFromServerVersion} from '@utils/server';
|
||||
import {Calls} from '@constants';
|
||||
|
||||
import * as ClientConstants from './constants';
|
||||
import ClientError from './error';
|
||||
import ClientTracking from './tracking';
|
||||
|
||||
import type {
|
||||
APIClientInterface,
|
||||
ClientHeaders,
|
||||
ClientResponse,
|
||||
RequestOptions,
|
||||
} from '@mattermost/react-native-network-client';
|
||||
|
||||
export default class ClientBase {
|
||||
apiClient: APIClientInterface;
|
||||
csrfToken = '';
|
||||
requestHeaders: {[x: string]: string} = {};
|
||||
serverVersion = '';
|
||||
urlVersion = '/api/v4';
|
||||
enableLogging = false;
|
||||
import type {APIClientInterface} from '@mattermost/react-native-network-client';
|
||||
|
||||
export default class ClientBase extends ClientTracking {
|
||||
constructor(apiClient: APIClientInterface, serverUrl: string, bearerToken?: string, csrfToken?: string) {
|
||||
this.apiClient = apiClient;
|
||||
super(apiClient);
|
||||
|
||||
if (bearerToken) {
|
||||
this.setBearerToken(bearerToken);
|
||||
|
|
@ -54,16 +37,6 @@ export default class ClientBase {
|
|||
return this.apiClient.baseUrl + baseUrl;
|
||||
}
|
||||
|
||||
getRequestHeaders(requestMethod: string) {
|
||||
const headers = {...this.requestHeaders};
|
||||
|
||||
if (this.csrfToken && requestMethod.toLowerCase() !== 'get') {
|
||||
headers[ClientConstants.HEADER_X_CSRF_TOKEN] = this.csrfToken;
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
getWebSocketUrl = () => {
|
||||
return `${this.urlVersion}/websocket`;
|
||||
};
|
||||
|
|
@ -72,15 +45,6 @@ export default class ClientBase {
|
|||
this.requestHeaders[ClientConstants.HEADER_ACCEPT_LANGUAGE] = locale;
|
||||
}
|
||||
|
||||
setBearerToken(bearerToken: string) {
|
||||
this.requestHeaders[ClientConstants.HEADER_AUTH] = `${ClientConstants.HEADER_BEARER} ${bearerToken}`;
|
||||
setServerCredentials(this.apiClient.baseUrl, bearerToken);
|
||||
}
|
||||
|
||||
setCSRFToken(csrfToken: string) {
|
||||
this.csrfToken = csrfToken;
|
||||
}
|
||||
|
||||
// Routes
|
||||
|
||||
getUsersRoute() {
|
||||
|
|
@ -236,96 +200,6 @@ export default class ClientBase {
|
|||
}
|
||||
|
||||
doFetch = async (url: string, options: ClientOptions, returnDataOnly = true) => {
|
||||
let request;
|
||||
const method = options.method?.toLowerCase();
|
||||
switch (method) {
|
||||
case 'get':
|
||||
request = this.apiClient!.get;
|
||||
break;
|
||||
case 'put':
|
||||
request = this.apiClient!.put;
|
||||
break;
|
||||
case 'post':
|
||||
request = this.apiClient!.post;
|
||||
break;
|
||||
case 'patch':
|
||||
request = this.apiClient!.patch;
|
||||
break;
|
||||
case 'delete':
|
||||
request = this.apiClient!.delete;
|
||||
break;
|
||||
default:
|
||||
throw new ClientError(this.apiClient.baseUrl, {
|
||||
message: 'Invalid request method',
|
||||
intl: {
|
||||
id: t('mobile.request.invalid_request_method'),
|
||||
defaultMessage: 'Invalid request method',
|
||||
},
|
||||
url,
|
||||
});
|
||||
}
|
||||
|
||||
const requestOptions: RequestOptions = {
|
||||
body: options.body,
|
||||
headers: this.getRequestHeaders(method),
|
||||
};
|
||||
if (options.noRetry) {
|
||||
requestOptions.retryPolicyConfiguration = {
|
||||
retryLimit: 0,
|
||||
};
|
||||
}
|
||||
if (options.timeoutInterval) {
|
||||
requestOptions.timeoutInterval = options.timeoutInterval;
|
||||
}
|
||||
|
||||
if (options.headers) {
|
||||
if (requestOptions.headers) {
|
||||
requestOptions.headers = {
|
||||
...requestOptions.headers,
|
||||
...options.headers,
|
||||
};
|
||||
} else {
|
||||
requestOptions.headers = options.headers;
|
||||
}
|
||||
}
|
||||
|
||||
let response: ClientResponse;
|
||||
try {
|
||||
response = await request!(url, requestOptions);
|
||||
} catch (error) {
|
||||
throw new ClientError(this.apiClient.baseUrl, {
|
||||
message: 'Received invalid response from the server.',
|
||||
intl: {
|
||||
id: t('mobile.request.invalid_response'),
|
||||
defaultMessage: 'Received invalid response from the server.',
|
||||
},
|
||||
url,
|
||||
details: error,
|
||||
});
|
||||
}
|
||||
|
||||
const headers: ClientHeaders = response.headers || {};
|
||||
const serverVersion = semverFromServerVersion(headers[ClientConstants.HEADER_X_VERSION_ID] || headers[ClientConstants.HEADER_X_VERSION_ID.toLowerCase()]);
|
||||
const hasCacheControl = Boolean(headers[ClientConstants.HEADER_CACHE_CONTROL] || headers[ClientConstants.HEADER_CACHE_CONTROL.toLowerCase()]);
|
||||
if (serverVersion && !hasCacheControl && this.serverVersion !== serverVersion) {
|
||||
this.serverVersion = serverVersion;
|
||||
DeviceEventEmitter.emit(Events.SERVER_VERSION_CHANGED, {serverUrl: this.apiClient.baseUrl, serverVersion});
|
||||
}
|
||||
|
||||
const bearerToken = headers[ClientConstants.HEADER_TOKEN] || headers[ClientConstants.HEADER_TOKEN.toLowerCase()];
|
||||
if (bearerToken) {
|
||||
this.setBearerToken(bearerToken);
|
||||
}
|
||||
|
||||
if (response.ok) {
|
||||
return returnDataOnly ? (response.data || {}) : response;
|
||||
}
|
||||
|
||||
throw new ClientError(this.apiClient.baseUrl, {
|
||||
message: response.data?.message as string || `Response with status code ${response.code}`,
|
||||
server_error_id: response.data?.id as string,
|
||||
status_code: response.code,
|
||||
url,
|
||||
});
|
||||
return this.doFetchWithTracking(url, options, returnDataOnly);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,17 +4,17 @@
|
|||
import type ClientBase from './base';
|
||||
|
||||
export interface ClientCategoriesMix {
|
||||
getCategories: (userId: string, teamId: string) => Promise<CategoriesWithOrder>;
|
||||
getCategories: (userId: string, teamId: string, groupLabel?: string) => Promise<CategoriesWithOrder>;
|
||||
getCategoriesOrder: (userId: string, teamId: string) => Promise<string[]>;
|
||||
getCategory: (userId: string, teamId: string, categoryId: string) => Promise<Category>;
|
||||
updateChannelCategories: (userId: string, teamId: string, categories: CategoryWithChannels[]) => Promise<CategoriesWithOrder>;
|
||||
}
|
||||
|
||||
const ClientCategories = <TBase extends Constructor<ClientBase>>(superclass: TBase) => class extends superclass {
|
||||
getCategories = async (userId: string, teamId: string) => {
|
||||
getCategories = async (userId: string, teamId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getCategoriesRoute(userId, teamId)}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
getCategoriesOrder = async (userId: string, teamId: string) => {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export interface ClientChannelBookmarksMix {
|
|||
updateChannelBookmark(channelId: string, bookmark: ChannelBookmark, connectionId?: string): Promise<UpdateChannelBookmarkResponse>;
|
||||
updateChannelBookmarkSortOrder(channelId: string, bookmarkId: string, newSortOrder: number, connectionId?: string): Promise<ChannelBookmarkWithFileInfo[]>;
|
||||
deleteChannelBookmark(channelId: string, bookmarkId: string, connectionId?: string): Promise<ChannelBookmarkWithFileInfo>;
|
||||
getChannelBookmarksForChannel(channelId: string, since: number): Promise<ChannelBookmarkWithFileInfo[]>;
|
||||
getChannelBookmarksForChannel(channelId: string, since: number, groupLabel?: string): Promise<ChannelBookmarkWithFileInfo[]>;
|
||||
}
|
||||
|
||||
const ClientChannelBookmarks = <TBase extends Constructor<ClientBase>>(superclass: TBase) => class extends superclass {
|
||||
|
|
@ -57,10 +57,10 @@ const ClientChannelBookmarks = <TBase extends Constructor<ClientBase>>(superclas
|
|||
);
|
||||
}
|
||||
|
||||
getChannelBookmarksForChannel(channelId: string, since: number) {
|
||||
getChannelBookmarksForChannel(channelId: string, since: number, groupLabel?: string) {
|
||||
return this.doFetch(
|
||||
`${this.getChannelBookmarksRoute(channelId)}${buildQueryString({bookmarks_since: since})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,24 +19,24 @@ export interface ClientChannelsMix {
|
|||
updateChannelPrivacy: (channelId: string, privacy: any) => Promise<Channel>;
|
||||
patchChannel: (channelId: string, channelPatch: Partial<Channel>) => Promise<Channel>;
|
||||
updateChannelNotifyProps: (props: ChannelNotifyProps & {channel_id: string; user_id: string}) => Promise<any>;
|
||||
getChannel: (channelId: string) => Promise<Channel>;
|
||||
getChannel: (channelId: string, groupLabel?: string) => Promise<Channel>;
|
||||
getChannelByName: (teamId: string, channelName: string, includeDeleted?: boolean) => Promise<Channel>;
|
||||
getChannelByNameAndTeamName: (teamName: string, channelName: string, includeDeleted?: boolean) => Promise<Channel>;
|
||||
getChannels: (teamId: string, page?: number, perPage?: number) => Promise<Channel[]>;
|
||||
getArchivedChannels: (teamId: string, page?: number, perPage?: number) => Promise<Channel[]>;
|
||||
getSharedChannels: (teamId: string, page?: number, perPage?: number) => Promise<Channel[]>;
|
||||
getMyChannels: (teamId: string, includeDeleted?: boolean, lastDeleteAt?: number) => Promise<Channel[]>;
|
||||
getMyChannels: (teamId: string, includeDeleted?: boolean, lastDeleteAt?: number, groupLabel?: string) => Promise<Channel[]>;
|
||||
getMyChannelMember: (channelId: string) => Promise<ChannelMembership>;
|
||||
getMyChannelMembers: (teamId: string) => Promise<ChannelMembership[]>;
|
||||
getMyChannelMembers: (teamId: string, groupLabel?: string) => Promise<ChannelMembership[]>;
|
||||
getChannelMembers: (channelId: string, page?: number, perPage?: number) => Promise<ChannelMembership[]>;
|
||||
getChannelTimezones: (channelId: string) => Promise<string[]>;
|
||||
getChannelMember: (channelId: string, userId: string) => Promise<ChannelMembership>;
|
||||
getChannelMember: (channelId: string, userId: string, groupLabel?: string) => Promise<ChannelMembership>;
|
||||
getChannelMembersByIds: (channelId: string, userIds: string[]) => Promise<ChannelMembership[]>;
|
||||
addToChannel: (userId: string, channelId: string, postRootId?: string) => Promise<ChannelMembership>;
|
||||
removeFromChannel: (userId: string, channelId: string) => Promise<any>;
|
||||
getChannelStats: (channelId: string) => Promise<ChannelStats>;
|
||||
getChannelStats: (channelId: string, groupLabel?: string) => Promise<ChannelStats>;
|
||||
getChannelMemberCountsByGroup: (channelId: string, includeTimezones: boolean) => Promise<ChannelMemberCountByGroup[]>;
|
||||
viewMyChannel: (channelId: string, prevChannelId?: string) => Promise<any>;
|
||||
viewMyChannel: (channelId: string, prevChannelId?: string, groupLabel?: string) => Promise<any>;
|
||||
autocompleteChannels: (teamId: string, name: string) => Promise<Channel[]>;
|
||||
autocompleteChannelsForSearch: (teamId: string, name: string) => Promise<Channel[]>;
|
||||
searchChannels: (teamId: string, term: string) => Promise<Channel[]>;
|
||||
|
|
@ -130,10 +130,10 @@ const ClientChannels = <TBase extends Constructor<ClientBase>>(superclass: TBase
|
|||
);
|
||||
};
|
||||
|
||||
getChannel = async (channelId: string) => {
|
||||
getChannel = async (channelId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
this.getChannelRoute(channelId),
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -180,13 +180,13 @@ const ClientChannels = <TBase extends Constructor<ClientBase>>(superclass: TBase
|
|||
);
|
||||
};
|
||||
|
||||
getMyChannels = async (teamId: string, includeDeleted = false, since = 0) => {
|
||||
getMyChannels = async (teamId: string, includeDeleted = false, since = 0, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUserRoute('me')}/teams/${teamId}/channels${buildQueryString({
|
||||
include_deleted: includeDeleted,
|
||||
last_delete_at: since,
|
||||
})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -197,10 +197,10 @@ const ClientChannels = <TBase extends Constructor<ClientBase>>(superclass: TBase
|
|||
);
|
||||
};
|
||||
|
||||
getMyChannelMembers = async (teamId: string) => {
|
||||
getMyChannelMembers = async (teamId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUserRoute('me')}/teams/${teamId}/channels/members`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -218,10 +218,10 @@ const ClientChannels = <TBase extends Constructor<ClientBase>>(superclass: TBase
|
|||
);
|
||||
};
|
||||
|
||||
getChannelMember = async (channelId: string, userId: string) => {
|
||||
getChannelMember = async (channelId: string, userId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getChannelMemberRoute(channelId, userId)}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -247,10 +247,10 @@ const ClientChannels = <TBase extends Constructor<ClientBase>>(superclass: TBase
|
|||
);
|
||||
};
|
||||
|
||||
getChannelStats = async (channelId: string) => {
|
||||
getChannelStats = async (channelId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getChannelRoute(channelId)}/stats`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -261,12 +261,12 @@ const ClientChannels = <TBase extends Constructor<ClientBase>>(superclass: TBase
|
|||
);
|
||||
};
|
||||
|
||||
viewMyChannel = async (channelId: string, prevChannelId?: string) => {
|
||||
viewMyChannel = async (channelId: string, prevChannelId?: string, groupLabel?: string) => {
|
||||
// collapsed_threads_supported is not based on user preferences but to know if "CLIENT" supports CRT
|
||||
const data = {channel_id: channelId, prev_channel_id: prevChannelId, collapsed_threads_supported: true};
|
||||
return this.doFetch(
|
||||
`${this.getChannelsRoute()}/members/me/view`,
|
||||
{method: 'post', body: data},
|
||||
{method: 'post', body: data, groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,28 +14,28 @@ type PoliciesResponse<T> = {
|
|||
}
|
||||
|
||||
export interface ClientGeneralMix {
|
||||
ping: (deviceId?: string, timeoutInterval?: number) => Promise<any>;
|
||||
ping: (deviceId?: string, timeoutInterval?: number, groupLabel?: string) => Promise<any>;
|
||||
logClientError: (message: string, level?: string) => Promise<any>;
|
||||
getClientConfigOld: () => Promise<ClientConfig>;
|
||||
getClientLicenseOld: () => Promise<ClientLicense>;
|
||||
getClientConfigOld: (groupLabel?: string) => Promise<ClientConfig>;
|
||||
getClientLicenseOld: (groupLabel?: string) => Promise<ClientLicense>;
|
||||
getTimezones: () => Promise<string[]>;
|
||||
getGlobalDataRetentionPolicy: () => Promise<GlobalDataRetentionPolicy>;
|
||||
getTeamDataRetentionPolicies: (userId: string, page?: number, perPage?: number) => Promise<PoliciesResponse<TeamDataRetentionPolicy>>;
|
||||
getChannelDataRetentionPolicies: (userId: string, page?: number, perPage?: number) => Promise<PoliciesResponse<ChannelDataRetentionPolicy>>;
|
||||
getRolesByNames: (rolesNames: string[]) => Promise<Role[]>;
|
||||
getGlobalDataRetentionPolicy: (groupLabel?: string) => Promise<GlobalDataRetentionPolicy>;
|
||||
getTeamDataRetentionPolicies: (userId: string, page?: number, perPage?: number, groupLabel?: string) => Promise<PoliciesResponse<TeamDataRetentionPolicy>>;
|
||||
getChannelDataRetentionPolicies: (userId: string, page?: number, perPage?: number, groupLabel?: string) => Promise<PoliciesResponse<ChannelDataRetentionPolicy>>;
|
||||
getRolesByNames: (rolesNames: string[], groupLabel?: string) => Promise<Role[]>;
|
||||
getRedirectLocation: (urlParam: string) => Promise<Record<string, string>>;
|
||||
sendPerformanceReport: (batch: PerformanceReport) => Promise<{}>;
|
||||
}
|
||||
|
||||
const ClientGeneral = <TBase extends Constructor<ClientBase>>(superclass: TBase) => class extends superclass {
|
||||
ping = async (deviceId?: string, timeoutInterval?: number) => {
|
||||
ping = async (deviceId?: string, timeoutInterval?: number, groupLabel?: string) => {
|
||||
let url = `${this.urlVersion}/system/ping?time=${Date.now()}`;
|
||||
if (deviceId) {
|
||||
url = `${url}&device_id=${deviceId}`;
|
||||
}
|
||||
return this.doFetch(
|
||||
url,
|
||||
{method: 'get', timeoutInterval},
|
||||
{method: 'get', timeoutInterval, groupLabel},
|
||||
false,
|
||||
);
|
||||
};
|
||||
|
|
@ -56,17 +56,17 @@ const ClientGeneral = <TBase extends Constructor<ClientBase>>(superclass: TBase)
|
|||
);
|
||||
};
|
||||
|
||||
getClientConfigOld = async () => {
|
||||
getClientConfigOld = async (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.urlVersion}/config/client?format=old`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getClientLicenseOld = async () => {
|
||||
getClientLicenseOld = async (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.urlVersion}/license/client?format=old`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -77,31 +77,31 @@ const ClientGeneral = <TBase extends Constructor<ClientBase>>(superclass: TBase)
|
|||
);
|
||||
};
|
||||
|
||||
getGlobalDataRetentionPolicy = () => {
|
||||
getGlobalDataRetentionPolicy = (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getGlobalDataRetentionRoute()}/policy`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getTeamDataRetentionPolicies = (userId: string, page = 0, perPage = PER_PAGE_DEFAULT) => {
|
||||
getTeamDataRetentionPolicies = (userId: string, page = 0, perPage = PER_PAGE_DEFAULT, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getGranularDataRetentionRoute(userId)}/team_policies${buildQueryString({page, per_page: perPage})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getChannelDataRetentionPolicies = (userId: string, page = 0, perPage = PER_PAGE_DEFAULT) => {
|
||||
getChannelDataRetentionPolicies = (userId: string, page = 0, perPage = PER_PAGE_DEFAULT, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getGranularDataRetentionRoute(userId)}/channel_policies${buildQueryString({page, per_page: perPage})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getRolesByNames = async (rolesNames: string[]) => {
|
||||
getRolesByNames = async (rolesNames: string[], groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getRolesRoute()}/names`,
|
||||
{method: 'post', body: rolesNames},
|
||||
{method: 'post', body: rolesNames, groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import type ClientBase from './base';
|
|||
|
||||
export interface ClientGroupsMix {
|
||||
getGroups: (params: {query?: string; filterAllowReference?: boolean; page?: number; perPage?: number; since?: number; includeMemberCount?: boolean}) => Promise<Group[]>;
|
||||
getAllGroupsAssociatedToChannel: (channelId: string, filterAllowReference?: boolean) => Promise<{groups: Group[]; total_group_count: number}>;
|
||||
getAllGroupsAssociatedToMembership: (userId: string, filterAllowReference?: boolean) => Promise<Group[]>;
|
||||
getAllGroupsAssociatedToChannel: (channelId: string, filterAllowReference?: boolean, groupLabel?: string) => Promise<{groups: Group[]; total_group_count: number}>;
|
||||
getAllGroupsAssociatedToMembership: (userId: string, filterAllowReference?: boolean, groupLabel?: string) => Promise<Group[]>;
|
||||
getAllGroupsAssociatedToTeam: (teamId: string, filterAllowReference?: boolean) => Promise<{groups: Group[]; total_group_count: number}>;
|
||||
}
|
||||
|
||||
|
|
@ -29,14 +29,14 @@ const ClientGroups = <TBase extends Constructor<ClientBase>>(superclass: TBase)
|
|||
);
|
||||
};
|
||||
|
||||
getAllGroupsAssociatedToChannel = async (channelId: string, filterAllowReference = false) => {
|
||||
getAllGroupsAssociatedToChannel = async (channelId: string, filterAllowReference = false, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.urlVersion}/channels/${channelId}/groups${buildQueryString({
|
||||
paginate: false,
|
||||
filter_allow_reference: filterAllowReference,
|
||||
include_member_count: true,
|
||||
})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -47,10 +47,10 @@ const ClientGroups = <TBase extends Constructor<ClientBase>>(superclass: TBase)
|
|||
);
|
||||
};
|
||||
|
||||
getAllGroupsAssociatedToMembership = async (userId: string, filterAllowReference = false) => {
|
||||
getAllGroupsAssociatedToMembership = async (userId: string, filterAllowReference = false, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.urlVersion}/users/${userId}/groups${buildQueryString({paginate: false, filter_allow_reference: filterAllowReference})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import type ClientBase from './base';
|
|||
export interface ClientPostsMix {
|
||||
createPost: (post: Post) => Promise<Post>;
|
||||
updatePost: (post: Post) => Promise<Post>;
|
||||
getPost: (postId: string) => Promise<Post>;
|
||||
getPost: (postId: string, groupLabel?: string) => Promise<Post>;
|
||||
patchPost: (postPatch: Partial<Post> & {id: string}) => Promise<Post>;
|
||||
deletePost: (postId: string) => Promise<any>;
|
||||
getPostThread: (postId: string, options: FetchPaginatedThreadOptions) => Promise<PostResponse>;
|
||||
getPosts: (channelId: string, page?: number, perPage?: number, collapsedThreads?: boolean, collapsedThreadsExtended?: boolean) => Promise<PostResponse>;
|
||||
getPostsSince: (channelId: string, since: number, collapsedThreads?: boolean, collapsedThreadsExtended?: boolean) => Promise<PostResponse>;
|
||||
getPostThread: (postId: string, options: FetchPaginatedThreadOptions, groupLabel?: string) => Promise<PostResponse>;
|
||||
getPosts: (channelId: string, page?: number, perPage?: number, collapsedThreads?: boolean, collapsedThreadsExtended?: boolean, groupLabel?: string) => Promise<PostResponse>;
|
||||
getPostsSince: (channelId: string, since: number, collapsedThreads?: boolean, collapsedThreadsExtended?: boolean, groupLabel?: string) => Promise<PostResponse>;
|
||||
getPostsBefore: (channelId: string, postId?: string, page?: number, perPage?: number, collapsedThreads?: boolean, collapsedThreadsExtended?: boolean) => Promise<PostResponse>;
|
||||
getPostsAfter: (channelId: string, postId: string, page?: number, perPage?: number, collapsedThreads?: boolean, collapsedThreadsExtended?: boolean) => Promise<PostResponse>;
|
||||
getFileInfosForPost: (postId: string) => Promise<FileInfo[]>;
|
||||
|
|
@ -51,10 +51,10 @@ const ClientPosts = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getPost = async (postId: string) => {
|
||||
getPost = async (postId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getPostRoute(postId)}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ const ClientPosts = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getPostThread = (postId: string, options: FetchPaginatedThreadOptions) => {
|
||||
getPostThread = (postId: string, options: FetchPaginatedThreadOptions, groupLabel?: string) => {
|
||||
const {
|
||||
fetchThreads = true,
|
||||
collapsedThreads = false,
|
||||
|
|
@ -84,21 +84,21 @@ const ClientPosts = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
} = options;
|
||||
return this.doFetch(
|
||||
`${this.getPostRoute(postId)}/thread${buildQueryString({skipFetchThreads: !fetchThreads, collapsedThreads, collapsedThreadsExtended, direction, perPage, ...rest})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getPosts = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT, collapsedThreads = false, collapsedThreadsExtended = false) => {
|
||||
getPosts = async (channelId: string, page = 0, perPage = PER_PAGE_DEFAULT, collapsedThreads = false, collapsedThreadsExtended = false, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getChannelRoute(channelId)}/posts${buildQueryString({page, per_page: perPage, collapsedThreads, collapsedThreadsExtended})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getPostsSince = async (channelId: string, since: number, collapsedThreads = false, collapsedThreadsExtended = false) => {
|
||||
getPostsSince = async (channelId: string, since: number, collapsedThreads = false, collapsedThreadsExtended = false, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getChannelRoute(channelId)}/posts${buildQueryString({since, collapsedThreads, collapsedThreadsExtended})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,23 +4,23 @@
|
|||
import type ClientBase from './base';
|
||||
|
||||
export interface ClientPreferencesMix {
|
||||
savePreferences: (userId: string, preferences: PreferenceType[]) => Promise<any>;
|
||||
savePreferences: (userId: string, preferences: PreferenceType[], groupLabel?: string) => Promise<any>;
|
||||
deletePreferences: (userId: string, preferences: PreferenceType[]) => Promise<any>;
|
||||
getMyPreferences: () => Promise<PreferenceType[]>;
|
||||
getMyPreferences: (groupLabel?: string) => Promise<PreferenceType[]>;
|
||||
}
|
||||
|
||||
const ClientPreferences = <TBase extends Constructor<ClientBase>>(superclass: TBase) => class extends superclass {
|
||||
savePreferences = async (userId: string, preferences: PreferenceType[]) => {
|
||||
savePreferences = async (userId: string, preferences: PreferenceType[], groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getPreferencesRoute(userId)}`,
|
||||
{method: 'put', body: preferences},
|
||||
{method: 'put', body: preferences, groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getMyPreferences = async () => {
|
||||
getMyPreferences = async (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getPreferencesRoute('me')}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -12,14 +12,14 @@ export interface ClientTeamsMix {
|
|||
deleteTeam: (teamId: string) => Promise<any>;
|
||||
updateTeam: (team: Team) => Promise<Team>;
|
||||
patchTeam: (team: Partial<Team> & {id: string}) => Promise<Team>;
|
||||
getTeams: (page?: number, perPage?: number, includeTotalCount?: boolean) => Promise<Team[]>;
|
||||
getTeam: (teamId: string) => Promise<Team>;
|
||||
getTeams: (page?: number, perPage?: number, includeTotalCount?: boolean, groupLabel?: string) => Promise<Team[]>;
|
||||
getTeam: (teamId: string, groupLabel?: string) => Promise<Team>;
|
||||
getTeamByName: (teamName: string) => Promise<Team>;
|
||||
getMyTeams: () => Promise<Team[]>;
|
||||
getMyTeams: (groupLabel?: string) => Promise<Team[]>;
|
||||
getTeamsForUser: (userId: string) => Promise<Team[]>;
|
||||
getMyTeamMembers: () => Promise<TeamMembership[]>;
|
||||
getMyTeamMembers: (groupLabel?: string) => Promise<TeamMembership[]>;
|
||||
getTeamMembers: (teamId: string, page?: number, perPage?: number) => Promise<TeamMembership[]>;
|
||||
getTeamMember: (teamId: string, userId: string) => Promise<TeamMembership>;
|
||||
getTeamMember: (teamId: string, userId: string, groupLabel?: string) => Promise<TeamMembership>;
|
||||
getTeamMembersByIds: (teamId: string, userIds: string[]) => Promise<TeamMembership[]>;
|
||||
addToTeam: (teamId: string, userId: string) => Promise<TeamMembership>;
|
||||
addUsersToTeamGracefully: (teamId: string, userIds: string[]) => Promise<TeamMemberWithError[]>;
|
||||
|
|
@ -59,17 +59,17 @@ const ClientTeams = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getTeams = async (page = 0, perPage = PER_PAGE_DEFAULT, includeTotalCount = false) => {
|
||||
getTeams = async (page = 0, perPage = PER_PAGE_DEFAULT, includeTotalCount = false, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getTeamsRoute()}${buildQueryString({page, per_page: perPage, include_total_count: includeTotalCount})}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getTeam = async (teamId: string) => {
|
||||
getTeam = async (teamId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
this.getTeamRoute(teamId),
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -80,10 +80,10 @@ const ClientTeams = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getMyTeams = async () => {
|
||||
getMyTeams = async (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUserRoute('me')}/teams`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -94,10 +94,10 @@ const ClientTeams = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getMyTeamMembers = async () => {
|
||||
getMyTeamMembers = async (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUserRoute('me')}/teams/members`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -108,10 +108,10 @@ const ClientTeams = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getTeamMember = async (teamId: string, userId: string) => {
|
||||
getTeamMember = async (teamId: string, userId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getTeamMemberRoute(teamId, userId)}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,12 @@ import {PER_PAGE_DEFAULT} from './constants';
|
|||
import type ClientBase from './base';
|
||||
|
||||
export interface ClientThreadsMix {
|
||||
getThreads: (userId: string, teamId: string, before?: string, after?: string, pageSize?: number, deleted?: boolean, unread?: boolean, since?: number, totalsOnly?: boolean, serverVersion?: string, excludeDirect?: boolean) => Promise<GetUserThreadsResponse>;
|
||||
getThreads: (
|
||||
userId: string, teamId: string,
|
||||
before?: string, after?: string, pageSize?: number,
|
||||
deleted?: boolean, unread?: boolean, since?: number, totalsOnly?: boolean, serverVersion?: string,
|
||||
excludeDirect?: boolean, groupLabel?: string,
|
||||
) => Promise<GetUserThreadsResponse>;
|
||||
getThread: (userId: string, teamId: string, threadId: string, extended?: boolean) => Promise<any>;
|
||||
markThreadAsRead: (userId: string, teamId: string, threadId: string, timestamp: number) => Promise<any>;
|
||||
markThreadAsUnread: (userId: string, teamId: string, threadId: string, postId: string) => Promise<any>;
|
||||
|
|
@ -17,7 +22,11 @@ export interface ClientThreadsMix {
|
|||
}
|
||||
|
||||
const ClientThreads = <TBase extends Constructor<ClientBase>>(superclass: TBase) => class extends superclass {
|
||||
getThreads = async (userId: string, teamId: string, before = '', after = '', pageSize = PER_PAGE_DEFAULT, deleted = false, unread = false, since = 0, totalsOnly = false, serverVersion = '', excludeDirect = false) => {
|
||||
getThreads = async (
|
||||
userId: string, teamId: string,
|
||||
before = '', after = '', pageSize = PER_PAGE_DEFAULT,
|
||||
deleted = false, unread = false, since = 0, totalsOnly = false, serverVersion = '',
|
||||
excludeDirect = false, groupLabel?: string) => {
|
||||
const queryStringObj: Record<string, any> = {
|
||||
extended: 'true',
|
||||
before,
|
||||
|
|
@ -35,7 +44,7 @@ const ClientThreads = <TBase extends Constructor<ClientBase>>(superclass: TBase)
|
|||
}
|
||||
return this.doFetch(
|
||||
`${this.getThreadsRoute(userId, teamId)}${buildQueryString(queryStringObj)}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
269
app/client/rest/tracking.test.ts
Normal file
269
app/client/rest/tracking.test.ts
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import test_helper from '@test/test_helper';
|
||||
|
||||
import * as ClientConstants from './constants';
|
||||
import ClientTracking from './tracking';
|
||||
|
||||
import type {APIClientInterface, ClientResponseMetrics} from '@mattermost/react-native-network-client';
|
||||
|
||||
jest.mock('react-native', () => ({
|
||||
DeviceEventEmitter: {
|
||||
emit: jest.fn(),
|
||||
},
|
||||
Platform: {
|
||||
OS: 'ios',
|
||||
select: jest.fn(({ios, default: def}: any) => {
|
||||
return ios ?? def;
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('@mattermost/rnutils', () => ({
|
||||
getIOSAppGroupDetails: jest.fn().mockRejectedValue(''),
|
||||
isRunningInSplitView: jest.fn().mockReturnValue({isSplit: false, isTablet: false}),
|
||||
}));
|
||||
|
||||
jest.mock('expo-crypto', () => ({
|
||||
randomUUID: jest.fn(() => '12345678-1234-1234-1234-1234567890ab'),
|
||||
}));
|
||||
|
||||
jest.mock('@i18n', () => ({
|
||||
t: jest.fn((key) => key),
|
||||
}));
|
||||
|
||||
jest.mock('@utils/file', () => ({
|
||||
getFormattedFileSize: jest.fn((size) => `${size} bytes`),
|
||||
}));
|
||||
|
||||
jest.mock('@utils/log', () => ({
|
||||
logDebug: jest.fn(),
|
||||
logInfo: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('@utils/server', () => ({
|
||||
semverFromServerVersion: jest.fn((version) => version),
|
||||
}));
|
||||
|
||||
jest.mock('@init/credentials', () => ({
|
||||
setServerCredentials: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('ClientTraking', () => {
|
||||
const apiClientMock = {
|
||||
baseUrl: 'https://example.com',
|
||||
get: jest.fn(),
|
||||
post: jest.fn(),
|
||||
put: jest.fn(),
|
||||
patch: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
};
|
||||
|
||||
let client: ClientTracking;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
client = new ClientTracking(apiClientMock as unknown as APIClientInterface);
|
||||
});
|
||||
|
||||
it('should set bearer token', () => {
|
||||
const token = 'testToken';
|
||||
client.setBearerToken(token);
|
||||
|
||||
expect(client.requestHeaders[ClientConstants.HEADER_AUTH]).toBe(`${ClientConstants.HEADER_BEARER} ${token}`);
|
||||
expect(require('@init/credentials').setServerCredentials).toHaveBeenCalledWith(apiClientMock.baseUrl, token);
|
||||
});
|
||||
|
||||
it('should set CSRF token', () => {
|
||||
const token = 'csrfToken';
|
||||
client.setCSRFToken(token);
|
||||
|
||||
expect(client.csrfToken).toBe(token);
|
||||
});
|
||||
|
||||
it('should get request headers', () => {
|
||||
client.setCSRFToken('csrfToken');
|
||||
client.setBearerToken('testToken');
|
||||
|
||||
const headers = client.getRequestHeaders('POST');
|
||||
expect(headers[ClientConstants.HEADER_AUTH]).toBe(`${ClientConstants.HEADER_BEARER} testToken`);
|
||||
expect(headers[ClientConstants.HEADER_X_CSRF_TOKEN]).toBe('csrfToken');
|
||||
});
|
||||
|
||||
it('should initialize and track group data', () => {
|
||||
client.initTrackGroup('testGroup');
|
||||
expect(client.requestGroups.has('testGroup')).toBe(true);
|
||||
|
||||
client.trackRequest('testGroup', 'https://example.com/api', {size: 100, compressedSize: 50} as ClientResponseMetrics);
|
||||
const group = client.requestGroups.get('testGroup')!;
|
||||
expect(group.totalSize).toBe(100);
|
||||
expect(group.totalCompressedSize).toBe(50);
|
||||
expect(group.urls['https://example.com/api'].count).toBe(1);
|
||||
});
|
||||
|
||||
it('should increment and decrement request count', () => {
|
||||
client.initTrackGroup('testGroup');
|
||||
client.incrementRequestCount('testGroup');
|
||||
let group = client.requestGroups.get('testGroup')!;
|
||||
expect(group.activeCount).toBe(1);
|
||||
|
||||
client.decrementRequestCount('testGroup');
|
||||
group = client.requestGroups.get('testGroup')!;
|
||||
expect(group.activeCount).toBe(0);
|
||||
});
|
||||
|
||||
it('should handle request completion', () => {
|
||||
client.initTrackGroup('testGroup');
|
||||
client.handleRequestCompletion('testGroup');
|
||||
|
||||
expect(require('@utils/log').logDebug).toHaveBeenCalledWith('Group "testGroup" completed.');
|
||||
});
|
||||
|
||||
it('should clear completion timer', () => {
|
||||
client.initTrackGroup('testGroup');
|
||||
const group = client.requestGroups.get('testGroup')!;
|
||||
group.completionTimer = setTimeout(() => {}, 100);
|
||||
|
||||
client.clearCompletionTimer('testGroup');
|
||||
expect(group.completionTimer).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should check if all requests are completed', () => {
|
||||
client.initTrackGroup('testGroup');
|
||||
const result = client.allRequestsCompleted('testGroup');
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should send telemetry event', () => {
|
||||
client.initTrackGroup('testGroup');
|
||||
const group = client.requestGroups.get('testGroup')!;
|
||||
group.urls = {
|
||||
'https://example.com/api': {
|
||||
count: 2,
|
||||
metrics: {latency: 200, networkType: 'Wi-Fi', tlsCipherSuite: 'none', tlsVersion: 'none', isCached: false, httpVersion: 'h2', compressedSize: 10 * 1024, size: 6 * 1024 * 1024, connectionTime: 0},
|
||||
},
|
||||
};
|
||||
|
||||
client.sendTelemetryEvent('testGroup', group, 1000);
|
||||
expect(require('@utils/log').logInfo).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should build request options', () => {
|
||||
const options = {
|
||||
body: {key: 'value'},
|
||||
method: 'POST',
|
||||
noRetry: true,
|
||||
timeoutInterval: 5000,
|
||||
headers: {custom: 'header'},
|
||||
};
|
||||
|
||||
const result = client.buildRequestOptions(options);
|
||||
expect(result.headers?.custom).toBe('header');
|
||||
expect(result.retryPolicyConfiguration?.retryLimit).toBe(0);
|
||||
expect(result.timeoutInterval).toBe(5000);
|
||||
});
|
||||
|
||||
it('should perform fetch with tracking', async () => {
|
||||
apiClientMock.get.mockResolvedValue({
|
||||
ok: true,
|
||||
data: {success: true},
|
||||
headers: {},
|
||||
});
|
||||
|
||||
const options = {
|
||||
method: 'GET',
|
||||
groupLabel: 'testGroup',
|
||||
};
|
||||
|
||||
const result = await client.doFetchWithTracking('https://example.com/api', options);
|
||||
expect(result).toEqual({success: true});
|
||||
});
|
||||
|
||||
it('should handle fetch errors', async () => {
|
||||
apiClientMock.get.mockRejectedValue(new Error('Request failed'));
|
||||
|
||||
const options = {
|
||||
method: 'GET',
|
||||
groupLabel: 'testGroup',
|
||||
};
|
||||
|
||||
await expect(client.doFetchWithTracking('https://example.com/api', options)).rejects.toThrow('Received invalid response from the server.');
|
||||
});
|
||||
|
||||
it('should call increment and decrement the same number of times as doFetchWithTracking, and handleRequestCompletion only once', async () => {
|
||||
const incrementSpy = jest.spyOn(client, 'incrementRequestCount');
|
||||
const decrementSpy = jest.spyOn(client, 'decrementRequestCount');
|
||||
const handleRequestCompletionSpy = jest.spyOn(client, 'handleRequestCompletion');
|
||||
|
||||
apiClientMock.get.mockImplementation(() => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
ok: true,
|
||||
data: {success: true},
|
||||
headers: {},
|
||||
metrics: {latency: 200, size: 500, compressedSize: 300},
|
||||
});
|
||||
}, 200); // Simulate a 100ms network delay
|
||||
});
|
||||
});
|
||||
|
||||
client.initTrackGroup('testGroup');
|
||||
|
||||
// Simulate multiple fetch calls
|
||||
const promises = [
|
||||
client.doFetchWithTracking('https://example.com/api1', {method: 'GET', groupLabel: 'testGroup'}),
|
||||
client.doFetchWithTracking('https://example.com/api2', {method: 'GET', groupLabel: 'testGroup'}),
|
||||
client.doFetchWithTracking('https://example.com/api3', {method: 'GET', groupLabel: 'testGroup'}),
|
||||
];
|
||||
|
||||
// Wait for all fetches to resolve
|
||||
await Promise.all(promises);
|
||||
|
||||
const group = client.requestGroups.get('testGroup')!;
|
||||
expect(group.activeCount).toBe(0);
|
||||
|
||||
await test_helper.wait(100);
|
||||
|
||||
expect(handleRequestCompletionSpy).toHaveBeenCalledTimes(1);
|
||||
expect(incrementSpy).toHaveBeenCalledTimes(3);
|
||||
expect(decrementSpy).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should track duplicate requests correctly and log duplicate details', async () => {
|
||||
const logDebugSpy = jest.spyOn(require('@utils/log'), 'logDebug');
|
||||
apiClientMock.get.mockResolvedValue({
|
||||
ok: true,
|
||||
data: {success: true},
|
||||
headers: {},
|
||||
metrics: {latency: 150, size: 200, compressedSize: 100},
|
||||
});
|
||||
|
||||
client.initTrackGroup('testGroup');
|
||||
|
||||
// Simulate multiple fetch calls to the same URL
|
||||
const promises = [
|
||||
client.doFetchWithTracking('https://example.com/api', {method: 'GET', groupLabel: 'testGroup'}),
|
||||
client.doFetchWithTracking('https://example.com/api', {method: 'GET', groupLabel: 'testGroup'}),
|
||||
client.doFetchWithTracking('https://example.com/api', {method: 'GET', groupLabel: 'testGroup'}),
|
||||
];
|
||||
|
||||
// Wait for all fetches to resolve
|
||||
await Promise.all(promises);
|
||||
|
||||
// Verify that the group tracked duplicates correctly
|
||||
const group = client.requestGroups.get('testGroup')!;
|
||||
expect(group.urls['https://example.com/api'].count).toBe(3); // URL was requested 3 times
|
||||
expect(group.totalSize).toBe(600); // Total size = 3 * 200
|
||||
expect(group.totalCompressedSize).toBe(300); // Total compressed size = 3 * 100
|
||||
|
||||
await test_helper.wait(100);
|
||||
|
||||
// Verify duplicate logging
|
||||
expect(logDebugSpy).toHaveBeenCalledWith(
|
||||
'Duplicate URLs:\n',
|
||||
expect.stringContaining('https://example.com/api'),
|
||||
);
|
||||
});
|
||||
});
|
||||
263
app/client/rest/tracking.ts
Normal file
263
app/client/rest/tracking.ts
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DeviceEventEmitter, Platform} from 'react-native';
|
||||
|
||||
import {Events} from '@constants';
|
||||
import {t} from '@i18n';
|
||||
import {setServerCredentials} from '@init/credentials';
|
||||
import {getFormattedFileSize} from '@utils/file';
|
||||
import {logDebug, logInfo} from '@utils/log';
|
||||
import {semverFromServerVersion} from '@utils/server';
|
||||
|
||||
import * as ClientConstants from './constants';
|
||||
import ClientError from './error';
|
||||
|
||||
import type {APIClientInterface, ClientHeaders, ClientResponseMetrics, RequestOptions} from '@mattermost/react-native-network-client';
|
||||
|
||||
type UrlData = {
|
||||
count: number;
|
||||
metrics?: ClientResponseMetrics;
|
||||
}
|
||||
|
||||
type GroupData = {
|
||||
activeCount: number;
|
||||
startTime: number;
|
||||
totalSize: number;
|
||||
totalCompressedSize: number;
|
||||
urls: Record<string, UrlData>;
|
||||
completionFlag: boolean;
|
||||
completionTimer?: NodeJS.Timeout;
|
||||
}
|
||||
|
||||
export default class ClientTracking {
|
||||
apiClient: APIClientInterface;
|
||||
csrfToken = '';
|
||||
requestHeaders: {[x: string]: string} = {};
|
||||
serverVersion = '';
|
||||
urlVersion = '/api/v4';
|
||||
enableLogging = false;
|
||||
|
||||
requestGroups: Map<string, GroupData> = new Map();
|
||||
|
||||
constructor(apiClient: APIClientInterface) {
|
||||
this.apiClient = apiClient;
|
||||
}
|
||||
|
||||
setBearerToken(bearerToken: string) {
|
||||
this.requestHeaders[ClientConstants.HEADER_AUTH] = `${ClientConstants.HEADER_BEARER} ${bearerToken}`;
|
||||
setServerCredentials(this.apiClient.baseUrl, bearerToken);
|
||||
}
|
||||
|
||||
setCSRFToken(csrfToken: string) {
|
||||
this.csrfToken = csrfToken;
|
||||
}
|
||||
|
||||
getRequestHeaders(requestMethod: string) {
|
||||
const headers = {...this.requestHeaders};
|
||||
|
||||
if (this.csrfToken && requestMethod.toLowerCase() !== 'get') {
|
||||
headers[ClientConstants.HEADER_X_CSRF_TOKEN] = this.csrfToken;
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
initTrackGroup(groupLabel: string) {
|
||||
if (!this.requestGroups.has(groupLabel)) {
|
||||
this.requestGroups.set(groupLabel, {
|
||||
activeCount: 0,
|
||||
startTime: Date.now(),
|
||||
totalSize: 0,
|
||||
totalCompressedSize: 0,
|
||||
urls: {},
|
||||
completionFlag: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
trackRequest(groupLabel: string, url: string, metrics?: ClientResponseMetrics) {
|
||||
this.initTrackGroup(groupLabel);
|
||||
|
||||
const group = this.requestGroups.get(groupLabel)!;
|
||||
|
||||
if (group.urls[url]) {
|
||||
group.urls[url].count += 1;
|
||||
} else {
|
||||
group.urls[url] = {
|
||||
count: 1,
|
||||
metrics,
|
||||
};
|
||||
}
|
||||
group.totalSize += metrics?.size ?? 0;
|
||||
group.totalCompressedSize += metrics?.compressedSize ?? 0;
|
||||
}
|
||||
|
||||
incrementRequestCount(groupLabel: string) {
|
||||
this.initTrackGroup(groupLabel);
|
||||
|
||||
const group = this.requestGroups.get(groupLabel)!;
|
||||
group.activeCount += 1;
|
||||
}
|
||||
|
||||
decrementRequestCount(groupLabel: string) {
|
||||
const group = this.requestGroups.get(groupLabel);
|
||||
if (group) {
|
||||
group.activeCount -= 1;
|
||||
|
||||
if (group.activeCount <= 0 && !group.completionFlag) {
|
||||
this.clearCompletionTimer(groupLabel);
|
||||
group.completionTimer = setTimeout(() => {
|
||||
if (this.allRequestsCompleted(groupLabel)) {
|
||||
group.completionFlag = true;
|
||||
this.handleRequestCompletion(groupLabel);
|
||||
this.clearCompletionTimer(groupLabel);
|
||||
}
|
||||
}, 100); // Adjust delay as needed (e.g., 100ms) should we set this based on latency or something?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearCompletionTimer(groupLabel: string) {
|
||||
const group = this.requestGroups.get(groupLabel);
|
||||
if (group?.completionTimer) {
|
||||
clearTimeout(group.completionTimer);
|
||||
group.completionTimer = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
handleRequestCompletion(groupLabel: string) {
|
||||
const group = this.requestGroups.get(groupLabel);
|
||||
if (group) {
|
||||
const duration = Date.now() - group.startTime;
|
||||
|
||||
logDebug(`Group "${groupLabel}" completed.`);
|
||||
this.sendTelemetryEvent(groupLabel, group, duration);
|
||||
|
||||
this.requestGroups.delete(groupLabel);
|
||||
}
|
||||
}
|
||||
|
||||
allRequestsCompleted(groupLabel: string): boolean {
|
||||
const group = this.requestGroups.get(groupLabel);
|
||||
return group ? group.activeCount <= 0 : true;
|
||||
}
|
||||
|
||||
sendTelemetryEvent(groupLabel: string, groupData: GroupData, duration: number) {
|
||||
const urls = Object.keys(groupData.urls);
|
||||
const urlData = Object.entries(groupData.urls);
|
||||
const dupe = urlData.filter((u) => u[1].count > 1);
|
||||
const urlCount = urlData.reduce((result, url) => (result + url[1].count), 0);
|
||||
const sumLatency = urlData.reduce((result, url) => (result + (url[1].metrics?.latency ?? 0)), 0);
|
||||
const latency = sumLatency / urlCount;
|
||||
logInfo(`Telemetry event on ${Platform.OS} for server ${this.apiClient.baseUrl}
|
||||
Group "${groupLabel}"
|
||||
requesting ${urls.length} urls
|
||||
total Compressed size of: ${getFormattedFileSize(groupData.totalCompressedSize)}
|
||||
total size of: ${getFormattedFileSize(groupData.totalSize)}
|
||||
elapsed time: ${duration / 1000} seconds
|
||||
average latency: ${latency} ms`);
|
||||
|
||||
if (dupe.length) {
|
||||
logDebug('Duplicate URLs:\n', dupe.map((d) => `${d[0]} ${JSON.stringify(d[1])}`).join('\n'));
|
||||
}
|
||||
|
||||
// Integrate with telemetry framework here
|
||||
}
|
||||
|
||||
buildRequestOptions(options: ClientOptions): RequestOptions {
|
||||
const requestOptions: RequestOptions = {
|
||||
body: options.body,
|
||||
headers: this.getRequestHeaders(options.method!.toLowerCase()),
|
||||
};
|
||||
if (options.noRetry) {
|
||||
requestOptions.retryPolicyConfiguration = {retryLimit: 0};
|
||||
}
|
||||
if (options.timeoutInterval) {
|
||||
requestOptions.timeoutInterval = options.timeoutInterval;
|
||||
}
|
||||
if (options.headers) {
|
||||
requestOptions.headers = {...requestOptions.headers, ...options.headers};
|
||||
}
|
||||
return requestOptions;
|
||||
}
|
||||
|
||||
doFetchWithTracking = async (url: string, options: ClientOptions, returnDataOnly = true) => {
|
||||
let request;
|
||||
const {groupLabel} = options;
|
||||
const method = options.method?.toLowerCase();
|
||||
switch (method) {
|
||||
case 'get': request = this.apiClient!.get;
|
||||
break;
|
||||
case 'put': request = this.apiClient!.put;
|
||||
break;
|
||||
case 'post': request = this.apiClient!.post;
|
||||
break;
|
||||
case 'patch': request = this.apiClient!.patch;
|
||||
break;
|
||||
case 'delete': request = this.apiClient!.delete;
|
||||
break;
|
||||
default:
|
||||
return {error: new ClientError(this.apiClient.baseUrl, {
|
||||
message: 'Invalid request method',
|
||||
intl: {
|
||||
id: t('mobile.request.invalid_request_method'),
|
||||
defaultMessage: 'Invalid request method',
|
||||
},
|
||||
url,
|
||||
})};
|
||||
}
|
||||
|
||||
if (groupLabel) {
|
||||
this.incrementRequestCount(groupLabel);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await request!(url, this.buildRequestOptions(options));
|
||||
const headers: ClientHeaders = response.headers || {};
|
||||
if (groupLabel) {
|
||||
this.trackRequest(groupLabel, url, response.metrics);
|
||||
}
|
||||
const serverVersion = semverFromServerVersion(
|
||||
headers[ClientConstants.HEADER_X_VERSION_ID] || headers[ClientConstants.HEADER_X_VERSION_ID.toLowerCase()],
|
||||
);
|
||||
const hasCacheControl = Boolean(
|
||||
headers[ClientConstants.HEADER_CACHE_CONTROL] || headers[ClientConstants.HEADER_CACHE_CONTROL.toLowerCase()],
|
||||
);
|
||||
if (serverVersion && !hasCacheControl && this.serverVersion !== serverVersion) {
|
||||
this.serverVersion = serverVersion;
|
||||
DeviceEventEmitter.emit(Events.SERVER_VERSION_CHANGED, {serverUrl: this.apiClient.baseUrl, serverVersion});
|
||||
}
|
||||
|
||||
const bearerToken = headers[ClientConstants.HEADER_TOKEN] || headers[ClientConstants.HEADER_TOKEN.toLowerCase()];
|
||||
if (bearerToken) {
|
||||
this.setBearerToken(bearerToken);
|
||||
}
|
||||
|
||||
if (response.ok) {
|
||||
return returnDataOnly ? (response.data || {}) : response;
|
||||
}
|
||||
|
||||
throw new ClientError(this.apiClient.baseUrl, {
|
||||
message: response.data?.message as string || `Response with status code ${response.code}`,
|
||||
server_error_id: response.data?.id as string,
|
||||
status_code: response.code,
|
||||
url,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new ClientError(this.apiClient.baseUrl, {
|
||||
message: 'Received invalid response from the server.',
|
||||
intl: {
|
||||
id: t('mobile.request.invalid_response'),
|
||||
defaultMessage: 'Received invalid response from the server.',
|
||||
},
|
||||
url,
|
||||
details: error,
|
||||
});
|
||||
} finally {
|
||||
if (groupLabel) {
|
||||
this.decrementRequestCount(groupLabel);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ import type ClientBase from './base';
|
|||
|
||||
export interface ClientUsersMix {
|
||||
createUser: (user: UserProfile, token: string, inviteId: string) => Promise<UserProfile>;
|
||||
patchMe: (userPatch: Partial<UserProfile>) => Promise<UserProfile>;
|
||||
patchMe: (userPatch: Partial<UserProfile>, groupLabel?: string) => Promise<UserProfile>;
|
||||
patchUser: (userPatch: Partial<UserProfile> & {id: string}) => Promise<UserProfile>;
|
||||
updateUser: (user: UserProfile) => Promise<UserProfile>;
|
||||
demoteUserToGuest: (userId: string) => Promise<any>;
|
||||
|
|
@ -21,15 +21,15 @@ export interface ClientUsersMix {
|
|||
loginById: (id: string, password: string, token?: string, deviceId?: string) => Promise<UserProfile>;
|
||||
logout: () => Promise<any>;
|
||||
getProfiles: (page?: number, perPage?: number, options?: Record<string, any>) => Promise<UserProfile[]>;
|
||||
getProfilesByIds: (userIds: string[], options?: Record<string, any>) => Promise<UserProfile[]>;
|
||||
getProfilesByUsernames: (usernames: string[]) => Promise<UserProfile[]>;
|
||||
getProfilesByIds: (userIds: string[], options?: Record<string, any>, groupLabel?: string) => Promise<UserProfile[]>;
|
||||
getProfilesByUsernames: (usernames: string[], groupLabel?: string) => Promise<UserProfile[]>;
|
||||
getProfilesInTeam: (teamId: string, page?: number, perPage?: number, sort?: string, options?: Record<string, any>) => Promise<UserProfile[]>;
|
||||
getProfilesNotInTeam: (teamId: string, groupConstrained: boolean, page?: number, perPage?: number) => Promise<UserProfile[]>;
|
||||
getProfilesWithoutTeam: (page?: number, perPage?: number, options?: Record<string, any>) => Promise<UserProfile[]>;
|
||||
getProfilesInChannel: (channelId: string, options?: GetUsersOptions) => Promise<UserProfile[]>;
|
||||
getProfilesInGroupChannels: (channelsIds: string[]) => Promise<{[x: string]: UserProfile[]}>;
|
||||
getProfilesInChannel: (channelId: string, options?: GetUsersOptions, groupLabel?: string) => Promise<UserProfile[]>;
|
||||
getProfilesInGroupChannels: (channelsIds: string[], groupLabel?: string) => Promise<{[x: string]: UserProfile[]}>;
|
||||
getProfilesNotInChannel: (teamId: string, channelId: string, groupConstrained: boolean, page?: number, perPage?: number) => Promise<UserProfile[]>;
|
||||
getMe: () => Promise<UserProfile>;
|
||||
getMe: (groupLabel?: string) => Promise<UserProfile>;
|
||||
getUser: (userId: string) => Promise<UserProfile>;
|
||||
getUserByUsername: (username: string) => Promise<UserProfile>;
|
||||
getUserByEmail: (email: string) => Promise<UserProfile>;
|
||||
|
|
@ -38,10 +38,10 @@ export interface ClientUsersMix {
|
|||
autocompleteUsers: (name: string, teamId: string, channelId?: string, options?: Record<string, any>) => Promise<{users: UserProfile[]; out_of_channel?: UserProfile[]}>;
|
||||
getSessions: (userId: string) => Promise<Session[]>;
|
||||
checkUserMfa: (loginId: string) => Promise<{mfa_required: boolean}>;
|
||||
setExtraSessionProps: (deviceId: string, notificationsEnabled: boolean, version: string | null) => Promise<{}>;
|
||||
setExtraSessionProps: (deviceId: string, notificationsEnabled: boolean, version: string | null, groupLabel?: string) => Promise<{}>;
|
||||
searchUsers: (term: string, options: SearchUserOptions) => Promise<UserProfile[]>;
|
||||
getStatusesByIds: (userIds: string[]) => Promise<UserStatus[]>;
|
||||
getStatus: (userId: string) => Promise<UserStatus>;
|
||||
getStatus: (userId: string, groupLabel?: string) => Promise<UserStatus>;
|
||||
updateStatus: (status: UserStatus) => Promise<UserStatus>;
|
||||
updateCustomStatus: (customStatus: UserCustomStatus) => Promise<{status: string}>;
|
||||
unsetCustomStatus: () => Promise<{status: string}>;
|
||||
|
|
@ -66,10 +66,10 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
patchMe = async (userPatch: Partial<UserProfile>) => {
|
||||
patchMe = async (userPatch: Partial<UserProfile>, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUserRoute('me')}/patch`,
|
||||
{method: 'put', body: userPatch},
|
||||
{method: 'put', body: userPatch, groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
body.ldap_only = 'true';
|
||||
}
|
||||
|
||||
const {data} = await this.doFetch(
|
||||
const resp = await this.doFetch(
|
||||
`${this.getUsersRoute()}/login`,
|
||||
{
|
||||
method: 'post',
|
||||
|
|
@ -137,7 +137,7 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
false,
|
||||
);
|
||||
|
||||
return data;
|
||||
return resp?.data;
|
||||
};
|
||||
|
||||
loginById = async (id: string, password: string, token = '', deviceId = '') => {
|
||||
|
|
@ -148,7 +148,7 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
token,
|
||||
};
|
||||
|
||||
const {data} = await this.doFetch(
|
||||
const resp = await this.doFetch(
|
||||
`${this.getUsersRoute()}/login`,
|
||||
{
|
||||
method: 'post',
|
||||
|
|
@ -158,7 +158,7 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
false,
|
||||
);
|
||||
|
||||
return data;
|
||||
return resp?.data;
|
||||
};
|
||||
|
||||
logout = async () => {
|
||||
|
|
@ -177,17 +177,17 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getProfilesByIds = async (userIds: string[], options = {}) => {
|
||||
getProfilesByIds = async (userIds: string[], options = {}, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUsersRoute()}/ids${buildQueryString(options)}`,
|
||||
{method: 'post', body: userIds},
|
||||
{method: 'post', body: userIds, groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getProfilesByUsernames = async (usernames: string[]) => {
|
||||
getProfilesByUsernames = async (usernames: string[], groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUsersRoute()}/usernames`,
|
||||
{method: 'post', body: usernames},
|
||||
{method: 'post', body: usernames, groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -217,18 +217,18 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getProfilesInChannel = async (channelId: string, options: GetUsersOptions) => {
|
||||
getProfilesInChannel = async (channelId: string, options: GetUsersOptions, groupLabel?: string) => {
|
||||
const queryStringObj = {in_channel: channelId, ...options};
|
||||
return this.doFetch(
|
||||
`${this.getUsersRoute()}${buildQueryString(queryStringObj)}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
getProfilesInGroupChannels = async (channelsIds: string[]) => {
|
||||
getProfilesInGroupChannels = async (channelsIds: string[], groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUsersRoute()}/group_channels`,
|
||||
{method: 'post', body: channelsIds},
|
||||
{method: 'post', body: channelsIds, groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -244,10 +244,10 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getMe = async () => {
|
||||
getMe = async (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUserRoute('me')}`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
setExtraSessionProps = async (deviceId: string, deviceNotificationDisabled: boolean, version: string | null) => {
|
||||
setExtraSessionProps = async (deviceId: string, deviceNotificationDisabled: boolean, version: string | null, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUsersRoute()}/sessions/device`,
|
||||
{
|
||||
|
|
@ -335,6 +335,7 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
device_notification_disabled: deviceNotificationDisabled ? 'true' : 'false',
|
||||
mobile_version: version || '',
|
||||
},
|
||||
groupLabel,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
|
@ -353,10 +354,10 @@ const ClientUsers = <TBase extends Constructor<ClientBase>>(superclass: TBase) =
|
|||
);
|
||||
};
|
||||
|
||||
getStatus = async (userId: string) => {
|
||||
getStatus = async (userId: string, groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getUserRoute(userId)}/status`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,10 @@ const sqliteLikeStringRegex = xRegExp('[^\\p{L}\\p{Nd}]', 'g');
|
|||
export const sanitizeLikeString = (value: string) => value.replace(sqliteLikeStringRegex, '_');
|
||||
|
||||
export function removeDuplicatesModels(array: Model[]) {
|
||||
if (!array.length) {
|
||||
return array;
|
||||
}
|
||||
|
||||
const seen = new Set();
|
||||
return array.filter((item) => {
|
||||
const key = `${item.collection.table}-${item.id}`;
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ const launchToHome = async (props: LaunchProps) => {
|
|||
openPushNotification = Boolean(props.serverUrl && !props.launchError && extra.userInteraction && extra.payload?.channel_id && !extra.payload?.userInfo?.local);
|
||||
if (openPushNotification) {
|
||||
await resetToHome(props);
|
||||
return pushNotificationEntry(props.serverUrl!, extra.payload!);
|
||||
return pushNotificationEntry(props.serverUrl!, extra.payload!, 'notification');
|
||||
}
|
||||
|
||||
appEntry(props.serverUrl!);
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ class AppsManager {
|
|||
}
|
||||
};
|
||||
|
||||
fetchBindings = async (serverUrl: string, channelId: string, forThread = false) => {
|
||||
fetchBindings = async (serverUrl: string, channelId: string, forThread = false, groupLabel?: string) => {
|
||||
try {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const userId = await getCurrentUserId(database);
|
||||
|
|
@ -114,7 +114,7 @@ class AppsManager {
|
|||
}
|
||||
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const fetchedBindings = await client.getAppsBindings(userId, channelId, teamId);
|
||||
const fetchedBindings = await client.getAppsBindings(userId, channelId, teamId, groupLabel);
|
||||
const validatedBindings = validateBindings(fetchedBindings);
|
||||
const bindingsToStore = validatedBindings.length ? validatedBindings : emptyBindings;
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ class AppsManager {
|
|||
}
|
||||
};
|
||||
|
||||
refreshAppBindings = async (serverUrl: string) => {
|
||||
refreshAppBindings = async (serverUrl: string, groupLabel?: string) => {
|
||||
try {
|
||||
const {database} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
const appsEnabled = (await getConfig(database))?.FeatureFlagAppsEnabled === 'true';
|
||||
|
|
@ -147,11 +147,11 @@ class AppsManager {
|
|||
const channelId = await getCurrentChannelId(database);
|
||||
|
||||
// We await here, since errors on this call may clear the thread bindings
|
||||
await this.fetchBindings(serverUrl, channelId);
|
||||
await this.fetchBindings(serverUrl, channelId, false, groupLabel);
|
||||
|
||||
const threadChannelId = this.getThreadsBindingsSubject(serverUrl).value.channelId;
|
||||
if (threadChannelId) {
|
||||
await this.fetchBindings(serverUrl, threadChannelId, true);
|
||||
await this.fetchBindings(serverUrl, threadChannelId, true, groupLabel);
|
||||
}
|
||||
} catch (error) {
|
||||
logDebug('Error refreshing apps', error);
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class NetworkManager {
|
|||
waitsForConnectivity: false,
|
||||
httpMaximumConnectionsPerHost: 100,
|
||||
cancelRequestsOnUnauthorized: true,
|
||||
collectMetrics: false,
|
||||
},
|
||||
retryPolicyConfiguration: {
|
||||
type: RetryTypes.EXPONENTIAL_RETRY,
|
||||
|
|
@ -134,6 +135,7 @@ class NetworkManager {
|
|||
timeoutIntervalForRequest: managedConfig?.timeout ? parseInt(managedConfig.timeout, 10) : this.DEFAULT_CONFIG.sessionConfiguration?.timeoutIntervalForRequest,
|
||||
timeoutIntervalForResource: managedConfig?.timeoutVPN ? parseInt(managedConfig.timeoutVPN, 10) : this.DEFAULT_CONFIG.sessionConfiguration?.timeoutIntervalForResource,
|
||||
waitsForConnectivity: managedConfig?.useVPN === 'true',
|
||||
collectMetrics: LocalConfig.CollectNetworkMetrics,
|
||||
},
|
||||
headers,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -109,16 +109,16 @@ class WebsocketManager {
|
|||
}
|
||||
};
|
||||
|
||||
public openAll = async () => {
|
||||
public openAll = async (groupLabel?: string) => {
|
||||
let queued = 0;
|
||||
for await (const clientUrl of Object.keys(this.clients)) {
|
||||
const activeServerUrl = await DatabaseManager.getActiveServerUrl();
|
||||
if (clientUrl === activeServerUrl) {
|
||||
this.initializeClient(clientUrl);
|
||||
this.initializeClient(clientUrl, groupLabel);
|
||||
} else {
|
||||
queued += 1;
|
||||
this.getConnectedSubject(clientUrl).next('connecting');
|
||||
this.connectionTimerIDs[clientUrl] = setTimeout(() => this.initializeClient(clientUrl), WAIT_UNTIL_NEXT * queued);
|
||||
this.connectionTimerIDs[clientUrl] = setTimeout(() => this.initializeClient(clientUrl, groupLabel), WAIT_UNTIL_NEXT * queued);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -148,7 +148,7 @@ class WebsocketManager {
|
|||
}
|
||||
};
|
||||
|
||||
public initializeClient = async (serverUrl: string) => {
|
||||
public initializeClient = async (serverUrl: string, groupLabel = 'reconnection') => {
|
||||
const client: WebSocketClient = this.clients[serverUrl];
|
||||
clearTimeout(this.connectionTimerIDs[serverUrl]);
|
||||
delete this.connectionTimerIDs[serverUrl];
|
||||
|
|
@ -156,7 +156,7 @@ class WebsocketManager {
|
|||
const hasSynced = this.firstConnectionSynced[serverUrl];
|
||||
client.initialize({}, !hasSynced);
|
||||
if (!hasSynced) {
|
||||
const error = await handleFirstConnect(serverUrl);
|
||||
const error = await handleFirstConnect(serverUrl, groupLabel);
|
||||
if (error) {
|
||||
// This will try to reconnect and try to sync again
|
||||
client.close(false);
|
||||
|
|
@ -271,7 +271,7 @@ class WebsocketManager {
|
|||
}
|
||||
this.isBackgroundTimerRunning = false;
|
||||
if (this.netConnected) {
|
||||
this.openAll();
|
||||
this.openAll('reconnection');
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -390,9 +390,9 @@ describe('Actions.Calls', () => {
|
|||
const {result} = renderHook(() => useCallsConfig('server1'));
|
||||
|
||||
await act(async () => {
|
||||
await CallsActions.loadConfig('server1');
|
||||
await CallsActions.loadConfig('server1', false, 'calls');
|
||||
});
|
||||
expect(mockClient.getCallsConfig).toHaveBeenCalledWith();
|
||||
expect(mockClient.getCallsConfig).toHaveBeenCalledWith('calls');
|
||||
assert.equal(result.current.DefaultEnabled, true);
|
||||
assert.equal(result.current.AllowEnableCalls, true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ import type {IntlShape} from 'react-intl';
|
|||
let connection: CallsConnection | null = null;
|
||||
export const getConnectionForTesting = () => connection;
|
||||
|
||||
export const loadConfig = async (serverUrl: string, force = false) => {
|
||||
export const loadConfig = async (serverUrl: string, force = false, groupLabel?: string) => {
|
||||
const now = Date.now();
|
||||
const config = getCallsConfig(serverUrl);
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ export const loadConfig = async (serverUrl: string, force = false) => {
|
|||
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
const configs = await Promise.all([client.getCallsConfig(), client.getVersion()]);
|
||||
const configs = await Promise.all([client.getCallsConfig(groupLabel), client.getVersion(groupLabel)]);
|
||||
const nextConfig = {...configs[0], version: configs[1], last_retrieved_at: now};
|
||||
setConfig(serverUrl, nextConfig);
|
||||
return {data: nextConfig};
|
||||
|
|
@ -77,11 +77,11 @@ export const loadConfig = async (serverUrl: string, force = false) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const loadCalls = async (serverUrl: string, userId: string) => {
|
||||
export const loadCalls = async (serverUrl: string, userId: string, groupLabel?: string) => {
|
||||
let resp: CallChannelState[] = [];
|
||||
try {
|
||||
const client = NetworkManager.getClient(serverUrl);
|
||||
resp = await client.getCalls() || [];
|
||||
resp = await client.getCalls(groupLabel) || [];
|
||||
} catch (error) {
|
||||
logDebug('error on loadCalls', getFullErrorMessage(error));
|
||||
await forceLogoutIfNecessary(serverUrl, error);
|
||||
|
|
@ -104,7 +104,7 @@ export const loadCalls = async (serverUrl: string, userId: string) => {
|
|||
|
||||
// Batch load user models async because we'll need them later
|
||||
if (ids.size > 0) {
|
||||
fetchUsersByIds(serverUrl, Array.from(ids));
|
||||
fetchUsersByIds(serverUrl, Array.from(ids), false, groupLabel);
|
||||
}
|
||||
|
||||
setCalls(serverUrl, userId, callsResults, enabledChannels);
|
||||
|
|
@ -192,11 +192,11 @@ export const createCallAndAddToIds = (channelId: string, call: CallState, ids?:
|
|||
return convertedCall;
|
||||
};
|
||||
|
||||
export const loadConfigAndCalls = async (serverUrl: string, userId: string) => {
|
||||
export const loadConfigAndCalls = async (serverUrl: string, userId: string, groupLabel?: string) => {
|
||||
const res = await checkIsCallsPluginEnabled(serverUrl);
|
||||
if (res.data) {
|
||||
loadConfig(serverUrl, true);
|
||||
loadCalls(serverUrl, userId);
|
||||
loadConfig(serverUrl, true, groupLabel);
|
||||
loadCalls(serverUrl, userId, groupLabel);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import type {RTCIceServer} from 'react-native-webrtc';
|
|||
|
||||
export interface ClientCallsMix {
|
||||
getEnabled: () => Promise<Boolean>;
|
||||
getCalls: () => Promise<CallChannelState[]>;
|
||||
getCalls: (groupLabel?: string) => Promise<CallChannelState[]>;
|
||||
getCallForChannel: (channelId: string) => Promise<CallChannelState>;
|
||||
getCallsConfig: () => Promise<CallsConfig>;
|
||||
getVersion: () => Promise<CallsVersion>;
|
||||
getCallsConfig: (groupLabel?: string) => Promise<CallsConfig>;
|
||||
getVersion: (groupLabel?: string) => Promise<CallsVersion>;
|
||||
enableChannelCalls: (channelId: string, enable: boolean) => Promise<CallChannelState>;
|
||||
endCall: (channelId: string) => Promise<ApiResp>;
|
||||
genTURNCredentials: () => Promise<RTCIceServer[]>;
|
||||
|
|
@ -38,10 +38,10 @@ const ClientCalls = (superclass: any) => class extends superclass {
|
|||
}
|
||||
};
|
||||
|
||||
getCalls = async () => {
|
||||
getCalls = async (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getCallsRoute()}/channels?mobilev2=true`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -52,18 +52,18 @@ const ClientCalls = (superclass: any) => class extends superclass {
|
|||
);
|
||||
};
|
||||
|
||||
getCallsConfig = async () => {
|
||||
getCallsConfig = async (groupLabel?: string) => {
|
||||
return this.doFetch(
|
||||
`${this.getCallsRoute()}/config`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
) as CallsConfig;
|
||||
};
|
||||
|
||||
getVersion = async () => {
|
||||
getVersion = async (groupLabel?: string) => {
|
||||
try {
|
||||
return this.doFetch(
|
||||
`${this.getCallsRoute()}/version`,
|
||||
{method: 'get'},
|
||||
{method: 'get', groupLabel},
|
||||
);
|
||||
} catch (e) {
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ export const CallNotification = ({
|
|||
const onContainerPress = useCallback(async () => {
|
||||
if (incomingCall.serverUrl !== serverUrl) {
|
||||
await DatabaseManager.setActiveServerDatabase(incomingCall.serverUrl);
|
||||
await WebsocketManager.initializeClient(incomingCall.serverUrl);
|
||||
await WebsocketManager.initializeClient(incomingCall.serverUrl, 'calls');
|
||||
}
|
||||
switchToChannelById(incomingCall.serverUrl, incomingCall.channelID);
|
||||
}, [incomingCall, serverUrl]);
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ const CallScreen = ({
|
|||
await popTopScreen(Screens.THREAD);
|
||||
}
|
||||
await DatabaseManager.setActiveServerDatabase(currentCall.serverUrl);
|
||||
WebsocketManager.initializeClient(currentCall.serverUrl);
|
||||
WebsocketManager.initializeClient(currentCall.serverUrl, 'calls');
|
||||
await goToScreen(Screens.THREAD, callThreadOptionTitle, {rootId: currentCall.threadId});
|
||||
}, [currentCall?.serverUrl, currentCall?.threadId, fromThreadScreen, componentId, callThreadOptionTitle]);
|
||||
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ const ServerItem = ({
|
|||
await dismissBottomSheet();
|
||||
Navigation.updateProps(Screens.HOME, {extra: undefined});
|
||||
DatabaseManager.setActiveServerDatabase(server.url);
|
||||
WebsocketManager.initializeClient(server.url);
|
||||
WebsocketManager.initializeClient(server.url, 'entry');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ describe('handleDeepLink', () => {
|
|||
const result = await handleDeepLink('https://existingserver.com/team/channels/town-square');
|
||||
expect(dismissAllModalsAndPopToRoot).toHaveBeenCalled();
|
||||
expect(DatabaseManager.setActiveServerDatabase).toHaveBeenCalledWith('https://existingserver.com');
|
||||
expect(WebsocketManager.initializeClient).toHaveBeenCalledWith('https://existingserver.com');
|
||||
expect(WebsocketManager.initializeClient).toHaveBeenCalledWith('https://existingserver.com', 'deeplink');
|
||||
expect(result).toEqual({error: false});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export async function handleDeepLink(deepLinkUrl: string, intlShape?: IntlShape,
|
|||
if (existingServerUrl !== currentServerUrl && NavigationStore.getVisibleScreen()) {
|
||||
await dismissAllModalsAndPopToRoot();
|
||||
DatabaseManager.setActiveServerDatabase(existingServerUrl);
|
||||
WebsocketManager.initializeClient(existingServerUrl);
|
||||
WebsocketManager.initializeClient(existingServerUrl, 'deeplink');
|
||||
await NavigationStore.waitUntilScreenHasLoaded(Screens.HOME);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,5 +28,6 @@
|
|||
"ShowOnboarding": false,
|
||||
|
||||
"ExperimentalNormalizeMarkdownLinks": false,
|
||||
"CustomRequestHeaders": {}
|
||||
"CustomRequestHeaders": {},
|
||||
"CollectNetworkMetrics": false
|
||||
}
|
||||
|
|
|
|||
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -21,7 +21,7 @@
|
|||
"@mattermost/compass-icons": "0.1.45",
|
||||
"@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard",
|
||||
"@mattermost/react-native-emm": "1.5.0",
|
||||
"@mattermost/react-native-network-client": "1.7.3",
|
||||
"@mattermost/react-native-network-client": "github:mattermost/react-native-network-client#ad7b88412f41c5a1024420a4f4c7461883cd0e63",
|
||||
"@mattermost/react-native-paste-input": "0.8.0",
|
||||
"@mattermost/react-native-turbo-log": "github:mattermost/react-native-turbo-log#d8ddf5e7974546aff3e83b2c563907eb609ac5f4",
|
||||
"@mattermost/rnshare": "file:./libraries/@mattermost/rnshare",
|
||||
|
|
@ -5891,8 +5891,8 @@
|
|||
},
|
||||
"node_modules/@mattermost/react-native-network-client": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/@mattermost/react-native-network-client/-/react-native-network-client-1.7.3.tgz",
|
||||
"integrity": "sha512-gJSQ4Prf5jcbPlxVylhEtBGafSBYZSat+T21LIDHksGOfeY+jvPL3p8dS+cq+0D1AOHQ3tHNBkZ7RaY6IdUadw==",
|
||||
"resolved": "git+ssh://git@github.com/mattermost/react-native-network-client.git#ad7b88412f41c5a1024420a4f4c7461883cd0e63",
|
||||
"integrity": "sha512-vCKDx7hQowcY0AkhKr4vk1CTMXHaOiPuA4fqvDAepD3RjdfoMdnz1VYXizSuj5pjHKWbuFp+D+L/sL/1G/FUlw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"validator": "13.12.0",
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
"@mattermost/compass-icons": "0.1.45",
|
||||
"@mattermost/hardware-keyboard": "file:./libraries/@mattermost/hardware-keyboard",
|
||||
"@mattermost/react-native-emm": "1.5.0",
|
||||
"@mattermost/react-native-network-client": "1.7.3",
|
||||
"@mattermost/react-native-network-client": "github:mattermost/react-native-network-client#ad7b88412f41c5a1024420a4f4c7461883cd0e63",
|
||||
"@mattermost/react-native-paste-input": "0.8.0",
|
||||
"@mattermost/react-native-turbo-log": "github:mattermost/react-native-turbo-log#d8ddf5e7974546aff3e83b2c563907eb609ac5f4",
|
||||
"@mattermost/rnshare": "file:./libraries/@mattermost/rnshare",
|
||||
|
|
|
|||
1
types/api/client.d.ts
vendored
1
types/api/client.d.ts
vendored
|
|
@ -9,6 +9,7 @@ type ClientOptions = {
|
|||
noRetry?: boolean;
|
||||
timeoutInterval?: number;
|
||||
headers?: Record<string, any>;
|
||||
groupLabel?: string;
|
||||
};
|
||||
|
||||
type ClientErrorIntl =
|
||||
|
|
|
|||
Loading…
Reference in a new issue