forked from Ivasoft/mattermost-mobile
MM-37110: handle toggling of CRT feature (#6382)
* MM-37110: handle toggling of CRT feature When a user toggles CRT on/off the app should truncate affected tables, and re-fetch data. Truncated tables: - POST - POSTS_IN_CHANNEL - POSTS_IN_THREAD - THREAD - THREADS_IN_TEAM - THREAD_PARTICIPANT - MY_CHANNEL After truncation `entry` is called again. We must make sure though that we save the CRT change before calling `entry` again, or we end up with infinite recursion. PS the UI seems to handle the change rather good * Fixes appEntry and popToRoot * Small refactor * Fixes since param on appEntry * Further refactoring * Delete unneeded return type * Removes shouldPopToRoot from appEntry * Addresses review comments
This commit is contained in:
@@ -22,7 +22,8 @@ import NetworkManager from '@managers/network_manager';
|
||||
import {getDeviceToken} from '@queries/app/global';
|
||||
import {queryAllServers} from '@queries/app/servers';
|
||||
import {queryAllChannelsForTeam, queryChannelsById} from '@queries/servers/channel';
|
||||
import {prepareModels} from '@queries/servers/entry';
|
||||
import {prepareModels, truncateCrtRelatedTables} from '@queries/servers/entry';
|
||||
import {getHasCRTChanged} from '@queries/servers/preference';
|
||||
import {getConfig, getPushVerificationStatus, getWebSocketLastDisconnected} from '@queries/servers/system';
|
||||
import {deleteMyTeams, getAvailableTeamIds, getNthLastChannelFromTeam, queryMyTeams, queryMyTeamsByIds, queryTeamsById} from '@queries/servers/team';
|
||||
import {isDMorGM} from '@utils/channel';
|
||||
@@ -128,18 +129,32 @@ export const entry = async (serverUrl: string, teamId?: string, channelId?: stri
|
||||
return {models: models.flat(), initialChannelId, initialTeamId, prefData, teamData, chData, meData};
|
||||
};
|
||||
|
||||
export const fetchAppEntryData = async (serverUrl: string, since: number, initialTeamId = ''): Promise<AppEntryData | AppEntryError> => {
|
||||
export const fetchAppEntryData = async (serverUrl: string, sinceArg: number, initialTeamId = ''): Promise<AppEntryData | AppEntryError> => {
|
||||
const database = DatabaseManager.serverDatabases[serverUrl]?.database;
|
||||
if (!database) {
|
||||
return {error: `${serverUrl} database not found`};
|
||||
}
|
||||
|
||||
let since = sinceArg;
|
||||
const includeDeletedChannels = true;
|
||||
const fetchOnly = true;
|
||||
|
||||
const confReq = await fetchConfigAndLicense(serverUrl);
|
||||
const prefData = await fetchMyPreferences(serverUrl, fetchOnly);
|
||||
const isCRTEnabled = Boolean(prefData.preferences && processIsCRTEnabled(prefData.preferences, confReq.config));
|
||||
if (prefData.preferences) {
|
||||
const crtToggled = await getHasCRTChanged(database, prefData.preferences);
|
||||
if (crtToggled) {
|
||||
const currentServerUrl = await DatabaseManager.getActiveServerUrl();
|
||||
const isSameServer = currentServerUrl === serverUrl;
|
||||
if (isSameServer) {
|
||||
since = 0;
|
||||
}
|
||||
const {error} = await truncateCrtRelatedTables(serverUrl);
|
||||
if (error) {
|
||||
return {error: `Resetting CRT on ${serverUrl} failed`};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch in parallel teams / team membership / channels for current team / user preferences / user
|
||||
const promises: [Promise<MyTeamsRequest>, Promise<MyChannelsRequest | undefined>, Promise<MyUserRequest>] = [
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DeviceEventEmitter} from 'react-native';
|
||||
|
||||
import {updateDmGmDisplayName} from '@actions/local/channel';
|
||||
import {appEntry} from '@actions/remote/entry';
|
||||
import {fetchPostById} from '@actions/remote/post';
|
||||
import {Preferences} from '@constants';
|
||||
import {Events, Preferences} from '@constants';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {truncateCrtRelatedTables} from '@queries/servers/entry';
|
||||
import {getPostById} from '@queries/servers/post';
|
||||
import {deletePreferences, differsFromLocalNameFormat} from '@queries/servers/preference';
|
||||
import {deletePreferences, differsFromLocalNameFormat, getHasCRTChanged} from '@queries/servers/preference';
|
||||
|
||||
async function handleCRTToggled(serverUrl: string) {
|
||||
const currentServerUrl = await DatabaseManager.getActiveServerUrl();
|
||||
await truncateCrtRelatedTables(serverUrl);
|
||||
appEntry(serverUrl);
|
||||
DeviceEventEmitter.emit(Events.CRT_TOGGLED, serverUrl === currentServerUrl);
|
||||
}
|
||||
|
||||
export async function handlePreferenceChangedEvent(serverUrl: string, msg: WebSocketMessage): Promise<void> {
|
||||
let database;
|
||||
@@ -24,6 +35,7 @@ export async function handlePreferenceChangedEvent(serverUrl: string, msg: WebSo
|
||||
handleSavePostAdded(serverUrl, [preference]);
|
||||
|
||||
const hasDiffNameFormatPref = await differsFromLocalNameFormat(database, [preference]);
|
||||
const crtToggled = await getHasCRTChanged(database, [preference]);
|
||||
|
||||
if (operator) {
|
||||
await operator.handlePreferences({
|
||||
@@ -35,6 +47,10 @@ export async function handlePreferenceChangedEvent(serverUrl: string, msg: WebSo
|
||||
if (hasDiffNameFormatPref) {
|
||||
updateDmGmDisplayName(serverUrl);
|
||||
}
|
||||
|
||||
if (crtToggled) {
|
||||
handleCRTToggled(serverUrl);
|
||||
}
|
||||
} catch (error) {
|
||||
// Do nothing
|
||||
}
|
||||
@@ -50,7 +66,7 @@ export async function handlePreferencesChangedEvent(serverUrl: string, msg: WebS
|
||||
handleSavePostAdded(serverUrl, preferences);
|
||||
|
||||
const hasDiffNameFormatPref = await differsFromLocalNameFormat(operator.database, preferences);
|
||||
|
||||
const crtToggled = await getHasCRTChanged(operator.database, preferences);
|
||||
if (operator) {
|
||||
await operator.handlePreferences({
|
||||
prepareRecordsOnly: false,
|
||||
@@ -61,6 +77,10 @@ export async function handlePreferencesChangedEvent(serverUrl: string, msg: WebS
|
||||
if (hasDiffNameFormatPref) {
|
||||
updateDmGmDisplayName(serverUrl);
|
||||
}
|
||||
|
||||
if (crtToggled) {
|
||||
handleCRTToggled(serverUrl);
|
||||
}
|
||||
} catch (error) {
|
||||
// Do nothing
|
||||
}
|
||||
@@ -95,4 +115,3 @@ async function handleSavePostAdded(serverUrl: string, preferences: PreferenceTyp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,4 +27,5 @@ export default keyMirror({
|
||||
SWIPEABLE: null,
|
||||
ITEM_IN_VIEWPORT: null,
|
||||
SEND_TO_POST_DRAFT: null,
|
||||
CRT_TOGGLED: null,
|
||||
});
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import ServerDataOperator from '@database/operator/server_data_operator';
|
||||
|
||||
import {prepareCategories, prepareCategoryChannels} from './categories';
|
||||
import {prepareDeleteChannel, prepareMyChannelsForTeam} from './channel';
|
||||
import {prepareMyPreferences} from './preference';
|
||||
import {resetWebSocketLastDisconnected} from './system';
|
||||
import {prepareDeleteTeam, prepareMyTeams} from './team';
|
||||
import {prepareUsers} from './user';
|
||||
|
||||
@@ -29,6 +32,16 @@ type PrepareModelsArgs = {
|
||||
isCRTEnabled?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
POST,
|
||||
POSTS_IN_CHANNEL,
|
||||
POSTS_IN_THREAD,
|
||||
THREAD,
|
||||
THREADS_IN_TEAM,
|
||||
THREAD_PARTICIPANT,
|
||||
MY_CHANNEL,
|
||||
} = MM_TABLES.SERVER;
|
||||
|
||||
export async function prepareModels({operator, initialTeamId, removeTeams, removeChannels, teamData, chData, prefData, meData, isCRTEnabled}: PrepareModelsArgs): Promise<Array<Promise<Model[]>>> {
|
||||
const modelPromises: Array<Promise<Model[]>> = [];
|
||||
|
||||
@@ -67,3 +80,33 @@ export async function prepareModels({operator, initialTeamId, removeTeams, remov
|
||||
|
||||
return modelPromises;
|
||||
}
|
||||
|
||||
export async function truncateCrtRelatedTables(serverUrl: string): Promise<{error: any}> {
|
||||
const {database, operator} = DatabaseManager.getServerDatabaseAndOperator(serverUrl);
|
||||
|
||||
try {
|
||||
await database.write(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
return database.adapter.unsafeExecute({
|
||||
sqls: [
|
||||
[`DELETE FROM ${POST}`, []],
|
||||
[`DELETE FROM ${POSTS_IN_CHANNEL}`, []],
|
||||
[`DELETE FROM ${POSTS_IN_THREAD}`, []],
|
||||
[`DELETE FROM ${THREAD}`, []],
|
||||
[`DELETE FROM ${THREADS_IN_TEAM}`, []],
|
||||
[`DELETE FROM ${THREAD_PARTICIPANT}`, []],
|
||||
[`DELETE FROM ${MY_CHANNEL}`, []],
|
||||
],
|
||||
});
|
||||
});
|
||||
await resetWebSocketLastDisconnected(operator);
|
||||
} catch (error) {
|
||||
if (__DEV__) {
|
||||
throw error;
|
||||
}
|
||||
return {error};
|
||||
}
|
||||
|
||||
return {error: false};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {MM_TABLES} from '@constants/database';
|
||||
import {getPreferenceValue} from '@helpers/api/preference';
|
||||
|
||||
import {getCurrentTeamId} from './system';
|
||||
import {getIsCRTEnabled} from './thread';
|
||||
|
||||
import type ServerDataOperator from '@database/operator/server_data_operator';
|
||||
import type {ServerDatabase} from '@typings/database/database';
|
||||
@@ -79,3 +80,16 @@ export const differsFromLocalNameFormat = async (database: Database, preferences
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export async function getHasCRTChanged(database: Database, preferences: PreferenceType[]): Promise<boolean> {
|
||||
const oldCRT = await getIsCRTEnabled(database);
|
||||
const newCRTPref = preferences.filter((p) => p.name === Preferences.COLLAPSED_REPLY_THREADS)?.[0];
|
||||
|
||||
if (!newCRTPref) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const newCRT = newCRTPref.value === 'on';
|
||||
|
||||
return oldCRT !== newCRT;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import {enableFreeze, enableScreens} from 'react-native-screens';
|
||||
|
||||
import {Events, Screens} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {findChannels} from '@screens/navigation';
|
||||
import {findChannels, popToRoot} from '@screens/navigation';
|
||||
import NavigationStore from '@store/navigation_store';
|
||||
import {alertChannelArchived, alertChannelRemove, alertTeamRemove} from '@utils/navigation';
|
||||
import {notificationError} from '@utils/notification';
|
||||
@@ -67,10 +67,17 @@ export default function HomeScreen(props: HomeProps) {
|
||||
alertChannelArchived(displayName, intl);
|
||||
});
|
||||
|
||||
const crtToggledListener = DeviceEventEmitter.addListener(Events.CRT_TOGGLED, (isSameServer: boolean) => {
|
||||
if (isSameServer) {
|
||||
popToRoot();
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
leaveTeamListener.remove();
|
||||
leaveChannelListener.remove();
|
||||
archivedChannelListener.remove();
|
||||
crtToggledListener.remove();
|
||||
};
|
||||
}, [intl.locale]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user