From 7c6b34afe39837487c6c8a79675fc14ca3f05d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Fri, 24 Feb 2023 14:35:20 +0100 Subject: [PATCH] Minor performance fixes on message send (#7164) --- app/actions/local/notification.ts | 58 ------------------- app/components/post_list/index.ts | 16 +++-- .../post_list/more_messages/index.ts | 15 +++-- app/queries/servers/channel.ts | 7 +++ app/queries/servers/role.ts | 14 ++--- app/queries/servers/team.ts | 7 +++ app/queries/servers/user.ts | 7 +++ .../channel/channel_post_list/intro/index.ts | 14 ++--- .../channel_info_form.tsx | 2 +- 9 files changed, 57 insertions(+), 83 deletions(-) delete mode 100644 app/actions/local/notification.ts diff --git a/app/actions/local/notification.ts b/app/actions/local/notification.ts deleted file mode 100644 index 1ec0ad85eb..0000000000 --- a/app/actions/local/notification.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -import DatabaseManager from '@database/manager'; -import {getPostById, queryPostsInChannel, queryPostsInThread} from '@queries/servers/post'; -import {logError} from '@utils/log'; - -export const updatePostSinceCache = async (serverUrl: string, notification: NotificationWithData) => { - try { - const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl); - if (notification.payload?.channel_id) { - const chunks = await queryPostsInChannel(database, notification.payload.channel_id).fetch(); - if (chunks.length) { - const recent = chunks[0]; - const lastPost = await getPostById(database, notification.payload.post_id); - if (lastPost) { - await operator.database.write(async () => { - await recent.update(() => { - recent.latest = lastPost.createAt; - }); - }); - } - } - } - return {}; - } catch (error) { - logError('Failed updatePostSinceCache', error); - return {error}; - } -}; - -export const updatePostsInThreadsSinceCache = async (serverUrl: string, notification: NotificationWithData) => { - const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; - if (!operator) { - return {error: `${serverUrl} database not found`}; - } - - try { - if (notification.payload?.root_id) { - const {database} = operator; - const chunks = await queryPostsInThread(database, notification.payload.root_id).fetch(); - if (chunks.length) { - const recent = chunks[0]; - const lastPost = await getPostById(database, notification.payload.post_id); - if (lastPost) { - await operator.database.write(async () => { - await recent.update(() => { - recent.latest = lastPost.createAt; - }); - }); - } - } - } - return {}; - } catch (error) { - return {error}; - } -}; diff --git a/app/components/post_list/index.ts b/app/components/post_list/index.ts index bcb76e3cdd..ae7ea4f3b2 100644 --- a/app/components/post_list/index.ts +++ b/app/components/post_list/index.ts @@ -19,21 +19,25 @@ import PostList from './post_list'; import type {WithDatabaseArgs} from '@typings/database/database'; import type PostModel from '@typings/database/models/servers/post'; -const enhanced = withObservables(['posts'], ({database, posts}: {posts: PostModel[]} & WithDatabaseArgs) => { +const enhancedWithoutPosts = withObservables([], ({database}: WithDatabaseArgs) => { const currentUser = observeCurrentUser(database); - const postIds = posts.map((p) => p.id); - return { appsEnabled: observeConfigBooleanValue(database, 'FeatureFlagAppsEnabled'), isTimezoneEnabled: observeConfigBooleanValue(database, 'ExperimentalTimezone'), currentTimezone: currentUser.pipe((switchMap((user) => of$(getTimezone(user?.timezone || null))))), currentUserId: currentUser.pipe((switchMap((user) => of$(user?.id)))), currentUsername: currentUser.pipe((switchMap((user) => of$(user?.username)))), - savedPostIds: observeSavedPostsByIds(database, postIds), - customEmojiNames: queryAllCustomEmojis(database).observe().pipe( + customEmojiNames: queryAllCustomEmojis(database).observeWithColumns(['name']).pipe( switchMap((customEmojis) => of$(mapCustomEmojiNames(customEmojis))), ), }; }); -export default React.memo(withDatabase(enhanced(PostList))); +const enhanced = withObservables(['posts'], ({database, posts}: {posts: PostModel[]} & WithDatabaseArgs) => { + const postIds = posts.map((p) => p.id); + return { + savedPostIds: observeSavedPostsByIds(database, postIds), + }; +}); + +export default React.memo(withDatabase(enhancedWithoutPosts(enhanced(PostList)))); diff --git a/app/components/post_list/more_messages/index.ts b/app/components/post_list/more_messages/index.ts index ade8c96c6d..507874da72 100644 --- a/app/components/post_list/more_messages/index.ts +++ b/app/components/post_list/more_messages/index.ts @@ -3,8 +3,9 @@ import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider'; import withObservables from '@nozbe/with-observables'; +import React from 'react'; import {of as of$, first as first$} from 'rxjs'; -import {switchMap} from 'rxjs/operators'; +import {distinctUntilChanged, switchMap} from 'rxjs/operators'; import {observeMyChannel} from '@queries/servers/channel'; import {observeThreadById} from '@queries/servers/thread'; @@ -31,8 +32,14 @@ const enhanced = withObservables(['channelId', 'isCRTEnabled', 'rootId'], ({chan } const myChannel = observeMyChannel(database, channelId); - const isManualUnread = myChannel.pipe(switchMap((ch) => of$(ch?.manuallyUnread))); - const unreadCount = myChannel.pipe(switchMap((ch) => of$(ch?.messageCount))); + const isManualUnread = myChannel.pipe( + switchMap((ch) => of$(ch?.manuallyUnread)), + distinctUntilChanged(), + ); + const unreadCount = myChannel.pipe( + switchMap((ch) => of$(ch?.messageCount)), + distinctUntilChanged(), + ); return { isManualUnread, @@ -40,4 +47,4 @@ const enhanced = withObservables(['channelId', 'isCRTEnabled', 'rootId'], ({chan }; }); -export default withDatabase(enhanced(MoreMessages)); +export default React.memo(withDatabase(enhanced(MoreMessages))); diff --git a/app/queries/servers/channel.ts b/app/queries/servers/channel.ts index d32accfce8..ba9b2a8270 100644 --- a/app/queries/servers/channel.ts +++ b/app/queries/servers/channel.ts @@ -211,6 +211,13 @@ export const observeMyChannel = (database: Database, channelId: string) => { ); }; +export const observeMyChannelRoles = (database: Database, channelId: string) => { + return observeMyChannel(database, channelId).pipe( + switchMap((v) => of$(v?.roles)), + distinctUntilChanged(), + ); +}; + export const getChannelById = async (database: Database, channelId: string) => { try { const channel = await database.get(CHANNEL).find(channelId); diff --git a/app/queries/servers/role.ts b/app/queries/servers/role.ts index 58417da697..e3ac7f1dd9 100644 --- a/app/queries/servers/role.ts +++ b/app/queries/servers/role.ts @@ -9,8 +9,8 @@ import {Database as DatabaseConstants, General, Permissions} from '@constants'; import {isDMorGM} from '@utils/channel'; import {hasPermission} from '@utils/role'; -import {observeChannel, observeMyChannel} from './channel'; -import {observeMyTeam} from './team'; +import {observeChannel, observeMyChannelRoles} from './channel'; +import {observeMyTeam, observeMyTeamRoles} from './team'; import type ChannelModel from '@typings/database/models/servers/channel'; import type PostModel from '@typings/database/models/servers/post'; @@ -41,16 +41,16 @@ export function observePermissionForChannel(database: Database, channel: Channel if (!user || !channel) { return of$(defaultValue); } - const myChannel = observeMyChannel(database, channel.id); - const myTeam = channel.teamId ? observeMyTeam(database, channel.teamId) : of$(undefined); + const myChannelRoles = observeMyChannelRoles(database, channel.id); + const myTeamRoles = channel.teamId ? observeMyTeamRoles(database, channel.teamId) : of$(undefined); - return combineLatest([myChannel, myTeam]).pipe(switchMap(([mc, mt]) => { + return combineLatest([myChannelRoles, myTeamRoles]).pipe(switchMap(([mc, mt]) => { const rolesArray = [...user.roles.split(' ')]; if (mc) { - rolesArray.push(...mc.roles.split(' ')); + rolesArray.push(...mc.split(' ')); } if (mt) { - rolesArray.push(...mt.roles.split(' ')); + rolesArray.push(...mt.split(' ')); } return queryRolesByNames(database, rolesArray).observeWithColumns(['permissions']).pipe( switchMap((r) => of$(hasPermission(r, permission))), diff --git a/app/queries/servers/team.ts b/app/queries/servers/team.ts index 2d71b20e6f..d5a7fe96ab 100644 --- a/app/queries/servers/team.ts +++ b/app/queries/servers/team.ts @@ -296,6 +296,13 @@ export const observeMyTeam = (database: Database, teamId: string) => { ); }; +export const observeMyTeamRoles = (database: Database, teamId: string) => { + return observeMyTeam(database, teamId).pipe( + switchMap((v) => of$(v?.roles)), + distinctUntilChanged(), + ); +}; + export const getTeamById = async (database: Database, teamId: string) => { try { const team = (await database.get(TEAM).find(teamId)); diff --git a/app/queries/servers/user.ts b/app/queries/servers/user.ts index 2a76096766..42eab91749 100644 --- a/app/queries/servers/user.ts +++ b/app/queries/servers/user.ts @@ -48,6 +48,13 @@ export const observeCurrentUser = (database: Database) => { ); }; +export const observeCurrentUserRoles = (database: Database) => { + return observeCurrentUser(database).pipe( + switchMap((v) => of$(v?.roles)), + distinctUntilChanged(), + ); +}; + export const queryAllUsers = (database: Database) => { return database.get(USER).query(); }; diff --git a/app/screens/channel/channel_post_list/intro/index.ts b/app/screens/channel/channel_post_list/intro/index.ts index c341e6f374..cf19d46866 100644 --- a/app/screens/channel/channel_post_list/intro/index.ts +++ b/app/screens/channel/channel_post_list/intro/index.ts @@ -6,9 +6,9 @@ import withObservables from '@nozbe/with-observables'; import {combineLatest} from 'rxjs'; import {switchMap} from 'rxjs/operators'; -import {observeChannel, observeMyChannel} from '@queries/servers/channel'; +import {observeChannel, observeMyChannelRoles} from '@queries/servers/channel'; import {queryRolesByNames} from '@queries/servers/role'; -import {observeCurrentUser} from '@queries/servers/user'; +import {observeCurrentUserRoles} from '@queries/servers/user'; import Intro from './intro'; @@ -16,13 +16,13 @@ import type {WithDatabaseArgs} from '@typings/database/database'; const enhanced = withObservables(['channelId'], ({channelId, database}: {channelId: string} & WithDatabaseArgs) => { const channel = observeChannel(database, channelId); - const myChannel = observeMyChannel(database, channelId); - const me = observeCurrentUser(database); + const myChannelRoles = observeMyChannelRoles(database, channelId); + const meRoles = observeCurrentUserRoles(database); - const roles = combineLatest([me, myChannel]).pipe( + const roles = combineLatest([meRoles, myChannelRoles]).pipe( switchMap(([user, member]) => { - const userRoles = user?.roles.split(' '); - const memberRoles = member?.roles.split(' '); + const userRoles = user?.split(' '); + const memberRoles = member?.split(' '); const combinedRoles = []; if (userRoles) { combinedRoles.push(...userRoles); diff --git a/app/screens/create_or_edit_channel/channel_info_form.tsx b/app/screens/create_or_edit_channel/channel_info_form.tsx index 64954583df..33d5e4fe21 100644 --- a/app/screens/create_or_edit_channel/channel_info_form.tsx +++ b/app/screens/create_or_edit_channel/channel_info_form.tsx @@ -17,7 +17,6 @@ import { import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view'; import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context'; -import {useInputPropagation} from '@app/hooks/input'; import Autocomplete from '@components/autocomplete'; import ErrorText from '@components/error_text'; import FloatingTextInput from '@components/floating_text_input_label'; @@ -28,6 +27,7 @@ import {General, Channel} from '@constants'; import {useTheme} from '@context/theme'; import {useAutocompleteDefaultAnimatedValues} from '@hooks/autocomplete'; import {useIsTablet, useKeyboardHeight, useModalPosition} from '@hooks/device'; +import {useInputPropagation} from '@hooks/input'; import {t} from '@i18n'; import { changeOpacity,