MM 45015 - auto follow threads (#7463)

* auto follow select option added

* unused code removed

* auto follow threads condition fixed on CRT enabled

* error handles

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Tanmay Vardhaman Thole 2023-11-14 14:30:19 +05:30 committed by GitHub
parent 148f9dd716
commit 805c794b3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 142 additions and 10 deletions

View file

@ -6,6 +6,8 @@ export const MAX_CHANNEL_NAME_LENGTH = 64;
export const IGNORE_CHANNEL_MENTIONS_ON = 'on';
export const IGNORE_CHANNEL_MENTIONS_OFF = 'off';
export const IGNORE_CHANNEL_MENTIONS_DEFAULT = 'default';
export const CHANNEL_AUTO_FOLLOW_THREADS_TRUE = 'on';
export const CHANNEL_AUTO_FOLLOW_THREADS_FALSE = 'off';
export default {
IGNORE_CHANNEL_MENTIONS_ON,
@ -13,4 +15,6 @@ export default {
IGNORE_CHANNEL_MENTIONS_DEFAULT,
MAX_CHANNEL_NAME_LENGTH,
MIN_CHANNEL_NAME_LENGTH,
CHANNEL_AUTO_FOLLOW_THREADS_TRUE,
CHANNEL_AUTO_FOLLOW_THREADS_FALSE,
};

View file

@ -30,6 +30,7 @@ type Props = {
canEnableDisableCalls: boolean;
isCallsEnabledInChannel: boolean;
canManageMembers: boolean;
isCRTEnabled: boolean;
canManageSettings: boolean;
}
@ -51,6 +52,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
}));
const ChannelInfo = ({
isCRTEnabled,
channelId,
closeButtonId,
componentId,
@ -105,6 +107,7 @@ const ChannelInfo = ({
type={type}
callsEnabled={callsAvailable}
canManageMembers={canManageMembers}
isCRTEnabled={isCRTEnabled}
canManageSettings={canManageSettings}
/>
<View style={styles.separator}/>

View file

@ -17,6 +17,7 @@ import {
observeCurrentTeamId,
observeCurrentUserId,
} from '@queries/servers/system';
import {observeIsCRTEnabled} from '@queries/servers/thread';
import {observeCurrentUser, observeUserIsChannelAdmin, observeUserIsTeamAdmin} from '@queries/servers/user';
import {isTypeDMorGM} from '@utils/channel';
import {isMinimumServerVersion} from '@utils/helpers';
@ -117,6 +118,7 @@ const enhanced = withObservables([], ({serverUrl, database}: Props) => {
canEnableDisableCalls,
isCallsEnabledInChannel,
canManageMembers,
isCRTEnabled: observeIsCRTEnabled(database),
canManageSettings,
};
});

View file

@ -0,0 +1,61 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useState} from 'react';
import {useIntl} from 'react-intl';
import {updateChannelNotifyProps} from '@actions/remote/channel';
import OptionItem from '@components/option_item';
import {
CHANNEL_AUTO_FOLLOW_THREADS_FALSE,
CHANNEL_AUTO_FOLLOW_THREADS_TRUE,
} from '@constants/channel';
import {useServerUrl} from '@context/server';
import {t} from '@i18n';
import {alertErrorWithFallback} from '@utils/draft';
import {preventDoubleTap} from '@utils/tap';
type Props = {
channelId: string;
followedStatus: boolean;
displayName: string;
};
const AutoFollowThreads = ({channelId, displayName, followedStatus}: Props) => {
const [autoFollow, setAutoFollow] = useState(followedStatus);
const serverUrl = useServerUrl();
const intl = useIntl();
const toggleFollow = preventDoubleTap(async () => {
const props: Partial<ChannelNotifyProps> = {
channel_auto_follow_threads: followedStatus ? CHANNEL_AUTO_FOLLOW_THREADS_FALSE : CHANNEL_AUTO_FOLLOW_THREADS_TRUE,
};
setAutoFollow((v) => !v);
const result = await updateChannelNotifyProps(serverUrl, channelId, props);
if (result?.error) {
alertErrorWithFallback(
intl,
result.error,
{
id: t('channel_info.channel_auto_follow_threads_failed'),
defaultMessage: 'An error occurred trying to auto follow all threads in channel {displayName}',
},
{displayName},
);
setAutoFollow((v) => !v);
}
});
return (
<OptionItem
action={toggleFollow}
label={intl.formatMessage({id: 'channel_info.channel_auto_follow_threads', defaultMessage: 'Follow all threads in this channel'})}
icon='message-plus-outline'
type='toggle'
selected={autoFollow}
testID={`channel_info.options.channel_auto_follow_threads.option.toggled.${autoFollow}`}
/>
);
};
export default AutoFollowThreads;

View file

@ -0,0 +1,35 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
import withObservables from '@nozbe/with-observables';
import {of as of$} from 'rxjs';
import {switchMap} from 'rxjs/operators';
import {Channel} from '@constants';
import {observeChannel, observeChannelSettings} from '@queries/servers/channel';
import AutoFollowThreads from './auto_follow_threads';
import type {WithDatabaseArgs} from '@typings/database/database';
type Props = WithDatabaseArgs & {
channelId: string;
}
const enhanced = withObservables(['channelId'], ({channelId, database}: Props) => {
const channel = observeChannel(database, channelId);
const settings = observeChannelSettings(database, channelId);
const followedStatus = settings.pipe(
switchMap((s) => {
return of$(s?.notifyProps?.channel_auto_follow_threads === Channel.CHANNEL_AUTO_FOLLOW_THREADS_TRUE);
}),
);
return {
followedStatus,
displayName: channel.pipe(switchMap((c) => of$(c?.displayName))),
};
});
export default withDatabase(enhanced(AutoFollowThreads));

View file

@ -5,6 +5,8 @@ import React, {useState} from 'react';
import {useIntl} from 'react-intl';
import {updateChannelNotifyProps} from '@actions/remote/channel';
import {t} from '@app/i18n';
import {alertErrorWithFallback} from '@app/utils/draft';
import OptionItem from '@components/option_item';
import {useServerUrl} from '@context/server';
import {preventDoubleTap} from '@utils/tap';
@ -12,25 +14,38 @@ import {preventDoubleTap} from '@utils/tap';
type Props = {
channelId: string;
ignoring: boolean;
displayName: string;
}
const IgnoreMentions = ({channelId, ignoring}: Props) => {
const IgnoreMentions = ({channelId, ignoring, displayName}: Props) => {
const [ignored, setIgnored] = useState(ignoring);
const serverUrl = useServerUrl();
const {formatMessage} = useIntl();
const intl = useIntl();
const toggleIgnore = preventDoubleTap(() => {
const toggleIgnore = preventDoubleTap(async () => {
const props: Partial<ChannelNotifyProps> = {
ignore_channel_mentions: ignoring ? 'off' : 'on',
};
setIgnored(!ignored);
updateChannelNotifyProps(serverUrl, channelId, props);
setIgnored((v) => !v);
const result = await updateChannelNotifyProps(serverUrl, channelId, props);
if (result?.error) {
alertErrorWithFallback(
intl,
result.error,
{
id: t('channel_info.channel_auto_follow_threads_failed'),
defaultMessage: 'An error occurred trying to auto follow all threads in channel {displayName}',
},
{displayName},
);
setIgnored((v) => !v);
}
});
return (
<OptionItem
action={toggleIgnore}
label={formatMessage({id: 'channel_info.ignore_mentions', defaultMessage: 'Ignore @channel, @here, @all'})}
label={intl.formatMessage({id: 'channel_info.ignore_mentions', defaultMessage: 'Ignore @channel, @here, @all'})}
icon='at'
type='toggle'
selected={ignored}

View file

@ -7,7 +7,7 @@ import {of as of$} from 'rxjs';
import {combineLatestWith, switchMap} from 'rxjs/operators';
import {Channel} from '@constants';
import {observeChannelSettings} from '@queries/servers/channel';
import {observeChannel, observeChannelSettings} from '@queries/servers/channel';
import {observeCurrentUser} from '@queries/servers/user';
import IgnoreMentions from './ignore_mentions';
@ -34,6 +34,7 @@ const isChannelMentionsIgnored = (channelNotifyProps?: Partial<ChannelNotifyProp
};
const enhanced = withObservables(['channelId'], ({channelId, database}: Props) => {
const channel = observeChannel(database, channelId);
const currentUser = observeCurrentUser(database);
const settings = observeChannelSettings(database, channelId);
const ignoring = currentUser.pipe(
@ -43,6 +44,7 @@ const enhanced = withObservables(['channelId'], ({channelId, database}: Props) =
return {
ignoring,
displayName: channel.pipe(switchMap((c) => of$(c?.displayName))),
};
});

View file

@ -8,6 +8,7 @@ import {General} from '@constants';
import {isTypeDMorGM} from '@utils/channel';
import AddMembers from './add_members';
import AutoFollowThreads from './auto_follow_threads';
import ChannelFiles from './channel_files';
import EditChannel from './edit_channel';
import IgnoreMentions from './ignore_mentions';
@ -20,6 +21,7 @@ type Props = {
type?: ChannelType;
callsEnabled: boolean;
canManageMembers: boolean;
isCRTEnabled: boolean;
canManageSettings: boolean;
}
@ -28,15 +30,21 @@ const Options = ({
type,
callsEnabled,
canManageMembers,
isCRTEnabled,
canManageSettings,
}: Props) => {
const isDMorGM = isTypeDMorGM(type);
return (
<>
{type !== General.DM_CHANNEL &&
<IgnoreMentions channelId={channelId}/>
}
{type !== General.DM_CHANNEL && (
<>
{isCRTEnabled && (
<AutoFollowThreads channelId={channelId}/>
)}
<IgnoreMentions channelId={channelId}/>
</>
)}
<NotificationPreference channelId={channelId}/>
<PinnedMessages channelId={channelId}/>
<ChannelFiles channelId={channelId}/>

View file

@ -112,6 +112,7 @@
"channel_info.archive_description.cannot_view_archived": "This will archive the channel from the team and remove it from the user interface. Archived channels can be unarchived if needed again.\n\nAre you sure you wish to archive the {term} {name}?",
"channel_info.archive_failed": "An error occurred trying to archive the channel {displayName}",
"channel_info.archive_title": "Archive {term}",
"channel_info.channel_auto_follow_threads": "Follow all threads in this channel",
"channel_info.channel_files": "Files",
"channel_info.close": "Close",
"channel_info.close_dm": "Close direct message",

View file

@ -17,6 +17,7 @@ type ChannelNotifyProps = {
mark_unread: 'all' | 'mention';
push: NotificationLevel;
ignore_channel_mentions: 'default' | 'off' | 'on';
channel_auto_follow_threads: 'on' | 'off';
push_threads: 'all' | 'mention';
};
type Channel = {