From 9bbdca7240b0399573d19bfdba31b54b67df2973 Mon Sep 17 00:00:00 2001 From: Ben Cooke Date: Mon, 2 Oct 2023 12:06:14 -0400 Subject: [PATCH] [MM-54493] Allow a user to disable the webapp prefetch (#24389) * allow a user to disable the webapp prefetch if they are experiencing degraded performance on initial load --------- Co-authored-by: Mattermost Build --- .../data_prefetch/data_prefetch.test.tsx | 2 + .../data_prefetch/data_prefetch.tsx | 14 ++- .../src/components/data_prefetch/index.ts | 7 +- .../user_settings/advanced/index.ts | 5 +- .../advanced/user_settings_advanced.test.tsx | 2 + .../advanced/user_settings_advanced.tsx | 102 ++++++++++++++++++ webapp/channels/src/i18n/en.json | 2 + .../src/constants/preferences.ts | 1 + webapp/channels/src/utils/constants.tsx | 1 + 9 files changed, 131 insertions(+), 5 deletions(-) diff --git a/webapp/channels/src/components/data_prefetch/data_prefetch.test.tsx b/webapp/channels/src/components/data_prefetch/data_prefetch.test.tsx index 222a62e189..04100ed248 100644 --- a/webapp/channels/src/components/data_prefetch/data_prefetch.test.tsx +++ b/webapp/channels/src/components/data_prefetch/data_prefetch.test.tsx @@ -68,6 +68,8 @@ describe('/components/data_prefetch', () => { last_post_at: 1235, last_root_post_at: 1235, })], + disableWebappPrefetchAllowed: false, + dataPrefetchEnabled: true, }; beforeEach(() => { diff --git a/webapp/channels/src/components/data_prefetch/data_prefetch.tsx b/webapp/channels/src/components/data_prefetch/data_prefetch.tsx index 0467fc6fac..fe6e064178 100644 --- a/webapp/channels/src/components/data_prefetch/data_prefetch.tsx +++ b/webapp/channels/src/components/data_prefetch/data_prefetch.tsx @@ -21,6 +21,9 @@ type Props = { sidebarLoaded: boolean; unreadChannels: Channel[]; + + disableWebappPrefetchAllowed: boolean; + dataPrefetchEnabled: boolean; actions: { prefetchChannelPosts: (channelId: string, delay?: number) => Promise; trackPreloadedChannels: (prefetchQueueObj: Record) => void; @@ -52,15 +55,20 @@ export default class DataPrefetch extends React.PureComponent { private prefetchTimeout?: number; async componentDidUpdate(prevProps: Props) { - const {currentChannelId, prefetchQueueObj, sidebarLoaded} = this.props; + const {currentChannelId, prefetchQueueObj, sidebarLoaded, disableWebappPrefetchAllowed, dataPrefetchEnabled} = this.props; + const enablePrefetch = (!disableWebappPrefetchAllowed) || (disableWebappPrefetchAllowed && dataPrefetchEnabled); if (currentChannelId && sidebarLoaded && (!prevProps.currentChannelId || !prevProps.sidebarLoaded)) { queue.add(async () => this.prefetchPosts(currentChannelId)); await loadProfilesForSidebar(); - this.prefetchData(); + if (enablePrefetch) { + this.prefetchData(); + } } else if (prevProps.prefetchQueueObj !== prefetchQueueObj) { clearTimeout(this.prefetchTimeout); await queue.clear(); - this.prefetchData(); + if (enablePrefetch) { + this.prefetchData(); + } } if (currentChannelId && sidebarLoaded && (!prevProps.currentChannelId || !prevProps.sidebarLoaded)) { diff --git a/webapp/channels/src/components/data_prefetch/index.ts b/webapp/channels/src/components/data_prefetch/index.ts index 00f7ee18de..e8fc8ad9f0 100644 --- a/webapp/channels/src/components/data_prefetch/index.ts +++ b/webapp/channels/src/components/data_prefetch/index.ts @@ -9,9 +9,11 @@ import type {Channel, ChannelMembership} from '@mattermost/types/channels'; import type {PostList} from '@mattermost/types/posts'; import type {RelationOneToOne} from '@mattermost/types/utilities'; +import {Preferences} from 'mattermost-redux/constants'; import {getCurrentChannelId, getUnreadChannels} from 'mattermost-redux/selectors/entities/channels'; import {getMyChannelMemberships} from 'mattermost-redux/selectors/entities/common'; -import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences'; +import {isPerformanceDebuggingEnabled} from 'mattermost-redux/selectors/entities/general'; +import {getBool, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences'; import {isChannelMuted} from 'mattermost-redux/utils/channel_utils'; import {memoizeResult} from 'mattermost-redux/utils/helpers'; @@ -82,6 +84,7 @@ function mapStateToProps(state: GlobalState) { const unreadChannels = getUnreadChannels(state, lastUnreadChannel); const prefetchQueueObj = prefetchQueue(unreadChannels, memberships, isCollapsedThreadsEnabled(state)); const prefetchRequestStatus = state.views.channel.channelPrefetchStatus; + const disableWebappPrefetchAllowed = isPerformanceDebuggingEnabled(state); return { currentChannelId: getCurrentChannelId(state), @@ -89,6 +92,8 @@ function mapStateToProps(state: GlobalState) { prefetchRequestStatus, sidebarLoaded: isSidebarLoaded(state), unreadChannels, + disableWebappPrefetchAllowed, + dataPrefetchEnabled: getBool(state, Preferences.CATEGORY_ADVANCED_SETTINGS, Preferences.ADVANCED_DATA_PREFETCH, true), }; } diff --git a/webapp/channels/src/components/user_settings/advanced/index.ts b/webapp/channels/src/components/user_settings/advanced/index.ts index 4ea3a91b8d..49bf659e9b 100644 --- a/webapp/channels/src/components/user_settings/advanced/index.ts +++ b/webapp/channels/src/components/user_settings/advanced/index.ts @@ -7,7 +7,7 @@ import type {ActionCreatorsMapObject, Dispatch} from 'redux'; import {savePreferences} from 'mattermost-redux/actions/preferences'; import {updateUserActive, revokeAllSessionsForUser} from 'mattermost-redux/actions/users'; -import {getConfig} from 'mattermost-redux/selectors/entities/general'; +import {getConfig, isPerformanceDebuggingEnabled} from 'mattermost-redux/selectors/entities/general'; import {get, getUnreadScrollPositionPreference, makeGetCategory, syncedDraftsAreAllowed} from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentUser} from 'mattermost-redux/selectors/entities/users'; import type {ActionFunc} from 'mattermost-redux/types/actions'; @@ -27,6 +27,7 @@ function makeMapStateToProps() { const enablePreviewFeatures = config.EnablePreviewFeatures === 'true'; const enableUserDeactivation = config.EnableUserDeactivation === 'true'; + const disableWebappPrefetchAllowed = isPerformanceDebuggingEnabled(state); const enableJoinLeaveMessage = config.EnableJoinLeaveMessageByDefault === 'true'; return { @@ -41,6 +42,8 @@ function makeMapStateToProps() { enablePreviewFeatures, enableUserDeactivation, syncedDraftsAreAllowed: syncedDraftsAreAllowed(state), + disableWebappPrefetchAllowed, + dataPrefetchEnabled: get(state, Preferences.CATEGORY_ADVANCED_SETTINGS, 'data_prefetch', 'true'), }; }; } diff --git a/webapp/channels/src/components/user_settings/advanced/user_settings_advanced.test.tsx b/webapp/channels/src/components/user_settings/advanced/user_settings_advanced.test.tsx index 945e60b65a..79dbec275f 100644 --- a/webapp/channels/src/components/user_settings/advanced/user_settings_advanced.test.tsx +++ b/webapp/channels/src/components/user_settings/advanced/user_settings_advanced.test.tsx @@ -47,6 +47,8 @@ describe('components/user_settings/display/UserSettingsDisplay', () => { enablePreviewFeatures: false, enableUserDeactivation: false, syncedDraftsAreAllowed: true, + disableWebappPrefetchAllowed: false, + dataPrefetchEnabled: 'true', }; test('should have called handleSubmit', async () => { diff --git a/webapp/channels/src/components/user_settings/advanced/user_settings_advanced.tsx b/webapp/channels/src/components/user_settings/advanced/user_settings_advanced.tsx index 91539d0172..f80749c494 100644 --- a/webapp/channels/src/components/user_settings/advanced/user_settings_advanced.tsx +++ b/webapp/channels/src/components/user_settings/advanced/user_settings_advanced.tsx @@ -36,6 +36,7 @@ type Settings = { formatting: Props['formatting']; join_leave: Props['joinLeave']; sync_drafts: Props['syncDrafts']; + data_prefetch: Props['dataPrefetchEnabled']; }; export type Props = { @@ -54,6 +55,8 @@ export type Props = { enablePreviewFeatures: boolean; enableUserDeactivation: boolean; syncedDraftsAreAllowed: boolean; + disableWebappPrefetchAllowed: boolean; + dataPrefetchEnabled: string; actions: { savePreferences: (userId: string, preferences: PreferenceType[]) => Promise; updateUserActive: (userId: string, active: boolean) => Promise; @@ -87,6 +90,7 @@ export default class AdvancedSettingsDisplay extends React.PureComponent { + const active = this.props.activeSection === AdvancedSections.DATA_PREFETCH; + let max = null; + if (active) { + max = ( + + } + inputs={[ +
+ + + +
+ +
+
+
+ +
+
+
+ +
+
, + ]} + setting={AdvancedSections.DATA_PREFETCH} + submit={this.handleSubmit.bind(this, ['data_prefetch'])} + saving={this.state.isSaving} + serverError={this.state.serverError} + updateSection={this.handleUpdateSection} + /> + ); + } + + return ( + + } + describe={this.renderOnOffLabel(this.state.settings.data_prefetch)} + section={AdvancedSections.DATA_PREFETCH} + updateSection={this.handleUpdateSection} + max={max} + /> + ); + }; + renderFeatureLabel(feature: string): ReactNode { switch (feature) { case 'MARKDOWN_PREVIEW': @@ -895,6 +986,15 @@ export default class AdvancedSettingsDisplay extends React.PureComponent; + } + } + return (
@@ -953,6 +1053,8 @@ export default class AdvancedSettingsDisplay extends React.PureComponent {makeConfirmationModal}
diff --git a/webapp/channels/src/i18n/en.json b/webapp/channels/src/i18n/en.json index f5b2d2c931..4cdd6a785e 100644 --- a/webapp/channels/src/i18n/en.json +++ b/webapp/channels/src/i18n/en.json @@ -5208,6 +5208,8 @@ "user_profile.send.dm.yourself": "Send yourself a message", "user.settings.advance.confirmDeactivateAccountTitle": "Confirm Deactivation", "user.settings.advance.confirmDeactivateDesc": "Are you sure you want to deactivate your account? This can only be reversed by your System Administrator.", + "user.settings.advance.dataPrefetch.Desc": "When disabled, messages and user information will be fetched on each channel load instead of being pre-fetched on startup. Disabling prefetch is recommended for users with a high unread channel count in order to improve application performance.", + "user.settings.advance.dataPrefetch.Title": "Allow Mattermost to prefetch channel posts", "user.settings.advance.deactivate_member_modal.deactivateButton": "Yes, deactivate my account", "user.settings.advance.deactivateAccountTitle": "Deactivate Account", "user.settings.advance.deactivateDesc": "Deactivating your account removes your ability to log in to this server and disables all email and mobile notifications. To reactivate your account, contact your System Administrator.", diff --git a/webapp/channels/src/packages/mattermost-redux/src/constants/preferences.ts b/webapp/channels/src/packages/mattermost-redux/src/constants/preferences.ts index d4efe1e522..d3f3e52597 100644 --- a/webapp/channels/src/packages/mattermost-redux/src/constants/preferences.ts +++ b/webapp/channels/src/packages/mattermost-redux/src/constants/preferences.ts @@ -55,6 +55,7 @@ const Preferences = { ADVANCED_CODE_BLOCK_ON_CTRL_ENTER: 'code_block_ctrl_enter', ADVANCED_SEND_ON_CTRL_ENTER: 'send_on_ctrl_enter', ADVANCED_SYNC_DRAFTS: 'sync_drafts', + ADVANCED_DATA_PREFETCH: 'data_prefetch', CATEGORY_WHATS_NEW_MODAL: 'whats_new_modal', HAS_SEEN_SIDEBAR_WHATS_NEW_MODAL: 'has_seen_sidebar_whats_new_modal', diff --git a/webapp/channels/src/utils/constants.tsx b/webapp/channels/src/utils/constants.tsx index 1a2e6d2449..9933af4f7b 100644 --- a/webapp/channels/src/utils/constants.tsx +++ b/webapp/channels/src/utils/constants.tsx @@ -1014,6 +1014,7 @@ export const AdvancedSections = { PREVIEW_FEATURES: 'advancedPreviewFeatures', PERFORMANCE_DEBUGGING: 'performanceDebugging', SYNC_DRAFTS: 'syncDrafts', + DATA_PREFETCH: 'dataPrefetch', }; export const RHSStates = {