Improve Redux types part 5/Replace DispatchFunc (#26004)

* Remove non-functional code from Login component

* Remove remaining usage of useDispatch<DispatchFunc>

* Remove usage of DispatchFunc from actions/file_actions

* actions/global_actions

* Remove usage of DispatchFunc from actions/marketplace

* Remove DispatchFunc from actions/post_actions

* Remove DispatchFunc from actions/storage

* Remove DispatchFunc from actions/user_actions

* Remove DispatchFunc from actions/views/channel

* Remove DispatchFunc from actions/views/channel_sidebar

* Remove DispatchFunc from actions/views/create_comment

* Remove DispatchFunc from actions/views/lhs.ts

* Remove DispatchFunc from actions/views/rhs.ts

* Remove DispatchFunc from actions/views/onboarding_tasks

* Remove DispatchFunc from actions/views/root

* Remove DispatchFunc from components/logged_in

* Remove DispatchFunc from components/msg_typing

* Remove DispatchFunc from components/permalink_view

* Remove DispatchFunc from components/suggestion

* Remove DispatchFunc from mattermost-redux/actions/posts

* Remove DispatchFunc from mattermost-redux/actions/roles

* Remove DispatchFunc from mattermost-redux/actions/threads

* Remove DispatchFunc from mattermost-redux/actions/timezone

* Remove DispatchFunc from plugins/products

* Make DispatchFunc into Dispatch

* Fix how dispatch is mocked in test for toggleSideBarRightMenuAction
This commit is contained in:
Harrison Healey 2024-01-24 10:28:38 -05:00 committed by GitHub
parent d8e11fe292
commit 8e165c7685
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
72 changed files with 450 additions and 539 deletions

View File

@ -10,7 +10,7 @@ import {FileTypes} from 'mattermost-redux/action_types';
import {getLogErrorAction} from 'mattermost-redux/actions/errors';
import {forceLogoutIfNecessary} from 'mattermost-redux/actions/helpers';
import {Client4} from 'mattermost-redux/client';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {ThunkActionFunc} from 'mattermost-redux/types/actions';
import type {FilePreviewInfo} from 'components/file_preview/file_preview';
@ -28,8 +28,8 @@ export interface UploadFile {
onError: (err: string | ServerError, clientId: string, channelId: string, rootId: string) => void;
}
export function uploadFile({file, name, type, rootId, channelId, clientId, onProgress, onSuccess, onError}: UploadFile) {
return (dispatch: DispatchFunc, getState: GetStateFunc): XMLHttpRequest => {
export function uploadFile({file, name, type, rootId, channelId, clientId, onProgress, onSuccess, onError}: UploadFile): ThunkActionFunc<XMLHttpRequest> {
return (dispatch, getState) => {
dispatch({type: FileTypes.UPLOAD_FILES_REQUEST});
const xhr = new XMLHttpRequest();

View File

@ -575,10 +575,12 @@ describe('actions/global_actions', () => {
});
test('toggleSideBarRightMenuAction', () => {
const dispatchMock = async () => {
return {data: true};
const dispatchMock = (arg: any) => {
if (typeof arg === 'function') {
arg(dispatchMock);
}
};
toggleSideBarRightMenuAction()(dispatchMock);
dispatchMock(toggleSideBarRightMenuAction());
expect(closeRhsMenu).toHaveBeenCalled();
expect(closeRightHandSide).toHaveBeenCalled();
expect(closeLhs).toHaveBeenCalled();

View File

@ -24,7 +24,7 @@ import {getConfig, isPerformanceDebuggingEnabled} from 'mattermost-redux/selecto
import {getBool, getIsOnboardingFlowEnabled, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId, getMyTeams, getTeam, getMyTeamMember, getTeamMemberships, getActiveTeamsList} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser, getCurrentUserId, isFirstAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GetStateFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {calculateUnreadCount} from 'mattermost-redux/utils/channel_utils';
import {handleNewPost} from 'actions/post_actions';
@ -229,7 +229,7 @@ export function sendAddToChannelEphemeralPost(user: UserProfile, addedUsername:
let lastTimeTypingSent = 0;
export function emitLocalUserTypingEvent(channelId: string, parentPostId: string) {
const userTyping = async (actionDispatch: DispatchFunc, actionGetState: GetStateFunc) => {
const userTyping: NewActionFuncAsync = async (actionDispatch, actionGetState) => {
const state = actionGetState();
const config = getConfig(state);
@ -282,8 +282,8 @@ export function emitUserLoggedOutEvent(redirectTo = '/', shouldSignalLogout = tr
});
}
export function toggleSideBarRightMenuAction() {
return (doDispatch: DispatchFunc) => {
export function toggleSideBarRightMenuAction(): ThunkActionFunc<void> {
return (doDispatch) => {
doDispatch(closeRightHandSide());
doDispatch(closeLhs());
doDispatch(closeRhsMenu());

View File

@ -9,7 +9,7 @@ import {AppBindingLocations, AppCallResponseTypes} from 'mattermost-redux/consta
import {appsEnabled} from 'mattermost-redux/selectors/entities/apps';
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import type {DispatchFunc, GetStateFunc, NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {getFilter, getPlugin} from 'selectors/views/marketplace';
@ -142,8 +142,8 @@ export function installPlugin(id: string): ThunkActionFunc<void, GlobalState> {
// installApp installed an App using a given URL a call to the `/install-listed` call path.
//
// On success, it also requests the current state of the apps to reflect the newly installed app.
export function installApp(id: string): ThunkActionFunc<Promise<boolean>> {
return async (dispatch: DispatchFunc, getState: GetStateFunc): Promise<boolean> => {
export function installApp(id: string): ThunkActionFunc<Promise<boolean>, GlobalState> {
return async (dispatch, getState) => {
dispatch({
type: ActionTypes.INSTALLING_MARKETPLACE_ITEM,
id,

View File

@ -15,7 +15,7 @@ import * as PostSelectors from 'mattermost-redux/selectors/entities/posts';
import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserId, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GetStateFunc, NewActionFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {DispatchFunc, NewActionFunc, NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {canEditPost, comparePosts} from 'mattermost-redux/utils/post_utils';
import {addRecentEmoji, addRecentEmojis} from 'actions/emoji_actions';
@ -78,8 +78,8 @@ export function handleNewPost(post: Post, msg?: {data?: NewPostMessageProps & Gr
const getPostsForIds = PostSelectors.makeGetPostsForIds();
export function flagPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function flagPost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
await dispatch(PostActions.flagPost(postId));
const state = getState() as GlobalState;
const rhsState = getRhsState(state);
@ -92,8 +92,8 @@ export function flagPost(postId: string) {
};
}
export function unflagPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function unflagPost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
await dispatch(PostActions.unflagPost(postId));
const state = getState() as GlobalState;
const rhsState = getRhsState(state);
@ -106,8 +106,8 @@ export function unflagPost(postId: string) {
};
}
export function createPost(post: Post, files: FileInfo[]) {
return async (dispatch: DispatchFunc) => {
export function createPost(post: Post, files: FileInfo[]): NewActionFuncAsync {
return async (dispatch) => {
// parse message and emit emoji event
const emojis = matchEmoticons(post.message);
if (emojis) {
@ -132,15 +132,15 @@ export function createPost(post: Post, files: FileInfo[]) {
};
}
function storeDraft(channelId: string, draft: null) {
return (dispatch: DispatchFunc) => {
function storeDraft(channelId: string, draft: null): NewActionFunc {
return (dispatch) => {
dispatch(StorageActions.setGlobalItem('draft_' + channelId, draft));
return {data: true};
};
}
function storeCommentDraft(rootPostId: string, draft: null) {
return (dispatch: DispatchFunc) => {
function storeCommentDraft(rootPostId: string, draft: null): NewActionFunc {
return (dispatch) => {
dispatch(StorageActions.setGlobalItem('comment_draft_' + rootPostId, draft));
return {data: true};
};
@ -202,16 +202,16 @@ export function addReaction(postId: string, emojiName: string): NewActionFunc {
};
}
export function searchForTerm(term: string) {
return (dispatch: DispatchFunc) => {
export function searchForTerm(term: string): NewActionFunc<boolean, GlobalState> {
return (dispatch) => {
dispatch(RhsActions.updateSearchTerms(term));
dispatch(RhsActions.showSearchResults());
return {data: true};
};
}
function addPostToSearchResults(postId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
function addPostToSearchResults(postId: string): NewActionFunc {
return (dispatch, getState) => {
const state = getState();
const results = state.entities.search.results;
const index = results.indexOf(postId);
@ -251,10 +251,10 @@ function removePostFromSearchResults(postId: string, state: GlobalState, dispatc
}
}
export function pinPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function pinPost(postId: string): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
await dispatch(PostActions.pinPost(postId));
const state = getState() as GlobalState;
const state = getState();
const rhsState = getRhsState(state);
if (rhsState === RHSStates.PIN) {
@ -264,10 +264,10 @@ export function pinPost(postId: string) {
};
}
export function unpinPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function unpinPost(postId: string): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
await dispatch(PostActions.unpinPost(postId));
const state = getState() as GlobalState;
const state = getState();
const rhsState = getRhsState(state);
if (rhsState === RHSStates.PIN) {
@ -337,8 +337,8 @@ export function markPostAsUnread(post: Post, location?: string): NewActionFuncAs
};
}
export function markMostRecentPostInChannelAsUnread(channelId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function markMostRecentPostInChannelAsUnread(channelId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
let state = getState();
let postId = PostSelectors.getMostRecentPostIdInChannel(state, channelId);
if (!postId) {
@ -392,11 +392,11 @@ export function deleteAndRemovePost(post: Post): NewActionFuncAsync<boolean, Glo
};
}
export function toggleEmbedVisibility(postId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function toggleEmbedVisibility(postId: string): ThunkActionFunc<void, GlobalState> {
return (dispatch, getState) => {
const state = getState();
const currentUserId = getCurrentUserId(state);
const visible = isEmbedVisible(state as GlobalState, postId);
const visible = isEmbedVisible(state, postId);
dispatch(StorageActions.setGlobalItem(StoragePrefixes.EMBED_VISIBLE + currentUserId + '_' + postId, !visible));
};
@ -406,11 +406,11 @@ export function resetEmbedVisibility() {
return StorageActions.actionOnGlobalItemsWithPrefix(StoragePrefixes.EMBED_VISIBLE, () => null);
}
export function toggleInlineImageVisibility(postId: string, imageKey: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function toggleInlineImageVisibility(postId: string, imageKey: string): ThunkActionFunc<void, GlobalState> {
return (dispatch, getState) => {
const state = getState();
const currentUserId = getCurrentUserId(state);
const visible = isInlineImageVisible(state as GlobalState, postId, imageKey);
const visible = isInlineImageVisible(state, postId, imageKey);
dispatch(StorageActions.setGlobalItem(StoragePrefixes.INLINE_IMAGE_VISIBLE + currentUserId + '_' + postId + '_' + imageKey, !visible));
};

View File

@ -66,7 +66,7 @@ export function loadStatusesForProfilesList(users: UserProfile[] | null): NewAct
};
}
export function loadStatusesForProfilesMap(users: Record<string, UserProfile> | null): NewActionFunc {
export function loadStatusesForProfilesMap(users: Record<string, UserProfile> | UserProfile[] | null): NewActionFunc {
return (dispatch) => {
if (users == null) {
return {data: false};

View File

@ -1,13 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {NewActionFunc} from 'mattermost-redux/types/actions';
import {StorageTypes} from 'utils/constants';
import {getPrefix} from 'utils/storage_utils';
export function setItem(name: string, value: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function setItem(name: string, value: string): NewActionFunc {
return (dispatch, getState) => {
const state = getState();
const prefix = getPrefix(state);
dispatch({
@ -18,8 +18,8 @@ export function setItem(name: string, value: string) {
};
}
export function removeItem(name: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function removeItem(name: string): NewActionFunc { // HARRISONTODO unused
return (dispatch, getState) => {
const state = getState();
const prefix = getPrefix(state);
dispatch({
@ -37,8 +37,8 @@ export function setGlobalItem(name: string, value: any) {
};
}
export function removeGlobalItem(name: string) {
return (dispatch: DispatchFunc) => {
export function removeGlobalItem(name: string): NewActionFunc {
return (dispatch) => {
dispatch({
type: StorageTypes.REMOVE_GLOBAL_ITEM,
data: {name},

View File

@ -3,6 +3,7 @@
import PQueue from 'p-queue';
import type {UserAutocomplete} from '@mattermost/types/autocomplete';
import type {Channel} from '@mattermost/types/channels';
import type {UserProfile, UserStatus} from '@mattermost/types/users';
@ -22,7 +23,7 @@ import {
import {getBool, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId, getTeamMember} from 'mattermost-redux/selectors/entities/teams';
import * as Selectors from 'mattermost-redux/selectors/entities/users';
import type {ActionResult, DispatchFunc, GetStateFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {ActionResult, NewActionFunc, NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {calculateUnreadCount} from 'mattermost-redux/utils/channel_utils';
import {loadCustomEmojisForCustomStatusesByUserIds} from 'actions/emoji_actions';
@ -39,8 +40,8 @@ export const queue = new PQueue({concurrency: 4});
const dispatch = store.dispatch;
const getState = store.getState;
export function loadProfilesAndStatusesInChannel(channelId: string, page = 0, perPage: number = General.PROFILE_CHUNK_SIZE, sort = '', options = {}) {
return async (doDispatch: DispatchFunc) => {
export function loadProfilesAndStatusesInChannel(channelId: string, page = 0, perPage: number = General.PROFILE_CHUNK_SIZE, sort = '', options = {}): NewActionFuncAsync { // HARRISONTODO unused
return async (doDispatch) => {
const {data} = await doDispatch(UserActions.getProfilesInChannel(channelId, page, perPage, sort, options));
if (data) {
doDispatch(loadStatusesForProfilesList(data));
@ -49,8 +50,8 @@ export function loadProfilesAndStatusesInChannel(channelId: string, page = 0, pe
};
}
export function loadProfilesAndReloadTeamMembers(page: number, perPage: number, teamId: string, options = {}) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function loadProfilesAndReloadTeamMembers(page: number, perPage: number, teamId: string, options = {}): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const newTeamId = teamId || getCurrentTeamId(doGetState());
const {data} = await doDispatch(UserActions.getProfilesInTeam(newTeamId, page, perPage, '', options));
if (data) {
@ -64,8 +65,8 @@ export function loadProfilesAndReloadTeamMembers(page: number, perPage: number,
};
}
export function loadProfilesAndReloadChannelMembers(page: number, perPage?: number, channelId?: string, sort = '', options = {}) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function loadProfilesAndReloadChannelMembers(page: number, perPage?: number, channelId?: string, sort = '', options = {}): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const newChannelId = channelId || getCurrentChannelId(doGetState());
const {data} = await doDispatch(UserActions.getProfilesInChannel(newChannelId, page, perPage, sort, options));
if (data) {
@ -92,8 +93,8 @@ export function loadProfilesAndTeamMembers(page: number, perPage: number, teamId
};
}
export function searchProfilesAndTeamMembers(term = '', options: Record<string, any> = {}) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function searchProfilesAndTeamMembers(term = '', options: Record<string, any> = {}): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const newTeamId = options.team_id || getCurrentTeamId(doGetState());
const {data} = await doDispatch(UserActions.searchProfiles(term, options));
if (data) {
@ -107,8 +108,8 @@ export function searchProfilesAndTeamMembers(term = '', options: Record<string,
};
}
export function searchProfilesAndChannelMembers(term: string, options: Record<string, any> = {}) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function searchProfilesAndChannelMembers(term: string, options: Record<string, any> = {}): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const newChannelId = options.in_channel_id || getCurrentChannelId(doGetState());
const {data} = await doDispatch(UserActions.searchProfiles(term, options));
if (data) {
@ -140,8 +141,8 @@ export function loadProfilesAndTeamMembersAndChannelMembers(page: number, perPag
};
}
export function loadTeamMembersForProfilesList(profiles: UserProfile[], teamId: string, reloadAllMembers = false) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function loadTeamMembersForProfilesList(profiles: UserProfile[], teamId: string, reloadAllMembers = false): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const state = doGetState();
const teamIdParam = teamId || getCurrentTeamId(state);
const membersToLoad: Record<string, true> = {};
@ -164,18 +165,18 @@ export function loadTeamMembersForProfilesList(profiles: UserProfile[], teamId:
};
}
export function loadProfilesWithoutTeam(page: number, perPage: number, options?: Record<string, any>) {
return async (doDispatch: DispatchFunc) => {
export function loadProfilesWithoutTeam(page: number, perPage: number, options?: Record<string, any>): NewActionFuncAsync {
return async (doDispatch) => {
const {data} = await doDispatch(UserActions.getProfilesWithoutTeam(page, perPage, options));
doDispatch(loadStatusesForProfilesMap(data));
doDispatch(loadStatusesForProfilesMap(data!));
return data;
return {data};
};
}
export function loadTeamMembersAndChannelMembersForProfilesList(profiles: UserProfile[], teamId: string, channelId: string) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function loadTeamMembersAndChannelMembersForProfilesList(profiles: UserProfile[], teamId: string, channelId: string): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const state = doGetState();
const teamIdParam = teamId || getCurrentTeamId(state);
const channelIdParam = channelId || getCurrentChannelId(state);
@ -188,8 +189,8 @@ export function loadTeamMembersAndChannelMembersForProfilesList(profiles: UserPr
};
}
export function loadChannelMembersForProfilesList(profiles: UserProfile[], channelId: string, reloadAllMembers = false) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function loadChannelMembersForProfilesList(profiles: UserProfile[], channelId: string, reloadAllMembers = false): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const state = doGetState();
const channelIdParam = channelId || getCurrentChannelId(state);
const membersToLoad: Record<string, boolean> = {};
@ -212,8 +213,8 @@ export function loadChannelMembersForProfilesList(profiles: UserProfile[], chann
};
}
export function loadNewDMIfNeeded(channelId: string) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function loadNewDMIfNeeded(channelId: string): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const state = doGetState();
const currentUserId = Selectors.getCurrentUserId(state);
@ -252,8 +253,8 @@ export function loadNewDMIfNeeded(channelId: string) {
};
}
export function loadNewGMIfNeeded(channelId: string) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function loadNewGMIfNeeded(channelId: string): NewActionFuncAsync {
return async (doDispatch, doGetState) => {
const state = doGetState();
const currentUserId = Selectors.getCurrentUserId(state);
@ -275,8 +276,8 @@ export function loadNewGMIfNeeded(channelId: string) {
};
}
export function loadProfilesForGroupChannels(groupChannels: Channel[]) {
return (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function loadProfilesForGroupChannels(groupChannels: Channel[]): NewActionFunc {
return (doDispatch, doGetState) => {
const state = doGetState();
const userIdsInChannels = Selectors.getUserIdsInChannels(state);
@ -415,27 +416,27 @@ export async function loadProfilesForDM() {
await dispatch(loadCustomEmojisForCustomStatusesByUserIds(profileIds));
}
export function autocompleteUsersInTeam(username: string) {
return async (doDispatch: DispatchFunc, doGetState: GetStateFunc) => {
export function autocompleteUsersInTeam(username: string): ThunkActionFunc<Promise<UserAutocomplete>> {
return async (doDispatch, doGetState) => {
const currentTeamId = getCurrentTeamId(doGetState());
const {data} = await doDispatch(UserActions.autocompleteUsers(username, currentTeamId));
return data;
return data!;
};
}
export function autocompleteUsers(username: string) {
return async (doDispatch: DispatchFunc) => {
export function autocompleteUsers(username: string): ThunkActionFunc<Promise<UserAutocomplete>> {
return async (doDispatch) => {
const {data} = await doDispatch(UserActions.autocompleteUsers(username));
return data;
return data!;
};
}
export function autoResetStatus() {
return async (doDispatch: DispatchFunc): Promise<{data: UserStatus}> => {
export function autoResetStatus(): NewActionFuncAsync<UserStatus> {
return async (doDispatch) => {
const {currentUserId} = getState().entities.users;
const {data: userStatus} = await doDispatch(UserActions.getStatus(currentUserId));
if (userStatus.status === UserStatuses.OUT_OF_OFFICE || !userStatus.manual) {
if (userStatus!.status === UserStatuses.OUT_OF_OFFICE || !userStatus!.manual) {
return {data: userStatus};
}

View File

@ -4,6 +4,7 @@
import type {AnyAction} from 'redux';
import {batchActions} from 'redux-batched-actions';
import type {UserAutocomplete} from '@mattermost/types/autocomplete';
import type {Channel} from '@mattermost/types/channels';
import {TeamTypes} from 'mattermost-redux/action_types';
@ -41,7 +42,7 @@ import {
} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserId, getUserByUsername} from 'mattermost-redux/selectors/entities/users';
import {makeAddLastViewAtToProfiles} from 'mattermost-redux/selectors/entities/utils';
import type {DispatchFunc, GetStateFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {getChannelByName} from 'mattermost-redux/utils/channel_utils';
import EventEmitter from 'mattermost-redux/utils/event_emitter';
@ -60,8 +61,8 @@ import {Constants, ActionTypes, EventTypes, PostRequestTypes} from 'utils/consta
import type {GlobalState} from 'types/store';
export function goToLastViewedChannel() {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function goToLastViewedChannel(): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const currentChannel = getCurrentChannel(state) || {};
const channelsInTeam = getChannelsNameMapInCurrentTeam(state);
@ -78,21 +79,21 @@ export function goToLastViewedChannel() {
};
}
export function switchToChannelById(channelId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function switchToChannelById(channelId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const channel = getChannel(state, channelId);
return dispatch(switchToChannel(channel));
};
}
export function loadIfNecessaryAndSwitchToChannelById(channelId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function loadIfNecessaryAndSwitchToChannelById(channelId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
let channel = getChannel(state, channelId);
if (!channel) {
const res = await dispatch(loadChannel(channelId));
channel = res.data;
channel = res.data!;
}
return dispatch(switchToChannel(channel));
};
@ -129,8 +130,8 @@ export function switchToChannel(channel: Channel & {userId?: string}): NewAction
};
}
export function joinChannelById(channelId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function joinChannelById(channelId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const currentUserId = getCurrentUserId(state);
const currentTeamId = getCurrentTeamId(state);
@ -139,8 +140,8 @@ export function joinChannelById(channelId: string) {
};
}
export function leaveChannel(channelId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function leaveChannel(channelId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
let state = getState();
const currentUserId = getCurrentUserId(state);
const currentTeam = getCurrentTeam(state);
@ -190,8 +191,8 @@ export function leaveChannel(channelId: string) {
};
}
export function leaveDirectChannel(channelName: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function leaveDirectChannel(channelName: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const currentUserId = getCurrentUserId(state);
const teams = getTeamsList(state); // dms are shared across teams but on local storage are set linked to one, we need to look into all.
@ -210,9 +211,9 @@ export function leaveDirectChannel(channelName: string) {
};
}
export function autocompleteUsersInChannel(prefix: string, channelId: string) {
export function autocompleteUsersInChannel(prefix: string, channelId: string): NewActionFuncAsync<UserAutocomplete> {
const addLastViewAtToProfiles = makeAddLastViewAtToProfiles();
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch, getState) => {
const state = getState();
const currentTeamId = getCurrentTeamId(state);
@ -292,8 +293,8 @@ export function loadUnreads(channelId: string, prefetch = false): NewActionFuncA
};
}
export function loadPostsAround(channelId: string, focusedPostId: string) {
return async (dispatch: DispatchFunc) => {
export function loadPostsAround(channelId: string, focusedPostId: string): NewActionFuncAsync {
return async (dispatch) => {
const {data, error} = await dispatch(PostActions.getPostsAround(channelId, focusedPostId, Posts.POST_CHUNK_SIZE / 2));
if (error) {
return {
@ -306,17 +307,17 @@ export function loadPostsAround(channelId: string, focusedPostId: string) {
dispatch({
type: ActionTypes.INCREASE_POST_VISIBILITY,
data: channelId,
amount: data.order.length,
amount: data!.order.length,
});
return {
atLatestMessage: data.next_post_id === '',
atOldestmessage: data.prev_post_id === '',
atLatestMessage: data!.next_post_id === '',
atOldestmessage: data!.prev_post_id === '',
};
};
}
export function loadLatestPosts(channelId: string) {
return async (dispatch: DispatchFunc) => {
export function loadLatestPosts(channelId: string): NewActionFuncAsync {
return async (dispatch) => {
const time = Date.now();
const {data, error} = await dispatch(PostActions.getPosts(channelId, 0, Posts.POST_CHUNK_SIZE / 2));
@ -336,8 +337,8 @@ export function loadLatestPosts(channelId: string) {
return {
data,
atLatestMessage: data.next_post_id === '',
atOldestmessage: data.prev_post_id === '',
atLatestMessage: data!.next_post_id === '',
atOldestmessage: data!.prev_post_id === '',
};
};
}
@ -359,9 +360,9 @@ export function loadPosts({
channelId,
postId,
type,
}: LoadPostsParameters) {
}: LoadPostsParameters): ThunkActionFunc<Promise<LoadPostsReturnValue>> {
//type here can be BEFORE_ID or AFTER_ID
return async (dispatch: DispatchFunc): Promise<LoadPostsReturnValue> => {
return async (dispatch) => {
const POST_INCREASE_AMOUNT = Constants.POST_CHUNK_SIZE / 2;
dispatch({
@ -393,23 +394,23 @@ export function loadPosts({
};
}
dispatch(loadCustomStatusEmojisForPostList(data.posts));
dispatch(loadCustomStatusEmojisForPostList(data!.posts));
actions.push({
type: ActionTypes.INCREASE_POST_VISIBILITY,
data: channelId,
amount: data.order.length,
amount: data!.order.length,
});
dispatch(batchActions(actions));
return {
moreToLoad: type === PostRequestTypes.BEFORE_ID ? data.prev_post_id !== '' : data.next_post_id !== '',
moreToLoad: type === PostRequestTypes.BEFORE_ID ? data!.prev_post_id !== '' : data!.next_post_id !== '',
};
};
}
export function syncPostsInChannel(channelId: string, since: number, prefetch = false) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function syncPostsInChannel(channelId: string, since: number, prefetch = false): NewActionFuncAsync {
return async (dispatch, getState) => {
const time = Date.now();
const state = getState();
const socketStatus = getSocketStatus(state as GlobalState);
@ -483,8 +484,8 @@ export function scrollPostListToBottom() {
};
}
export function markChannelAsReadOnFocus(channelId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function markChannelAsReadOnFocus(channelId: string): ThunkActionFunc<void> {
return (dispatch, getState) => {
if (isManuallyUnread(getState(), channelId)) {
return;
}
@ -494,21 +495,19 @@ export function markChannelAsReadOnFocus(channelId: string) {
}
export function updateToastStatus(status: boolean) {
return (dispatch: DispatchFunc) => {
dispatch({
type: ActionTypes.UPDATE_TOAST_STATUS,
data: status,
});
return {
type: ActionTypes.UPDATE_TOAST_STATUS,
data: status,
};
}
export function deleteChannel(channelId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function deleteChannel(channelId: string): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
const res = await dispatch(deleteChannelRedux(channelId));
if (res.error) {
return {data: false};
}
const state = getState() as GlobalState;
const state = getState();
const selectedPost = getSelectedPost(state);
const selectedPostId = getSelectedPostId(state);

View File

@ -6,7 +6,7 @@ import {General} from 'mattermost-redux/constants';
import {CategoryTypes} from 'mattermost-redux/constants/channel_categories';
import {getCategory, makeGetChannelIdsForCategory} from 'mattermost-redux/selectors/entities/channel_categories';
import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels';
import type {DispatchFunc, GetStateFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {NewActionFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import {insertMultipleWithoutDuplicates} from 'mattermost-redux/utils/array_utils';
import {getCategoriesForCurrentTeam, getChannelsInCategoryOrder, getDisplayedChannels} from 'selectors/views/channel_sidebar';
@ -33,7 +33,7 @@ export function stopDragging() {
return {type: ActionTypes.SIDEBAR_DRAGGING_STOP};
}
export function createCategory(teamId: string, displayName: string, channelIds?: string[]): NewActionFuncAsync {
export function createCategory(teamId: string, displayName: string, channelIds?: string[]): NewActionFuncAsync<unknown, GlobalState> {
return async (dispatch, getState) => {
if (channelIds) {
const state = getState() as GlobalState;
@ -61,9 +61,9 @@ export function addChannelsInSidebar(categoryId: string, channelId: string) {
// moveChannelsInSidebar moves channels to a given category in the sidebar, but it accounts for when the target index
// may have changed due to archived channels not being shown in the sidebar.
export function moveChannelsInSidebar(categoryId: string, targetIndex: number, draggableChannelId: string, setManualSorting = true) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function moveChannelsInSidebar(categoryId: string, targetIndex: number, draggableChannelId: string, setManualSorting = true): NewActionFuncAsync<unknown, GlobalState> {
return (dispatch, getState) => {
const state = getState();
const multiSelectedChannelIds = state.views.channelSidebar.multiSelectedChannelIds;
let channelIds = [];
@ -137,24 +137,26 @@ export function adjustTargetIndexForMove(state: GlobalState, categoryId: string,
return Math.max(newIndex - removedChannelsAboveInsert.length, 0);
}
export function clearChannelSelection() {
return (dispatch: DispatchFunc, getState: () => GlobalState) => {
export function clearChannelSelection(): NewActionFunc<unknown, GlobalState> {
return (dispatch, getState) => {
const state = getState();
if (state.views.channelSidebar.multiSelectedChannelIds.length === 0) {
// No selection to clear
return Promise.resolve({data: true});
return {data: false};
}
return dispatch({
dispatch({
type: ActionTypes.MULTISELECT_CHANNEL_CLEAR,
});
return {data: true};
};
}
export function multiSelectChannelAdd(channelId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function multiSelectChannelAdd(channelId: string): NewActionFunc<unknown, GlobalState> {
return (dispatch, getState) => {
const state = getState();
const multiSelectedChannelIds = state.views.channelSidebar.multiSelectedChannelIds;
// Nothing already selected, so we include the active channel
@ -173,20 +175,18 @@ export function multiSelectChannelAdd(channelId: string) {
};
}
export function setFirstChannelName(channelName: string) {
return (dispatch: DispatchFunc) => {
dispatch({
type: ActionTypes.FIRST_CHANNEL_NAME,
data: channelName,
});
export function setFirstChannelName(channelName: string) { // HARRISONTODO unused
return {
type: ActionTypes.FIRST_CHANNEL_NAME,
data: channelName,
};
}
// Much of this logic was pulled from the react-beautiful-dnd sample multiselect implementation
// Found here: https://github.com/atlassian/react-beautiful-dnd/tree/master/stories/src/multi-drag
export function multiSelectChannelTo(channelId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function multiSelectChannelTo(channelId: string): NewActionFunc<unknown, GlobalState> {
return (dispatch, getState) => {
const state = getState();
const multiSelectedChannelIds = state.views.channelSidebar.multiSelectedChannelIds;
let lastSelected = state.views.channelSidebar.lastSelectedChannel;
@ -209,7 +209,7 @@ export function multiSelectChannelTo(channelId: string) {
// nothing to do here
if (indexOfNew === indexOfLast) {
return null;
return {data: false};
}
const start: number = Math.min(indexOfLast, indexOfNew);

View File

@ -18,7 +18,7 @@ import {
} from 'mattermost-redux/selectors/entities/posts';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GetStateFunc, NewActionFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {NewActionFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import {isPostPendingOrFailed} from 'mattermost-redux/utils/post_utils';
import {executeCommand} from 'actions/command';
@ -52,10 +52,10 @@ export function updateCommentDraft(rootId: string, draft?: PostDraft, save = fal
return updateDraft(key, draft ?? null, rootId, save);
}
export function makeOnMoveHistoryIndex(rootId: string, direction: number) {
export function makeOnMoveHistoryIndex(rootId: string, direction: number): () => NewActionFunc<boolean, GlobalState> { // HARRISONTODO unused
const getMessageInHistory = makeGetMessageInHistoryItem(Posts.MESSAGE_TYPES.COMMENT as 'comment');
return () => (dispatch: DispatchFunc, getState: () => GlobalState) => {
return () => (dispatch, getState) => {
const draft = getPostDraft(getState(), StoragePrefixes.COMMENT_DRAFT, rootId);
if (draft.message !== '' && draft.message !== getMessageInHistory(getState())) {
return {data: true};
@ -74,8 +74,8 @@ export function makeOnMoveHistoryIndex(rootId: string, direction: number) {
};
}
export function submitPost(channelId: string, rootId: string, draft: PostDraft) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function submitPost(channelId: string, rootId: string, draft: PostDraft): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const userId = getCurrentUserId(state);
@ -105,8 +105,8 @@ export function submitPost(channelId: string, rootId: string, draft: PostDraft)
};
}
export function submitCommand(channelId: string, rootId: string, draft: PostDraft) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function submitCommand(channelId: string, rootId: string, draft: PostDraft): NewActionFuncAsync<unknown, GlobalState> {
return async (dispatch, getState) => {
const state = getState();
const teamId = getCurrentTeamId(state);
@ -122,13 +122,13 @@ export function submitCommand(channelId: string, rootId: string, draft: PostDraf
const hookResult = await dispatch(runSlashCommandWillBePostedHooks(message, args));
if (hookResult.error) {
return {error: hookResult.error};
} else if (!hookResult.data.message && !hookResult.data.args) {
} else if (!hookResult.data!.message && !hookResult.data!.args) {
// do nothing with an empty return from a hook
return {};
}
message = hookResult.data.message;
args = hookResult.data.args;
message = hookResult.data!.message;
args = hookResult.data!.args;
const {error} = await dispatch(executeCommand(message, args));

View File

@ -3,8 +3,6 @@
import type {MockStoreEnhanced} from 'redux-mock-store';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {close, open, toggle} from 'actions/views/lhs';
import configureStore from 'store';
@ -24,7 +22,7 @@ describe('lhs view actions', () => {
},
};
let store: MockStoreEnhanced<GlobalState, DispatchFunc>;
let store: MockStoreEnhanced<GlobalState>;
beforeEach(() => {
store = mockStore(initialState);

View File

@ -3,7 +3,7 @@
import {selectChannel} from 'mattermost-redux/actions/channels';
import {getCurrentRelativeTeamUrl} from 'mattermost-redux/selectors/entities/teams';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {NewActionFunc, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {SidebarSize} from 'components/resizable_sidebar/constants';
@ -59,8 +59,8 @@ export const selectStaticPage = (itemId: string) => ({
data: itemId,
});
export const selectLhsItem = (type: LhsItemType, id?: string) => {
return (dispatch: DispatchFunc) => {
export const selectLhsItem = (type: LhsItemType, id?: string): ThunkActionFunc<unknown> => {
return (dispatch) => {
switch (type) {
case LhsItemType.Channel:
dispatch(selectChannel(id || ''));
@ -80,9 +80,9 @@ export const selectLhsItem = (type: LhsItemType, id?: string) => {
};
};
export function switchToLhsStaticPage(id: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function switchToLhsStaticPage(id: string): NewActionFunc<boolean, GlobalState> {
return (dispatch, getState) => {
const state = getState();
const teamUrl = getCurrentRelativeTeamUrl(state);
getHistory().push(`${teamUrl}/${id}`);

View File

@ -3,7 +3,7 @@
import {getCurrentUser, getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
import {getCurrentTeamId, getTeam} from 'mattermost-redux/selectors/entities/teams';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {NewActionFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import {getTeamRedirectChannelIfIsAccesible} from 'actions/global_actions';
import LocalStorageStore from 'stores/local_storage_store';
@ -13,13 +13,11 @@ import InvitationModal from 'components/invitation_modal';
import {getHistory} from 'utils/browser_history';
import {ActionTypes, Constants, ModalIdentifiers} from 'utils/constants';
import type {GlobalState} from 'types/store';
import {openModal} from './modals';
export function switchToChannels() {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function switchToChannels(): NewActionFuncAsync<boolean> {
return async (dispatch, getState) => {
const state = getState();
const currentUserId = getCurrentUserId(state);
const user = getCurrentUser(state);
const teamId = getCurrentTeamId(state) || LocalStorageStore.getPreviousTeamId(currentUserId);
@ -33,8 +31,8 @@ export function switchToChannels() {
};
}
export function openInvitationsModal(timeout = 1) {
return (dispatch: DispatchFunc) => {
export function openInvitationsModal(timeout = 1): NewActionFunc {
return (dispatch) => {
dispatch(switchToChannels());
setTimeout(() => {
dispatch(openModal({

View File

@ -2,6 +2,7 @@
// See LICENSE.txt for license information.
import {cloneDeep, set} from 'lodash';
import type {Dispatch} from 'redux';
import {batchActions} from 'redux-batched-actions';
import type {MockStoreEnhanced} from 'redux-mock-store';
@ -12,7 +13,6 @@ import type {IDMappedObjects} from '@mattermost/types/utilities';
import {SearchTypes} from 'mattermost-redux/action_types';
import * as PostActions from 'mattermost-redux/actions/posts';
import * as SearchActions from 'mattermost-redux/actions/search';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions.jsx';
import {
@ -132,7 +132,7 @@ describe('rhs view actions', () => {
},
} as GlobalState;
let store: MockStoreEnhanced<GlobalState, DispatchFunc>;
let store: MockStoreEnhanced<GlobalState>;
beforeEach(() => {
store = mockStore(initialState);
@ -277,7 +277,7 @@ describe('rhs view actions', () => {
describe('showFlaggedPosts', () => {
test('it dispatches the right actions', async () => {
(SearchActions.getFlaggedPosts as jest.Mock).mockReturnValue((dispatch: DispatchFunc) => {
(SearchActions.getFlaggedPosts as jest.Mock).mockReturnValue((dispatch: Dispatch) => {
dispatch({type: 'MOCK_GET_FLAGGED_POSTS'});
return {data: 'data'};
@ -321,7 +321,7 @@ describe('rhs view actions', () => {
describe('showPinnedPosts', () => {
test('it dispatches the right actions for the current channel', async () => {
(SearchActions.getPinnedPosts as jest.Mock).mockReturnValue((dispatch: DispatchFunc) => {
(SearchActions.getPinnedPosts as jest.Mock).mockReturnValue((dispatch: Dispatch) => {
dispatch({type: 'MOCK_GET_PINNED_POSTS'});
return {data: 'data'};
@ -367,7 +367,7 @@ describe('rhs view actions', () => {
test('it dispatches the right actions for a specific channel', async () => {
const channelId = 'channel1';
(SearchActions.getPinnedPosts as jest.Mock).mockReturnValue((dispatch: DispatchFunc) => {
(SearchActions.getPinnedPosts as jest.Mock).mockReturnValue((dispatch: Dispatch) => {
dispatch({type: 'MOCK_GET_PINNED_POSTS'});
return {data: 'data'};
@ -741,7 +741,7 @@ describe('rhs view actions', () => {
});
it('opens pinned posts', async () => {
(SearchActions.getPinnedPosts as jest.Mock).mockReturnValue((dispatch: DispatchFunc) => {
(SearchActions.getPinnedPosts as jest.Mock).mockReturnValue((dispatch: Dispatch) => {
dispatch({type: 'MOCK_GET_PINNED_POSTS'});
return {data: 'data'};
});
@ -765,7 +765,7 @@ describe('rhs view actions', () => {
});
it('opens flagged posts', async () => {
(SearchActions.getFlaggedPosts as jest.Mock).mockReturnValue((dispatch: DispatchFunc) => {
(SearchActions.getFlaggedPosts as jest.Mock).mockReturnValue((dispatch: Dispatch) => {
dispatch({type: 'MOCK_GET_FLAGGED_POSTS'});
return {data: 'data'};

View File

@ -24,7 +24,7 @@ import {getPost} from 'mattermost-redux/selectors/entities/posts';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone';
import {getCurrentUser, getCurrentUserMentionKeys} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GetStateFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {NewActionFunc, NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions.jsx';
import {getSearchTerms, getRhsState, getPluggableId, getFilesSearchExtFilter, getPreviousRhsState} from 'selectors/rhs';
@ -37,11 +37,11 @@ import {getBrowserUtcOffset, getUtcOffsetForTimeZone} from 'utils/timezone';
import type {GlobalState} from 'types/store';
import type {RhsState} from 'types/store/rhs';
function selectPostFromRightHandSideSearchWithPreviousState(post: Post, previousRhsState?: RhsState) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
function selectPostFromRightHandSideSearchWithPreviousState(post: Post, previousRhsState?: RhsState): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
const postRootId = post.root_id || post.id;
await dispatch(PostActions.getPostThread(postRootId));
const state = getState() as GlobalState;
const state = getState();
dispatch({
type: ActionTypes.SELECT_POST,
@ -55,9 +55,9 @@ function selectPostFromRightHandSideSearchWithPreviousState(post: Post, previous
};
}
function selectPostCardFromRightHandSideSearchWithPreviousState(post: Post, previousRhsState?: RhsState) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
function selectPostCardFromRightHandSideSearchWithPreviousState(post: Post, previousRhsState?: RhsState): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
const state = getState();
dispatch({
type: ActionTypes.SELECT_POST_CARD,
@ -70,8 +70,8 @@ function selectPostCardFromRightHandSideSearchWithPreviousState(post: Post, prev
};
}
export function updateRhsState(rhsState: string, channelId?: string, previousRhsState?: RhsState) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function updateRhsState(rhsState: string, channelId?: string, previousRhsState?: RhsState): NewActionFunc<boolean> {
return (dispatch, getState) => {
const action: AnyAction = {
type: ActionTypes.UPDATE_RHS_STATE,
state: rhsState,
@ -105,9 +105,9 @@ export function openShowEditHistory(post: Post) {
};
}
export function goBack() {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const prevState = getPreviousRhsState(getState() as GlobalState);
export function goBack(): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
const prevState = getPreviousRhsState(getState());
const defaultTab = 'channel-info';
dispatch({
@ -123,12 +123,12 @@ export function selectPostFromRightHandSideSearch(post: Post) {
return selectPostFromRightHandSideSearchWithPreviousState(post);
}
export function selectPostCardFromRightHandSideSearch(post: Post) {
export function selectPostCardFromRightHandSideSearch(post: Post) { // HARRISONTODO unused
return selectPostCardFromRightHandSideSearchWithPreviousState(post);
}
export function selectPostFromRightHandSideSearchByPostId(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function selectPostFromRightHandSideSearchByPostId(postId: string): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
const post = getPost(getState(), postId);
return dispatch(selectPostFromRightHandSideSearch(post));
};
@ -170,8 +170,8 @@ export function setRhsSize(rhsSize?: SidebarSize) {
};
}
export function updateSearchTermsForShortcut() {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function updateSearchTermsForShortcut(): ThunkActionFunc<unknown> {
return (dispatch, getState) => {
const currentChannelName = getCurrentChannelNameForSearchShortcut(getState());
return dispatch(updateSearchTerms(`in:${currentChannelName} `));
};
@ -191,13 +191,13 @@ function updateSearchResultsTerms(terms: string) {
};
}
export function performSearch(terms: string, isMentionSearch?: boolean) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function performSearch(terms: string, isMentionSearch?: boolean): ThunkActionFunc<unknown, GlobalState> {
return (dispatch, getState) => {
let searchTerms = terms;
const teamId = getCurrentTeamId(getState());
const config = getConfig(getState());
const viewArchivedChannels = config.ExperimentalViewArchivedChannels === 'true';
const extensionsFilters = getFilesSearchExtFilter(getState() as GlobalState);
const extensionsFilters = getFilesSearchExtFilter(getState());
const extensions = extensionsFilters?.map((ext) => `ext:${ext}`).join(' ');
let termsWithExtensionsFilters = searchTerms;
@ -231,18 +231,15 @@ export function performSearch(terms: string, isMentionSearch?: boolean) {
}
export function filterFilesSearchByExt(extensions: string[]) {
return (dispatch: DispatchFunc) => {
dispatch({
type: ActionTypes.SET_FILES_FILTER_BY_EXT,
data: extensions,
});
return {data: true};
return {
type: ActionTypes.SET_FILES_FILTER_BY_EXT,
data: extensions,
};
}
export function showSearchResults(isMentionSearch = false) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function showSearchResults(isMentionSearch = false): ThunkActionFunc<unknown, GlobalState> {
return (dispatch, getState) => {
const state = getState();
const searchTerms = getSearchTerms(state);
@ -265,9 +262,9 @@ export function showRHSPlugin(pluggableId: string) {
};
}
export function showChannelMembers(channelId: string, inEditingMode = false) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function showChannelMembers(channelId: string, inEditingMode = false): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
const state = getState();
if (inEditingMode) {
await dispatch(setEditChannelMembers(true));
@ -288,8 +285,8 @@ export function showChannelMembers(channelId: string, inEditingMode = false) {
};
}
export function hideRHSPlugin(pluggableId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function hideRHSPlugin(pluggableId: string): NewActionFunc<boolean, GlobalState> {
return (dispatch, getState) => {
const state = getState() as GlobalState;
if (getPluggableId(state) === pluggableId) {
@ -300,9 +297,9 @@ export function hideRHSPlugin(pluggableId: string) {
};
}
export function toggleRHSPlugin(pluggableId: string) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function toggleRHSPlugin(pluggableId: string): NewActionFunc<boolean, GlobalState> {
return (dispatch, getState) => {
const state = getState();
if (getPluggableId(state) === pluggableId) {
dispatch(hideRHSPlugin(pluggableId));
@ -392,9 +389,9 @@ export function showPinnedPosts(channelId?: string): NewActionFuncAsync<boolean,
};
}
export function showChannelFiles(channelId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
export function showChannelFiles(channelId: string): NewActionFuncAsync<boolean, GlobalState> {
return async (dispatch, getState) => {
const state = getState();
const teamId = getCurrentTeamId(state);
let previousRhsState = getRhsState(state);
@ -450,8 +447,8 @@ export function showChannelFiles(channelId: string) {
};
}
export function showMentions() {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function showMentions(): NewActionFunc<boolean, GlobalState> {
return (dispatch, getState) => {
const termKeys = getCurrentUserMentionKeys(getState()).filter(({key}) => {
return key !== '@channel' && key !== '@all' && key !== '@here';
});
@ -477,18 +474,15 @@ export function showMentions() {
}
export function showChannelInfo(channelId: string) {
return (dispatch: DispatchFunc) => {
dispatch({
type: ActionTypes.UPDATE_RHS_STATE,
channelId,
state: RHSStates.CHANNEL_INFO,
});
return {data: true};
return {
type: ActionTypes.UPDATE_RHS_STATE,
channelId,
state: RHSStates.CHANNEL_INFO,
};
}
export function closeRightHandSide() {
return (dispatch: DispatchFunc) => {
export function closeRightHandSide(): NewActionFunc {
return (dispatch) => {
const actionsBatch: AnyAction[] = [
{
type: ActionTypes.UPDATE_RHS_STATE,
@ -507,15 +501,15 @@ export function closeRightHandSide() {
};
}
export const toggleMenu = () => (dispatch: DispatchFunc) => dispatch({
export const toggleMenu = (): ThunkActionFunc<unknown> => (dispatch) => dispatch({
type: ActionTypes.TOGGLE_RHS_MENU,
});
export const openMenu = () => (dispatch: DispatchFunc) => dispatch({
export const openMenu = (): ThunkActionFunc<unknown> => (dispatch) => dispatch({
type: ActionTypes.OPEN_RHS_MENU,
});
export const closeMenu = () => (dispatch: DispatchFunc) => dispatch({
export const closeMenu = (): ThunkActionFunc<unknown> => (dispatch) => dispatch({
type: ActionTypes.CLOSE_RHS_MENU,
});
@ -532,13 +526,14 @@ export function toggleRhsExpanded() {
};
}
export function selectPostAndParentChannel(post: Post) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function selectPostAndParentChannel(post: Post): NewActionFuncAsync { // HARRISONTODO unused
return async (dispatch, getState) => {
const channel = getChannelSelector(getState(), post.channel_id);
if (!channel) {
await dispatch(getChannel(post.channel_id));
}
return dispatch(selectPost(post));
dispatch(selectPost(post));
return {data: true};
};
}
@ -551,8 +546,8 @@ export function selectPost(post: Post) {
};
}
export function selectPostById(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function selectPostById(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const post = getPost(state, postId) ?? (await dispatch(fetchPost(postId))).data;
if (post) {
@ -582,8 +577,8 @@ export const debouncedClearHighlightReply = debounce((dispatch) => {
return dispatch(clearHighlightReply);
}, Constants.PERMALINK_FADEOUT);
export function selectPostAndHighlight(post: Post) {
return (dispatch: DispatchFunc) => {
export function selectPostAndHighlight(post: Post): NewActionFunc {
return (dispatch) => {
dispatch(batchActions([
selectPost(post),
highlightReply(post),
@ -599,8 +594,8 @@ export function selectPostCard(post: Post) {
return {type: ActionTypes.SELECT_POST_CARD, postId: post.id, channelId: post.channel_id};
}
export function openRHSSearch() {
return (dispatch: DispatchFunc) => {
export function openRHSSearch(): NewActionFunc {
return (dispatch) => {
dispatch(clearSearch());
dispatch(updateSearchTerms(''));
dispatch(updateSearchResultsTerms(''));
@ -611,8 +606,8 @@ export function openRHSSearch() {
};
}
export function openAtPrevious(previous: any) { // TODO Could not find the proper type. Seems to be in several props around
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function openAtPrevious(previous: any): ThunkActionFunc<unknown, GlobalState> {
return (dispatch, getState) => {
if (!previous) {
return dispatch(openRHSSearch());
}
@ -659,11 +654,8 @@ export const unsuppressRHS = {
};
export function setEditChannelMembers(active: boolean) {
return (dispatch: DispatchFunc) => {
dispatch({
type: ActionTypes.SET_EDIT_CHANNEL_MEMBERS,
active,
});
return {data: true};
return {
type: ActionTypes.SET_EDIT_CHANNEL_MEMBERS,
active,
};
}

View File

@ -4,7 +4,7 @@
import {getClientConfig, getLicenseConfig} from 'mattermost-redux/actions/general';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {getCurrentLocale, getTranslations} from 'selectors/i18n';
@ -18,8 +18,8 @@ const pluginTranslationSources: Record<string, TranslationPluginFunction> = {};
export type TranslationPluginFunction = (locale: string) => Translations
export function loadConfigAndMe() {
return async (dispatch: DispatchFunc) => {
export function loadConfigAndMe(): NewActionFuncAsync<boolean> {
return async (dispatch) => {
await Promise.all([
dispatch(getClientConfig()),
dispatch(getLicenseConfig()),
@ -35,10 +35,10 @@ export function loadConfigAndMe() {
};
}
export function registerPluginTranslationsSource(pluginId: string, sourceFunction: TranslationPluginFunction) {
export function registerPluginTranslationsSource(pluginId: string, sourceFunction: TranslationPluginFunction): ThunkActionFunc<void, GlobalState> {
pluginTranslationSources[pluginId] = sourceFunction;
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
const state = getState() as GlobalState;
return (dispatch, getState) => {
const state = getState();
const locale = getCurrentLocale(state);
const immutableTranslations = getTranslations(state, locale);
const translations = {};
@ -60,8 +60,8 @@ export function unregisterPluginTranslationsSource(pluginId: string) {
Reflect.deleteProperty(pluginTranslationSources, pluginId);
}
export function loadTranslations(locale: string, url: string) {
return async (dispatch: DispatchFunc) => {
export function loadTranslations(locale: string, url: string): NewActionFuncAsync {
return async (dispatch) => {
const translations = {...en};
Object.values(pluginTranslationSources).forEach((pluginFunc) => {
Object.assign(translations, pluginFunc(locale));
@ -87,8 +87,8 @@ export function loadTranslations(locale: string, url: string) {
};
}
export function registerCustomPostRenderer(type: string, component: any, id: string) {
return async (dispatch: DispatchFunc) => {
export function registerCustomPostRenderer(type: string, component: any, id: string): NewActionFuncAsync {
return async (dispatch) => {
// piggyback on plugins state to register a custom post renderer
dispatch({
type: ActionTypes.RECEIVED_PLUGIN_POST_COMPONENT,

View File

@ -14,7 +14,6 @@ import {
getCloudCustomer as selectCloudCustomer,
getCloudErrors,
} from 'mattermost-redux/selectors/entities/cloud';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {pageVisited} from 'actions/telemetry_actions';
@ -58,7 +57,7 @@ export const searchableStrings = [
];
const BillingSubscriptions = () => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const subscription = useSelector(selectCloudSubscription);
const [cloudLimits] = useGetLimits();
const errorLoadingData = useSelector((state: GlobalState) => {

View File

@ -7,7 +7,6 @@ import {useDispatch, useSelector} from 'react-redux';
import {getCloudCustomer} from 'mattermost-redux/actions/cloud';
import {getCloudErrors} from 'mattermost-redux/selectors/entities/cloud';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {pageVisited} from 'actions/telemetry_actions';
@ -27,7 +26,7 @@ export const searchableStrings = [
];
const CompanyInfo: React.FC<Props> = () => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const {customer: customerError} = useSelector(getCloudErrors);
useEffect(() => {

View File

@ -10,7 +10,6 @@ import type {Feedback} from '@mattermost/types/cloud';
import {getSubscriptionProduct} from 'mattermost-redux/selectors/entities/cloud';
import {getLicense} from 'mattermost-redux/selectors/entities/general';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {subscribeCloudSubscription, deleteWorkspace as deleteWorkspaceRequest} from 'actions/cloud';
import {closeModal, openModal} from 'actions/views/modals';
@ -45,7 +44,7 @@ export const messages = defineMessages({
});
export default function DeleteWorkspaceModal(props: Props) {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const openDowngradeModal = useOpenDowngradeModal();
// License/product checks.

View File

@ -9,7 +9,6 @@ import type {GlobalState} from '@mattermost/types/store';
import {getCloudCustomer} from 'mattermost-redux/actions/cloud';
import {getCloudErrors} from 'mattermost-redux/selectors/entities/cloud';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {pageVisited} from 'actions/telemetry_actions';
@ -32,7 +31,7 @@ export const searchableStrings = [
];
const PaymentInfo: React.FC<Props> = () => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const {customer: customerError} = useSelector(getCloudErrors);
const isCardAboutToExpire = useSelector((state: GlobalState) => {

View File

@ -8,8 +8,6 @@ import {useDispatch} from 'react-redux';
import {AlertOutlineIcon} from '@mattermost/compass-icons/components';
import type {AllowedIPRange, FetchIPResponse} from '@mattermost/types/config';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {applyIPFilters, getCurrentIP, getIPFilters} from 'actions/admin_actions';
import {getInstallation} from 'actions/cloud';
import {closeModal, openModal} from 'actions/views/modals';
@ -30,7 +28,7 @@ import SaveChangesPanel from '../team_channel_settings/save_changes_panel';
import './ip_filtering.scss';
const IPFiltering = () => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const {formatMessage} = useIntl();
const [ipFilters, setIpFilters] = useState<AllowedIPRange[] | null>(null);
const [originalIpFilters, setOriginalIpFilters] = useState<AllowedIPRange[] | null>(null);

View File

@ -7,8 +7,6 @@ import {useSelector, useDispatch} from 'react-redux';
import {GenericModal} from '@mattermost/components';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {closeModal} from 'actions/views/modals';
import {isModalOpen} from 'selectors/views/modals';
@ -27,7 +25,7 @@ type Props = {
}
const ConfirmLicenseRemovalModal: React.FC<Props> = (props: Props): JSX.Element | null => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const show = useSelector((state: GlobalState) => isModalOpen(state, ModalIdentifiers.CONFIRM_LICENSE_REMOVAL));
if (!show) {

View File

@ -6,8 +6,6 @@ import {useSelector, useDispatch} from 'react-redux';
import {GenericModal} from '@mattermost/components';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {closeModal} from 'actions/views/modals';
import {isModalOpen} from 'selectors/views/modals';
@ -22,7 +20,7 @@ type Props = {
}
const EELicenseModal: React.FC<Props> = (props: Props): JSX.Element | null => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const show = useSelector((state: GlobalState) => isModalOpen(state, ModalIdentifiers.ENTERPRISE_EDITION_LICENSE));
if (!show) {

View File

@ -12,7 +12,6 @@ import type {ClientLicense} from '@mattermost/types/config';
import {uploadLicense} from 'mattermost-redux/actions/admin';
import {getLicenseConfig} from 'mattermost-redux/actions/general';
import {getLicense} from 'mattermost-redux/selectors/entities/general';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {closeModal} from 'actions/views/modals';
import {getCurrentLocale} from 'selectors/i18n';
@ -38,7 +37,7 @@ type Props = {
}
const UploadLicenseModal = (props: Props): JSX.Element | null => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const [fileObj, setFileObj] = React.useState<File | null>(props.fileObjFromProps);
const [isUploading, setIsUploading] = React.useState(false);

View File

@ -42,12 +42,8 @@ export interface Props {
enableGuestAccounts: boolean;
filters: Filters;
actions: {
loadTeamMembersForProfilesList: (profiles: UserProfile[], teamId: string) => Promise<{
data: boolean;
}>;
loadChannelMembersForProfilesList: (profiles: UserProfile[], channelId: string) => Promise<{
data: boolean;
}>;
loadTeamMembersForProfilesList: (profiles: UserProfile[], teamId: string) => Promise<ActionResult>;
loadChannelMembersForProfilesList: (profiles: UserProfile[], channelId: string) => Promise<ActionResult>;
setModalSearchTerm: (term: string) => ActionResult;
setModalFilters: (filters: Filters) => ActionResult;
};

View File

@ -14,7 +14,6 @@ import {
} from 'mattermost-redux/selectors/entities/cloud';
import {getLicense} from 'mattermost-redux/selectors/entities/general';
import {isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {getHistory} from 'utils/browser_history';
import {isCustomerCardExpired} from 'utils/cloud_utils';
@ -25,7 +24,7 @@ import AnnouncementBar from '../default_announcement_bar';
export default function PaymentAnnouncementBar() {
const [requestedCustomer, setRequestedCustomer] = useState(false);
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const subscription = useSelector(selectCloudSubscription);
const customer = useSelector(selectCloudCustomer);
const isStarterFree = useSelector(getSubscriptionProduct)?.sku === CloudProducts.STARTER;

View File

@ -10,7 +10,6 @@ import {savePreferences} from 'mattermost-redux/actions/preferences';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUser, isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
import {isModalOpen} from 'selectors/views/modals';
@ -31,7 +30,7 @@ const ShowStartTrialModal = () => {
const isUserAdmin = useSelector((state: GlobalState) => isCurrentUserSystemAdmin(state));
const openStartTrialFormModal = useOpenStartTrialFormModal();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const getCategory = makeGetCategory();
const userThreshold = 10;

View File

@ -11,7 +11,6 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
import {getLicense} from 'mattermost-redux/selectors/entities/general';
import {get as getPreference} from 'mattermost-redux/selectors/entities/preferences';
import {isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
import {openModal, closeModal} from 'actions/views/modals';
@ -37,7 +36,7 @@ const ShowThreeDaysLeftTrialModal = () => {
const subscription = useSelector(getCloudSubscription);
const isFreeTrial = subscription?.is_free_trial === 'true';
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const hadAdminDismissedModal = useSelector((state: GlobalState) => getPreference(state, Preferences.CLOUD_TRIAL_BANNER, CloudBanners.THREE_DAYS_LEFT_TRIAL_MODAL_DISMISSED)) === 'true';
const trialEndDate = new Date(subscription?.trial_end_at || 0);

View File

@ -5,8 +5,6 @@ import classNames from 'classnames';
import React, {useEffect} from 'react';
import {useDispatch} from 'react-redux';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {loadStatusesForChannelAndSidebar} from 'actions/status_actions';
import CenterChannel from 'components/channel_layout/center_channel';
@ -27,7 +25,7 @@ type Props = {
}
export default function ChannelController(props: Props) {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
useEffect(() => {
const isMsBrowser = isInternetExplorer() || isEdge();

View File

@ -20,7 +20,6 @@ import {CategoryTypes} from 'mattermost-redux/constants/channel_categories';
import {getCategoryInTeamWithChannel} from 'mattermost-redux/selectors/entities/channel_categories';
import {getAllChannels} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
import {addChannelsInSidebar} from 'actions/views/channel_sidebar';
@ -42,7 +41,7 @@ type Props = {
const ChannelMoveToSubMenu = (props: Props) => {
const {formatMessage} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const allChannels = useSelector(getAllChannels);
const multiSelectedChannelIds = useSelector((state: GlobalState) => state.views.channelSidebar.multiSelectedChannelIds);

View File

@ -18,7 +18,6 @@ import {CategoryTypes} from 'mattermost-redux/constants/channel_categories';
import {getCategoryInTeamWithChannel} from 'mattermost-redux/selectors/entities/channel_categories';
import {getAllChannels} from 'mattermost-redux/selectors/entities/channels';
import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
import {addChannelsInSidebar} from 'actions/views/channel_sidebar';
@ -42,7 +41,7 @@ type Props = {
const ChannelMoveToSubMenuOld = (props: Props) => {
const {formatMessage} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const allChannels = useSelector(getAllChannels);
const multiSelectedChannelIds = useSelector((state: GlobalState) => state.views.channelSidebar.multiSelectedChannelIds);

View File

@ -8,7 +8,6 @@ import {FormattedMessage} from 'react-intl';
import {useDispatch, useSelector} from 'react-redux';
import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {retryFailedCloudFetches} from 'actions/cloud';
import {retryFailedHostedCustomerFetches} from 'actions/hosted_customer';
@ -16,7 +15,7 @@ import {retryFailedHostedCustomerFetches} from 'actions/hosted_customer';
import './cloud_fetch_error.scss';
export default function CloudFetchError() {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const isCloud = useSelector(isCurrentLicenseCloud);
return (<div className='CloudFetchError '>
<div className='CloudFetchError__header '>

View File

@ -8,7 +8,6 @@ import {useDispatch} from 'react-redux';
import {GenericModal} from '@mattermost/components';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {isEmail} from 'mattermost-redux/utils/helpers';
import {validateBusinessEmail} from 'actions/cloud';
@ -36,7 +35,7 @@ const RequestBusinessEmailModal = (
onExited,
}: Props): JSX.Element | null => {
const {formatMessage} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const [email, setEmail] = useState<string>('');
const [customInputLabel, setCustomInputLabel] = useState<CustomMessageInputType>(null);
const [trialBtnDisabled, setTrialBtnDisabled] = useState<boolean>(true);

View File

@ -5,15 +5,14 @@ import {useEffect, useState} from 'react';
import {useDispatch} from 'react-redux';
import {getFilteredUsersStats} from 'mattermost-redux/actions/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
const useGetTotalUsersNoBots = (includeInactive = false): number => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const [userCount, setUserCount] = useState<number>(0);
const getTotalUsers = async () => {
const {data} = await dispatch(getFilteredUsersStats({include_bots: false, include_deleted: includeInactive}, false));
setUserCount(data?.total_users_count);
setUserCount(data?.total_users_count ?? 0);
};
useEffect(() => {

View File

@ -10,8 +10,6 @@ import {useHistory, useLocation} from 'react-router-dom';
import type {UserProfile} from '@mattermost/types/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {loginWithDesktopToken} from 'actions/views/login';
import DesktopApp from 'utils/desktop_api';
@ -35,7 +33,7 @@ type Props = {
}
const DesktopAuthToken: React.FC<Props> = ({href, onLogin}: Props) => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const history = useHistory();
const {search} = useLocation();
const query = new URLSearchParams(search);

View File

@ -10,7 +10,6 @@ import {clearErrors, logError} from 'mattermost-redux/actions/errors';
import {verifyUserEmail, getMe} from 'mattermost-redux/actions/users';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {redirectUserToDefaultTeam} from 'actions/global_actions';
import {trackEvent} from 'actions/telemetry_actions.jsx';
@ -32,7 +31,7 @@ const enum VerifyStatus {
const DoVerifyEmail = () => {
const {formatMessage} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const history = useHistory();
const {search} = useLocation();

View File

@ -13,7 +13,6 @@ import {checkHadPriorTrial} from 'mattermost-redux/selectors/entities/cloud';
import {getLicense} from 'mattermost-redux/selectors/entities/general';
import {deprecateCloudFree} from 'mattermost-redux/selectors/entities/preferences';
import {isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {closeModal} from 'actions/views/modals';
import {isModalOpen} from 'selectors/views/modals';
@ -56,7 +55,7 @@ const FeatureRestrictedModal = ({
minimumPlanRequiredForFeature,
}: FeatureRestrictedModalProps) => {
const {formatMessage} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
useEffect(() => {
dispatch(getPrevTrialLicense());

View File

@ -10,7 +10,6 @@ import {getSubscriptionProduct, checkHadPriorTrial} from 'mattermost-redux/selec
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {deprecateCloudFree} from 'mattermost-redux/selectors/entities/preferences';
import {isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {closeModal, openModal} from 'actions/views/modals';
@ -42,7 +41,7 @@ export default function InviteAs(props: Props) {
const {formatMessage} = useIntl();
const license = useSelector(getLicense);
const cloudFreeDeprecated = useSelector(deprecateCloudFree);
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
useEffect(() => {
dispatch(getPrevTrialLicense());

View File

@ -9,7 +9,6 @@ import {GenericModal} from '@mattermost/components';
import {getLicense} from 'mattermost-redux/selectors/entities/general';
import {deprecateCloudFree} from 'mattermost-redux/selectors/entities/preferences';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
import {closeModal} from 'actions/views/modals';
@ -43,7 +42,7 @@ const LearnMoreTrialModal = (
}: Props): JSX.Element | null => {
const {formatMessage} = useIntl();
const [embargoed, setEmbargoed] = useState(false);
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const [, salesLink] = useOpenSalesLink();

View File

@ -10,7 +10,7 @@ import {autoUpdateTimezone} from 'mattermost-redux/actions/timezone';
import {getChannel, getCurrentChannelId, isManuallyUnread} from 'mattermost-redux/selectors/entities/channels';
import {getLicense, getConfig} from 'mattermost-redux/selectors/entities/general';
import {getCurrentUser, shouldShowTermsOfService} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GenericAction} from 'mattermost-redux/types/actions';
import type {GenericAction, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {getChannelURL} from 'selectors/urls';
@ -44,7 +44,7 @@ function mapStateToProps(state: GlobalState, ownProps: Props) {
}
// NOTE: suggestions where to keep this welcomed
const getChannelURLAction = (channelId: string, teamId: string, url: string) => (dispatch: DispatchFunc, getState: () => GlobalState) => {
const getChannelURLAction = (channelId: string, teamId: string, url: string): ThunkActionFunc<void, GlobalState> => (dispatch, getState) => {
const state = getState();
if (url && isPermalinkURL(url)) {

View File

@ -10,23 +10,18 @@ import {useSelector, useDispatch} from 'react-redux';
import {Link, useLocation, useHistory, Route} from 'react-router-dom';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {loadMe} from 'mattermost-redux/actions/users';
import {Client4} from 'mattermost-redux/client';
import {RequestStatus} from 'mattermost-redux/constants';
import {isCurrentLicenseCloud} from 'mattermost-redux/selectors/entities/cloud';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {getIsOnboardingFlowEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getTeamByName, getMyTeamMember} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {isSystemAdmin} from 'mattermost-redux/utils/user_utils';
import {redirectUserToDefaultTeam} from 'actions/global_actions';
import {addUserToTeamFromInvite} from 'actions/team_actions';
import {trackEvent} from 'actions/telemetry_actions';
import {setNeedsLoggedInLimitReachedCheck} from 'actions/views/admin';
import {login} from 'actions/views/login';
import LocalStorageStore from 'stores/local_storage_store';
@ -73,7 +68,7 @@ type LoginProps = {
const Login = ({onCustomizeHeader}: LoginProps) => {
const {formatMessage} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const history = useHistory();
const {pathname, search, hash} = useLocation();
@ -112,7 +107,6 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
const experimentalPrimaryTeam = useSelector((state: GlobalState) => (ExperimentalPrimaryTeam ? getTeamByName(state, ExperimentalPrimaryTeam) : undefined));
const experimentalPrimaryTeamMember = useSelector((state: GlobalState) => getMyTeamMember(state, experimentalPrimaryTeam?.id ?? ''));
const onboardingFlowEnabled = useSelector(getIsOnboardingFlowEnabled);
const isCloud = useSelector(isCurrentLicenseCloud);
const loginIdInput = useRef<HTMLInputElement>(null);
const passwordInput = useRef<HTMLInputElement>(null);
@ -578,7 +572,7 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
const submit = async ({loginId, password, token}: SubmitOptions) => {
setIsWaiting(true);
const {data: userProfile, error: loginError} = await dispatch(login(loginId, password, token));
const {error: loginError} = await dispatch(login(loginId, password, token));
if (loginError && loginError.server_error_id && loginError.server_error_id.length !== 0) {
if (loginError.server_error_id === 'api.user.login.not_verified.app_error') {
@ -632,10 +626,10 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
return;
}
await postSubmit(userProfile);
await postSubmit();
};
const postSubmit = async (userProfile: UserProfile) => {
const postSubmit = async () => {
await dispatch(loadMe());
// check for query params brought over from signup_user_complete
@ -647,21 +641,17 @@ const Login = ({onCustomizeHeader}: LoginProps) => {
const {data: team} = await dispatch(addUserToTeamFromInvite(inviteToken, inviteId));
if (team) {
finishSignin(userProfile, team);
finishSignin(team);
} else {
// there's not really a good way to deal with this, so just let the user log in like normal
finishSignin(userProfile);
finishSignin();
}
} else {
finishSignin(userProfile);
finishSignin();
}
};
const finishSignin = (userProfile: UserProfile, team?: Team) => {
if (isCloud && isSystemAdmin(userProfile.roles)) {
dispatch(setNeedsLoggedInLimitReachedCheck(true));
}
const finishSignin = (team?: Team) => {
setCSRFFromCookie();
// Record a successful login to local storage. If an unintentional logout occurs, e.g.

View File

@ -8,7 +8,7 @@ import {General, Preferences, WebsocketEvents} from 'mattermost-redux/constants'
import {getConfig, isPerformanceDebuggingEnabled} from 'mattermost-redux/selectors/entities/general';
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId, getStatusForUserId} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
function getTimeBetweenTypingEvents(state: GlobalState) {
const config = getConfig(state);
@ -16,8 +16,8 @@ function getTimeBetweenTypingEvents(state: GlobalState) {
return config.TimeBetweenUserTypingUpdatesMilliseconds === undefined ? 0 : parseInt(config.TimeBetweenUserTypingUpdatesMilliseconds, 10);
}
export function userStartedTyping(userId: string, channelId: string, rootId: string, now: number) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function userStartedTyping(userId: string, channelId: string, rootId: string, now: number): ThunkActionFunc<void> {
return (dispatch, getState) => {
const state = getState();
if (
@ -45,8 +45,8 @@ export function userStartedTyping(userId: string, channelId: string, rootId: str
};
}
function fillInMissingInfo(userId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
function fillInMissingInfo(userId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const currentUserId = getCurrentUserId(state);

View File

@ -34,7 +34,7 @@ interface FormDateStateWithoutOtherPayment {
}
export const useGatherIntent = ({typeGatherIntent}: UseGatherIntentArgs) => {
const dispatch = useDispatch<any>();
const dispatch = useDispatch();
const [feedbackSaved, setFeedbackSave] = useState(false);
const [showError, setShowError] = useState(false);
const [submittingFeedback, setSubmittingFeedback] = useState(false);

View File

@ -12,7 +12,7 @@ import {getCurrentChannel, getChannel as getChannelFromRedux} from 'mattermost-r
import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeam, getTeam} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {getUserIdFromChannelName} from 'mattermost-redux/utils/channel_utils';
import {isSystemAdmin} from 'mattermost-redux/utils/user_utils';
@ -33,8 +33,8 @@ type Option = {
skipRedirectReplyPermalink: boolean;
}
function focusRootPost(post: Post, channel: Channel) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
function focusRootPost(post: Post, channel: Channel): NewActionFuncAsync {
return async (dispatch, getState) => {
const postURL = getPostURL(getState() as GlobalState, post);
dispatch(selectChannel(channel.id));
@ -49,11 +49,11 @@ function focusRootPost(post: Post, channel: Channel) {
};
}
function focusReplyPost(post: Post, channel: Channel, teamId: string, returnTo: string, option: Option) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
function focusReplyPost(post: Post, channel: Channel, teamId: string, returnTo: string, option: Option): NewActionFuncAsync {
return async (dispatch, getState) => {
const {data} = await dispatch(getPostThread(post.root_id));
if (data.first_inaccessible_post_time) {
if (data!.first_inaccessible_post_time) {
getHistory().replace(`/error?type=${ErrorPageTypes.CLOUD_ARCHIVED}&returnTo=${returnTo}`);
return {data: false};
}
@ -83,8 +83,8 @@ function focusReplyPost(post: Post, channel: Channel, teamId: string, returnTo:
};
}
export function focusPost(postId: string, returnTo = '', currentUserId: string, option: Option = {skipRedirectReplyPermalink: false}) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function focusPost(postId: string, returnTo = '', currentUserId: string, option: Option = {skipRedirectReplyPermalink: false}): ThunkActionFunc<Promise<void>> {
return async (dispatch, getState) => {
// Ignore if prompt is still visible
if (privateChannelJoinPromptVisible) {
return;
@ -108,7 +108,7 @@ export function focusPost(postId: string, returnTo = '', currentUserId: string,
privateChannelJoinPromptVisible = true;
const joinPromptResult = await dispatch(joinPrivateChannelPrompt(currentTeam, postInfo.channel_display_name));
privateChannelJoinPromptVisible = false;
if ('data' in joinPromptResult && !joinPromptResult.data.join) {
if ('data' in joinPromptResult && !joinPromptResult.data!.join) {
return;
}
}
@ -155,7 +155,7 @@ export function focusPost(postId: string, returnTo = '', currentUserId: string,
const membership = await dispatch(getChannelMember(channel.id, currentUserId));
if ('data' in membership) {
myMember = membership.data;
myMember = membership.data!;
}
if (!myMember) {

View File

@ -9,7 +9,6 @@ import {useDispatch} from 'react-redux';
import type {Post} from '@mattermost/types/posts';
import {getPostEditHistory} from 'mattermost-redux/actions/posts';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import AlertIcon from 'components/common/svg_images_components/alert_svg';
import LoadingScreen from 'components/loading_screen';
@ -48,7 +47,7 @@ const PostEditHistory = ({
const [postEditHistory, setPostEditHistory] = useState<Post[]>([]);
const [hasError, setHasError] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(false);
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const scrollbars = useRef<Scrollbars | null>(null);
const {formatMessage} = useIntl();
const retrieveErrorHeading = formatMessage({

View File

@ -15,7 +15,6 @@ import {
} from 'mattermost-redux/selectors/entities/cloud';
import {deprecateCloudFree} from 'mattermost-redux/selectors/entities/preferences';
import {isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {subscribeCloudSubscription} from 'actions/cloud';
import {trackEvent} from 'actions/telemetry_actions';
@ -58,7 +57,7 @@ type ContentProps = {
function Content(props: ContentProps) {
const {formatMessage, formatNumber} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const [limits] = useGetLimits();
const openPricingModalBackAction = useOpenPricingModal();

View File

@ -10,7 +10,6 @@ import {getTeammateNameDisplaySetting} from 'mattermost-redux/selectors/entities
import {getCurrentRelativeTeamUrl, getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getCurrentTimezone} from 'mattermost-redux/selectors/entities/timezone';
import {getStatusForUserId, getUser} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {displayUsername} from 'mattermost-redux/utils/user_utils';
import {openDirectChannelToUserId} from 'actions/channel_actions';
@ -112,7 +111,7 @@ const ProfilePopover = ({
}: ProfilePopoverProps) => {
const {formatMessage} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const user = useSelector((state: GlobalState) => getUser(state, userId));
const currentTeamId = useSelector((state: GlobalState) => getCurrentTeamId(state));
const channelId = useSelector((state: GlobalState) => (channelIdProp || getDefaultChannelId(state)));

View File

@ -9,6 +9,7 @@ import type {PreferenceType} from '@mattermost/types/preferences';
import type {UserStatus} from '@mattermost/types/users';
import {Preferences} from 'mattermost-redux/constants';
import type {ActionResult} from 'mattermost-redux/types/actions';
import ConfirmModal from 'components/confirm_modal';
@ -139,7 +140,7 @@ type Props = {
/*
* Function to get and then reset the user's status if needed
*/
autoResetStatus: () => Promise<{data: UserStatus}>;
autoResetStatus: () => Promise<ActionResult<UserStatus>>;
/*
* Function to set the status for a user
@ -172,8 +173,8 @@ export default class ResetStatusModal extends React.PureComponent<Props, State>
public componentDidMount(): void {
this.props.actions.autoResetStatus().then(
(result: {data: UserStatus}) => {
const status = result.data;
(result) => {
const status = result.data!;
const statusIsManual = status.manual;
const autoResetPrefNotSet = this.props.autoResetPref === '';

View File

@ -139,7 +139,7 @@ export type Actions = {
migrateRecentEmojis: () => void;
loadConfigAndMe: () => Promise<ActionResult>;
registerCustomPostRenderer: (type: string, component: any, id: string) => Promise<ActionResult>;
initializeProducts: () => Promise<ActionResult[]>;
initializeProducts: () => Promise<unknown>;
}
type Props = {

View File

@ -285,7 +285,7 @@ const Search: React.FC<Props> = (props: Props): JSX.Element => {
return;
}
const {error} = await actions.showSearchResults(Boolean(props.isMentionSearch));
const {error} = await actions.showSearchResults(Boolean(props.isMentionSearch)) as any;
if (!error) {
handleSearchOnSuccess();

View File

@ -43,7 +43,7 @@ export type DispatchProps = {
updateSearchTerms: (term: string) => Action;
updateSearchTermsForShortcut: () => void;
updateSearchType: (searchType: string) => Action;
showSearchResults: (isMentionSearch: boolean) => Record<string, any>;
showSearchResults: (isMentionSearch: boolean) => unknown;
showChannelFiles: (channelId: string) => void;
showMentions: () => void;
showFlaggedPosts: () => void;

View File

@ -18,7 +18,6 @@ import {getLicense} from 'mattermost-redux/selectors/entities/general';
import {getSelfHostedSignupProgress} from 'mattermost-redux/selectors/entities/hosted_customer';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUser, getFilteredUsersStats} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {confirmSelfHostedExpansion} from 'actions/hosted_customer';
import {pageVisited} from 'actions/telemetry_actions';
@ -166,7 +165,7 @@ export function canSubmit(formState: FormState, progress: ValueOf<typeof SelfHos
}
export default function SelfHostedExpansionModal() {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const intl = useIntl();
const cardRef = useRef<CardInputType | null>(null);
const theme = useSelector(getTheme);

View File

@ -8,7 +8,6 @@ import {useDispatch} from 'react-redux';
import {useLocation, useHistory} from 'react-router-dom';
import {sendVerificationEmail} from 'mattermost-redux/actions/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
@ -28,7 +27,7 @@ const enum ResendStatus {
const ShouldVerifyEmail = () => {
const {formatMessage} = useIntl();
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const history = useHistory();
const {search} = useLocation();

View File

@ -11,7 +11,6 @@ import {getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
import {haveICurrentChannelPermission} from 'mattermost-redux/selectors/entities/roles';
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
import {setAddChannelCtaDropdown} from 'actions/views/add_channel_dropdown';
@ -28,7 +27,7 @@ import {ModalIdentifiers, Preferences, Touched} from 'utils/constants';
import type {GlobalState} from 'types/store';
const AddChannelsCtaButton = (): JSX.Element | null => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const currentTeamId = useSelector(getCurrentTeamId);
const intl = useIntl();
const touchedAddChannelsCtaButton = useSelector((state: GlobalState) => getBool(state, Preferences.TOUCHED, Touched.ADD_CHANNELS_CTA));

View File

@ -16,7 +16,7 @@ import {localizeMessage} from 'utils/utils';
import type {PropsFromRedux} from './index';
interface Props extends PropsFromRedux {
export interface Props extends PropsFromRedux {
channel: Channel;
currentTeamName: string;
}

View File

@ -31,7 +31,7 @@ type Props = {
active: boolean;
actions: {
savePreferences: (userId: string, preferences: PreferenceType[]) => Promise<ActionResult>;
leaveDirectChannel: (channelId: string) => Promise<{data: boolean}>;
leaveDirectChannel: (channelId: string) => Promise<ActionResult>;
};
};

View File

@ -9,7 +9,6 @@ import {useSelector, useDispatch} from 'react-redux';
import {getLicenseConfig} from 'mattermost-redux/actions/general';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/common';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {requestTrialLicense} from 'actions/admin_actions';
import {validateBusinessEmail} from 'actions/cloud';
@ -69,7 +68,7 @@ type Props = {
function StartTrialFormModal(props: Props): JSX.Element | null {
const [status, setLoadStatus] = useState(TrialLoadStatus.NotStarted);
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const currentUser = useSelector(getCurrentUser);
const [name, setName] = useState('');
const [email, setEmail] = useState(currentUser.email);
@ -149,7 +148,7 @@ function StartTrialFormModal(props: Props): JSX.Element | null {
let buttonText;
let onTryAgain = handleErrorModalTryAgain;
if (data.status === 422) {
if ((data as any).status === 422) {
title = (<></>);
subtitle = (
<FormattedMessage

View File

@ -3,6 +3,8 @@
/* eslint-disable max-lines */
import type {Store} from 'redux';
import {Constants} from 'utils/constants';
import {
@ -56,7 +58,6 @@ import type {
AutocompleteSuggestion,
AutocompleteStaticSelect,
Channel,
Store,
ExtendedAutocompleteSuggestion} from './app_command_parser_dependencies';
export enum ParseState {
@ -990,7 +991,7 @@ export class AppCommandParser {
// Silently fail on default value
break;
}
user = dispatchResult.data;
user = dispatchResult.data!;
}
parsed.values[f.name] = user.username;
break;
@ -1004,7 +1005,7 @@ export class AppCommandParser {
// Silently fail on default value
break;
}
channel = dispatchResult.data;
channel = dispatchResult.data!;
}
parsed.values[f.name] = channel.name;
break;

View File

@ -5,17 +5,13 @@ import type {Channel} from '@mattermost/types/channels';
import type {AutocompleteSuggestion} from '@mattermost/types/integrations';
import type {UserProfile} from '@mattermost/types/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {sendEphemeralPost} from 'actions/global_actions';
import ReduxStore from 'stores/redux_store';
import reduxStore from 'stores/redux_store';
import {Constants} from 'utils/constants';
import {isMac} from 'utils/user_agent';
import {localizeAndFormatMessage} from 'utils/utils';
import type {GlobalState} from 'types/store';
import type {ParsedCommand} from './app_command_parser';
export type {
@ -72,12 +68,7 @@ export {
filterEmptyOptions,
} from 'utils/apps';
export type Store = {
dispatch: DispatchFunc;
getState: () => GlobalState;
}
export const getStore = () => ReduxStore;
export const getStore = () => reduxStore;
export {getChannelSuggestions, getUserSuggestions, inTextMentionSuggestions} from '../mentions';
@ -119,7 +110,7 @@ export type ExtendedAutocompleteSuggestion = AutocompleteSuggestion & {
}
export const displayError = (err: string, channelID: string, rootID?: string) => {
ReduxStore.dispatch(sendEphemeralPost(err, channelID, rootID));
reduxStore.dispatch(sendEphemeralPost(err, channelID, rootID));
};
// Shim of mobile-version intl

View File

@ -1,28 +1,22 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {Store} from 'redux';
import type {UserAutocomplete} from '@mattermost/types/autocomplete';
import type {Channel} from '@mattermost/types/channels';
import type {AutocompleteSuggestion} from '@mattermost/types/integrations';
import type {UserProfile} from '@mattermost/types/users';
import {autocompleteChannels} from 'mattermost-redux/actions/channels';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {autocompleteUsersInChannel} from 'actions/views/channel';
import {Constants} from 'utils/constants';
import type {GlobalState} from 'types/store';
export const COMMAND_SUGGESTION_CHANNEL = Constants.Integrations.COMMAND_SUGGESTION_CHANNEL;
export const COMMAND_SUGGESTION_USER = Constants.Integrations.COMMAND_SUGGESTION_USER;
export type Store = {
dispatch: DispatchFunc;
getState: () => GlobalState;
}
export async function inTextMentionSuggestions(pretext: string, store: Store, channelID: string, teamID: string, delimiter = ''): Promise<AutocompleteSuggestion[] | null> {
const separatedWords = pretext.split(' ');
const incompleteLessLastWord = separatedWords.slice(0, -1).join(' ');

View File

@ -7,8 +7,6 @@ import {useSelector, useDispatch} from 'react-redux';
import {GenericModal} from '@mattermost/components';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
import {closeModal} from 'actions/views/modals';
import {isModalOpen} from 'selectors/views/modals';
@ -27,7 +25,7 @@ type Props = {
}
const SwitchToYearlyPlanConfirmModal: React.FC<Props> = (props: Props): JSX.Element | null => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const {formatMessage} = useIntl();
const show = useSelector((state: GlobalState) => isModalOpen(state, ModalIdentifiers.CONFIRM_SWITCH_TO_YEARLY));

View File

@ -7,8 +7,6 @@ import {useSelector, useDispatch} from 'react-redux';
import {GenericModal} from '@mattermost/components';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {closeModal} from 'actions/views/modals';
import {isModalOpen} from 'selectors/views/modals';
@ -35,7 +33,7 @@ type Props = {
}
function ThreeDaysLeftTrialModal(props: Props): JSX.Element | null {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const {formatMessage} = useIntl();
const openPricingModal = useOpenPricingModal();
const show = useSelector((state: GlobalState) => isModalOpen(state, ModalIdentifiers.THREE_DAYS_LEFT_TRIAL_MODAL));

View File

@ -5,8 +5,6 @@ import React from 'react';
import {FormattedMessage} from 'react-intl';
import {useDispatch} from 'react-redux';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {trackEvent} from 'actions/telemetry_actions';
import {openModal} from 'actions/views/modals';
@ -24,7 +22,7 @@ export interface UpgradeLinkProps {
}
const UpgradeLink = (props: UpgradeLinkProps) => {
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const styleButton = props.styleButton ? ' style-button' : '';
const styleLink = props.styleLink ? ' style-link' : '';

View File

@ -10,7 +10,6 @@ import {getCloudSubscription, getSubscriptionProduct} from 'mattermost-redux/sel
import {getLicense} from 'mattermost-redux/selectors/entities/general';
import {deprecateCloudFree} from 'mattermost-redux/selectors/entities/preferences';
import {isCurrentUserSystemAdmin} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc} from 'mattermost-redux/types/actions';
import {openModal} from 'actions/views/modals';
@ -33,7 +32,7 @@ const MenuCloudTrial = ({id}: Props): JSX.Element | null => {
const subscriptionProduct = useSelector(getSubscriptionProduct);
const license = useSelector(getLicense);
const cloudFreeDeprecated = useSelector(deprecateCloudFree);
const dispatch = useDispatch<DispatchFunc>();
const dispatch = useDispatch();
const isCloud = license?.Cloud === 'true';
const isFreeTrial = subscription?.is_free_trial === 'true';

View File

@ -6,6 +6,7 @@ import {batchActions} from 'redux-batched-actions';
import type {Channel, ChannelUnread} from '@mattermost/types/channels';
import type {FetchPaginatedThreadOptions} from '@mattermost/types/client4';
import type {ServerError} from '@mattermost/types/errors';
import type {Group} from '@mattermost/types/groups';
import type {Post, PostList, PostAcknowledgement} from '@mattermost/types/posts';
import type {Reaction} from '@mattermost/types/reactions';
@ -31,7 +32,7 @@ import {getAllGroupsByName} from 'mattermost-redux/selectors/entities/groups';
import * as PostSelectors from 'mattermost-redux/selectors/entities/posts';
import {getUnreadScrollPositionPreference, isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentUserId, getUsersByUsername} from 'mattermost-redux/selectors/entities/users';
import type {ActionResult, DispatchFunc, GetStateFunc, NewActionFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {ActionResult, DispatchFunc, GetStateFunc, NewActionFunc, NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import {isCombinedUserActivityPost} from 'mattermost-redux/utils/post_list';
import {logError} from './errors';
@ -137,8 +138,8 @@ export function postRemoved(post: Post) {
};
}
export function getPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPost(postId: string): NewActionFuncAsync<Post> {
return async (dispatch, getState) => {
let post;
const crtEnabled = isCollapsedThreadsEnabled(getState());
@ -163,8 +164,8 @@ export function getPost(postId: string) {
};
}
export function createPost(post: Post, files: any[] = []) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function createPost(post: Post, files: any[] = []): NewActionFuncAsync {
return async (dispatch, getState) => {
const state = getState();
const currentUserId = state.entities.users.currentUserId;
@ -290,8 +291,8 @@ export function createPost(post: Post, files: any[] = []) {
};
}
export function createPostImmediately(post: Post, files: any[] = []) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function createPostImmediately(post: Post, files: any[] = []): NewActionFuncAsync<Post> {
return async (dispatch, getState) => {
const state = getState();
const currentUserId = state.entities.users.currentUserId;
const timestamp = Date.now();
@ -462,8 +463,8 @@ function getUnreadPostData(unreadChan: ChannelUnread, state: GlobalState) {
return data;
}
export function setUnreadPost(userId: string, postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function setUnreadPost(userId: string, postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
let state = getState();
const post = PostSelectors.getPost(state, postId);
let unreadChan;
@ -501,8 +502,8 @@ export function setUnreadPost(userId: string, postId: string) {
};
}
export function pinPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function pinPost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
dispatch({type: PostTypes.EDIT_POST_REQUEST});
let posts;
@ -553,8 +554,8 @@ export function decrementPinnedPostCount(channelId: Channel['id']) {
};
}
export function unpinPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function unpinPost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
dispatch({type: PostTypes.EDIT_POST_REQUEST});
let posts;
@ -592,8 +593,8 @@ export function unpinPost(postId: string) {
};
}
export function addReaction(postId: string, emojiName: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function addReaction(postId: string, emojiName: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const currentUserId = getState().entities.users.currentUserId;
let reaction;
@ -635,8 +636,8 @@ export function removeReaction(postId: string, emojiName: string): NewActionFunc
};
}
export function getCustomEmojiForReaction(name: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getCustomEmojiForReaction(name: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const nonExistentEmoji = getState().entities.emojis.nonExistentEmoji;
const customEmojisByName = selectCustomEmojisByName(getState());
@ -656,8 +657,8 @@ export function getCustomEmojiForReaction(name: string) {
};
}
export function getReactionsForPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getReactionsForPost(postId: string): ThunkActionFunc<Promise<Reaction[] | {error: ServerError}>> { // HARRISONTODO unused
return async (dispatch, getState) => {
let reactions;
try {
reactions = await Client4.getReactionsForPost(postId);
@ -708,8 +709,8 @@ export function getReactionsForPost(postId: string) {
};
}
export function flagPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function flagPost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const {currentUserId} = getState().entities.users;
const preference = {
user_id: currentUserId,
@ -758,8 +759,8 @@ async function getPaginatedPostThread(rootId: string, options: FetchPaginatedThr
return list;
}
export function getPostThread(rootId: string, fetchThreads = true) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPostThread(rootId: string, fetchThreads = true): NewActionFuncAsync<PostList> {
return async (dispatch, getState) => {
dispatch({type: PostTypes.GET_POST_THREAD_REQUEST});
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(getState());
@ -786,10 +787,10 @@ export function getPostThread(rootId: string, fetchThreads = true) {
};
}
export function getNewestPostThread(rootId: string) {
export function getNewestPostThread(rootId: string): NewActionFuncAsync {
const getPostsForThread = PostSelectors.makeGetPostsForThread();
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
return async (dispatch, getState) => {
dispatch({type: PostTypes.GET_POST_THREAD_REQUEST});
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(getState());
const savedPosts = getPostsForThread(getState(), rootId);
@ -827,8 +828,8 @@ export function getNewestPostThread(rootId: string) {
};
}
export function getPosts(channelId: string, page = 0, perPage = Posts.POST_CHUNK_SIZE, fetchThreads = true, collapsedThreadsExtended = false) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPosts(channelId: string, page = 0, perPage = Posts.POST_CHUNK_SIZE, fetchThreads = true, collapsedThreadsExtended = false): NewActionFuncAsync<PostList> {
return async (dispatch, getState) => {
let posts;
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(getState());
try {
@ -849,8 +850,8 @@ export function getPosts(channelId: string, page = 0, perPage = Posts.POST_CHUNK
};
}
export function getPostsUnread(channelId: string, fetchThreads = true, collapsedThreadsExtended = false) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPostsUnread(channelId: string, fetchThreads = true, collapsedThreadsExtended = false): NewActionFuncAsync<PostList> {
return async (dispatch, getState) => {
const shouldLoadRecent = getUnreadScrollPositionPreference(getState()) === Preferences.UNREAD_SCROLL_POSITION_START_FROM_NEWEST;
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(getState());
const userId = getCurrentUserId(getState());
@ -890,8 +891,8 @@ export function getPostsUnread(channelId: string, fetchThreads = true, collapsed
};
}
export function getPostsSince(channelId: string, since: number, fetchThreads = true, collapsedThreadsExtended = false) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPostsSince(channelId: string, since: number, fetchThreads = true, collapsedThreadsExtended = false): NewActionFuncAsync<PostList> {
return async (dispatch, getState) => {
let posts;
try {
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(getState());
@ -915,8 +916,8 @@ export function getPostsSince(channelId: string, since: number, fetchThreads = t
};
}
export function getPostsBefore(channelId: string, postId: string, page = 0, perPage = Posts.POST_CHUNK_SIZE, fetchThreads = true, collapsedThreadsExtended = false) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPostsBefore(channelId: string, postId: string, page = 0, perPage = Posts.POST_CHUNK_SIZE, fetchThreads = true, collapsedThreadsExtended = false): NewActionFuncAsync<PostList> {
return async (dispatch, getState) => {
let posts;
try {
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(getState());
@ -937,8 +938,8 @@ export function getPostsBefore(channelId: string, postId: string, page = 0, perP
};
}
export function getPostsAfter(channelId: string, postId: string, page = 0, perPage = Posts.POST_CHUNK_SIZE, fetchThreads = true, collapsedThreadsExtended = false) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPostsAfter(channelId: string, postId: string, page = 0, perPage = Posts.POST_CHUNK_SIZE, fetchThreads = true, collapsedThreadsExtended = false): NewActionFuncAsync<PostList> {
return async (dispatch, getState) => {
let posts;
try {
const collapsedThreadsEnabled = isCollapsedThreadsEnabled(getState());
@ -959,8 +960,8 @@ export function getPostsAfter(channelId: string, postId: string, page = 0, perPa
};
}
export function getPostsAround(channelId: string, postId: string, perPage = Posts.POST_CHUNK_SIZE / 2, fetchThreads = true, collapsedThreadsExtended = false) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPostsAround(channelId: string, postId: string, perPage = Posts.POST_CHUNK_SIZE / 2, fetchThreads = true, collapsedThreadsExtended = false): NewActionFuncAsync<PostList> {
return async (dispatch, getState) => {
let after;
let thread;
let before;
@ -1008,9 +1009,9 @@ export function getPostsAround(channelId: string, postId: string, perPage = Post
// getThreadsForPosts is intended for an array of posts that have been batched
// (see the actions/websocket_actions/handleNewPostEvents function in the webapp)
export function getThreadsForPosts(posts: Post[], fetchThreads = true) {
export function getThreadsForPosts(posts: Post[], fetchThreads = true): ThunkActionFunc<unknown> {
const rootsSet = new Set<string>();
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
return (dispatch, getState) => {
if (!Array.isArray(posts) || !posts.length) {
return {data: true};
}
@ -1138,8 +1139,8 @@ export async function getMentionsAndStatusesForPosts(postsArrayOrMap: Post[]|Pos
return Promise.all(promises);
}
export function getPostsByIds(ids: string[]) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getPostsByIds(ids: string[]): NewActionFuncAsync {
return async (dispatch, getState) => {
let posts;
try {
@ -1250,19 +1251,15 @@ export function removePost(post: ExtendedPost): NewActionFunc<boolean> {
};
}
export function selectPost(postId: string) {
return async (dispatch: DispatchFunc) => {
dispatch({
type: PostTypes.RECEIVED_POST_SELECTED,
data: postId,
});
return {data: true};
export function selectPost(postId: string) { // HARRISONTODO unused
return {
type: PostTypes.RECEIVED_POST_SELECTED,
data: postId,
};
}
export function moveThread(postId: string, channelId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function moveThread(postId: string, channelId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
try {
await Client4.moveThread(postId, channelId);
} catch (error) {
@ -1285,8 +1282,8 @@ export function selectFocusedPostId(postId: string) {
};
}
export function unflagPost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function unflagPost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const {currentUserId} = getState().entities.users;
const preference = {
user_id: currentUserId,
@ -1300,8 +1297,8 @@ export function unflagPost(postId: string) {
};
}
export function addPostReminder(userId: string, postId: string, timestamp: number) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function addPostReminder(userId: string, postId: string, timestamp: number): NewActionFuncAsync {
return async (dispatch, getState) => {
try {
await Client4.addPostReminder(userId, postId, timestamp);
} catch (error) {
@ -1317,8 +1314,8 @@ export function doPostAction(postId: string, actionId: string, selectedOption =
return doPostActionWithCookie(postId, actionId, '', selectedOption);
}
export function doPostActionWithCookie(postId: string, actionId: string, actionCookie: string, selectedOption = '') {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function doPostActionWithCookie(postId: string, actionId: string, actionCookie: string, selectedOption = ''): NewActionFuncAsync {
return async (dispatch, getState) => {
let data;
try {
data = await Client4.doPostActionWithCookie(postId, actionId, actionCookie, selectedOption);
@ -1340,29 +1337,21 @@ export function doPostActionWithCookie(postId: string, actionId: string, actionC
}
export function addMessageIntoHistory(message: string) {
return async (dispatch: DispatchFunc) => {
dispatch({
type: PostTypes.ADD_MESSAGE_INTO_HISTORY,
data: message,
});
return {data: true};
return {
type: PostTypes.ADD_MESSAGE_INTO_HISTORY,
data: message,
};
}
export function resetHistoryIndex(index: string) {
return async (dispatch: DispatchFunc) => {
dispatch({
type: PostTypes.RESET_HISTORY_INDEX,
data: index,
});
return {data: true};
return {
type: PostTypes.RESET_HISTORY_INDEX,
data: index,
};
}
export function moveHistoryIndexBack(index: string) {
return async (dispatch: DispatchFunc) => {
export function moveHistoryIndexBack(index: string): NewActionFuncAsync {
return async (dispatch) => {
dispatch({
type: PostTypes.MOVE_HISTORY_INDEX_BACK,
data: index,
@ -1372,8 +1361,8 @@ export function moveHistoryIndexBack(index: string) {
};
}
export function moveHistoryIndexForward(index: string) {
return async (dispatch: DispatchFunc) => {
export function moveHistoryIndexForward(index: string): NewActionFuncAsync {
return async (dispatch) => {
dispatch({
type: PostTypes.MOVE_HISTORY_INDEX_FORWARD,
data: index,
@ -1386,8 +1375,8 @@ export function moveHistoryIndexForward(index: string) {
/**
* Ensures thread-replies in channels correctly follow CRT:ON/OFF
*/
export function resetReloadPostsInChannel() {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function resetReloadPostsInChannel(): NewActionFuncAsync {
return async (dispatch, getState) => {
dispatch({
type: PostTypes.RESET_POSTS_IN_CHANNEL,
});
@ -1403,8 +1392,8 @@ export function resetReloadPostsInChannel() {
};
}
export function acknowledgePost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function acknowledgePost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const userId = getCurrentUserId(getState());
let data;
@ -1425,8 +1414,8 @@ export function acknowledgePost(postId: string) {
};
}
export function unacknowledgePost(postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function unacknowledgePost(postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const userId = getCurrentUserId(getState());
try {

View File

@ -6,7 +6,7 @@ import type {Role} from '@mattermost/types/roles';
import {RoleTypes} from 'mattermost-redux/action_types';
import {Client4} from 'mattermost-redux/client';
import {getRoles} from 'mattermost-redux/selectors/entities/roles_helpers';
import type {DispatchFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync} from 'mattermost-redux/types/actions';
import {bindClientFunc} from './helpers';
@ -62,9 +62,9 @@ export function editRole(role: Partial<Role> & {id: string}) {
}
export function setPendingRoles(roles: string[]) {
return async (dispatch: DispatchFunc) => {
dispatch({type: RoleTypes.SET_PENDING_ROLES, data: roles});
return {data: roles};
return {
type: RoleTypes.SET_PENDING_ROLES,
data: roles,
};
}

View File

@ -18,7 +18,7 @@ import {isCollapsedThreadsEnabled} from 'mattermost-redux/selectors/entities/pre
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
import {getThread as getThreadSelector, getThreadItemsInChannel} from 'mattermost-redux/selectors/entities/threads';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {DispatchFunc, GetStateFunc, NewActionFunc, NewActionFuncAsync} from 'mattermost-redux/types/actions';
import {logError} from './errors';
import {forceLogoutIfNecessary} from './helpers';
@ -26,8 +26,8 @@ import {getPostThread} from './posts';
type ExtendedPost = Post & { system_post_ids?: string[] };
export function fetchThreads(userId: string, teamId: string, {before = '', after = '', perPage = ThreadConstants.THREADS_CHUNK_SIZE, unread = false, totalsOnly = false, threadsOnly = false, extended = false, since = 0} = {}) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function fetchThreads(userId: string, teamId: string, {before = '', after = '', perPage = ThreadConstants.THREADS_CHUNK_SIZE, unread = false, totalsOnly = false, threadsOnly = false, extended = false, since = 0} = {}): NewActionFuncAsync<UserThreadList> {
return async (dispatch, getState) => {
let data: undefined | UserThreadList;
try {
@ -42,8 +42,8 @@ export function fetchThreads(userId: string, teamId: string, {before = '', after
};
}
export function getThreads(userId: string, teamId: string, {before = '', after = '', perPage = ThreadConstants.THREADS_CHUNK_SIZE, unread = false, extended = true} = {}) {
return async (dispatch: DispatchFunc) => {
export function getThreads(userId: string, teamId: string, {before = '', after = '', perPage = ThreadConstants.THREADS_CHUNK_SIZE, unread = false, extended = true} = {}): NewActionFuncAsync<UserThreadList> {
return async (dispatch) => {
const response = await dispatch(fetchThreads(userId, teamId, {before, after, perPage, unread, totalsOnly: false, threadsOnly: true, extended}));
if (response.error) {
@ -79,8 +79,8 @@ export function getThreads(userId: string, teamId: string, {before = '', after =
};
}
export function getThreadCounts(userId: string, teamId: string) {
return async (dispatch: DispatchFunc) => {
export function getThreadCounts(userId: string, teamId: string): NewActionFuncAsync {
return async (dispatch) => {
const response = await dispatch(fetchThreads(userId, teamId, {totalsOnly: true, threadsOnly: false}));
if (response.error) {
@ -111,8 +111,8 @@ export function getThreadCounts(userId: string, teamId: string) {
};
}
export function getCountsAndThreadsSince(userId: string, teamId: string, since?: number) {
return async (dispatch: DispatchFunc) => {
export function getCountsAndThreadsSince(userId: string, teamId: string, since?: number): NewActionFuncAsync {
return async (dispatch) => {
const response = await dispatch(fetchThreads(userId, teamId, {since, totalsOnly: false, threadsOnly: false, extended: true}));
if (response.error) {
@ -218,8 +218,8 @@ export function handleThreadArrived(dispatch: DispatchFunc, getState: GetStateFu
return thread;
}
export function getThread(userId: string, teamId: string, threadId: string, extended = true) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function getThread(userId: string, teamId: string, threadId: string, extended = true): NewActionFuncAsync {
return async (dispatch, getState) => {
let thread;
try {
thread = await Client4.getUserThread(userId, teamId, threadId, extended);
@ -246,8 +246,8 @@ export function handleAllMarkedRead(dispatch: DispatchFunc, teamId: string) {
});
}
export function markAllThreadsInTeamRead(userId: string, teamId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function markAllThreadsInTeamRead(userId: string, teamId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
try {
await Client4.updateThreadsReadForUser(userId, teamId);
} catch (error) {
@ -262,8 +262,8 @@ export function markAllThreadsInTeamRead(userId: string, teamId: string) {
};
}
export function markThreadAsUnread(userId: string, teamId: string, threadId: string, postId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function markThreadAsUnread(userId: string, teamId: string, threadId: string, postId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
try {
await Client4.markThreadAsUnreadForUser(userId, teamId, threadId, postId);
} catch (error) {
@ -276,8 +276,8 @@ export function markThreadAsUnread(userId: string, teamId: string, threadId: str
};
}
export function markLastPostInThreadAsUnread(userId: string, teamId: string, threadId: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function markLastPostInThreadAsUnread(userId: string, teamId: string, threadId: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const getPostsForThread = makeGetPostsForThread();
let posts = getPostsForThread(getState(), threadId);
@ -303,8 +303,8 @@ export function markLastPostInThreadAsUnread(userId: string, teamId: string, thr
};
}
export function updateThreadRead(userId: string, teamId: string, threadId: string, timestamp: number) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function updateThreadRead(userId: string, teamId: string, threadId: string, timestamp: number): NewActionFuncAsync {
return async (dispatch, getState) => {
try {
await Client4.updateThreadReadForUser(userId, teamId, threadId, timestamp);
} catch (error) {
@ -334,8 +334,8 @@ export function handleReadChanged(
prevUnreadReplies: number;
newUnreadReplies: number;
},
) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
): NewActionFunc {
return (dispatch, getState) => {
const state = getState();
const channel = getChannel(state, channelId);
const thread = getThreadSelector(state, threadId);
@ -369,8 +369,8 @@ export function handleFollowChanged(dispatch: DispatchFunc, threadId: string, te
});
}
export function setThreadFollow(userId: string, teamId: string, threadId: string, newState: boolean) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function setThreadFollow(userId: string, teamId: string, threadId: string, newState: boolean): NewActionFuncAsync {
return async (dispatch, getState) => {
handleFollowChanged(dispatch, threadId, teamId, newState);
try {
@ -412,8 +412,8 @@ export function handleAllThreadsInChannelMarkedRead(dispatch: DispatchFunc, getS
dispatch(batchActions(actions));
}
export function decrementThreadCounts(post: ExtendedPost) {
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function decrementThreadCounts(post: ExtendedPost): NewActionFunc {
return (dispatch, getState) => {
const state = getState();
const thread = getThreadSelector(state, post.id);
@ -424,12 +424,13 @@ export function decrementThreadCounts(post: ExtendedPost) {
const channel = getChannel(state, post.channel_id);
const teamId = channel?.team_id || getCurrentTeamId(state);
return dispatch({
dispatch({
type: ThreadTypes.DECREMENT_THREAD_COUNTS,
teamId,
replies: thread.unread_replies,
mentions: thread.unread_mentions,
channelType: channel.type,
});
return {data: true};
};
}

View File

@ -3,12 +3,12 @@
import {getCurrentTimezoneFull} from 'mattermost-redux/selectors/entities/timezone';
import {getCurrentUser} from 'mattermost-redux/selectors/entities/users';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync} from 'mattermost-redux/types/actions';
import {updateMe} from './users';
export function autoUpdateTimezone(deviceTimezone: string) {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
export function autoUpdateTimezone(deviceTimezone: string): NewActionFuncAsync {
return async (dispatch, getState) => {
const currentUser = getCurrentUser(getState());
const currentTimezone = getCurrentTimezoneFull(getState());
const newTimezoneExists = currentTimezone.automaticTimezone !== deviceTimezone;

View File

@ -292,7 +292,7 @@ export function getProfilesNotInTeam(teamId: string, groupConstrained: boolean,
};
}
export function getProfilesWithoutTeam(page: number, perPage: number = General.PROFILE_CHUNK_SIZE, options: any = {}): NewActionFuncAsync {
export function getProfilesWithoutTeam(page: number, perPage: number = General.PROFILE_CHUNK_SIZE, options: any = {}): NewActionFuncAsync<UserProfile[]> {
return async (dispatch, getState) => {
let profiles = null;
try {

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type {Action as ReduxAction, AnyAction} from 'redux';
import type {Action as ReduxAction, AnyAction, Dispatch} from 'redux';
import type {ThunkAction as BaseThunkAction} from 'redux-thunk';
import type {GlobalState} from '@mattermost/types/store';
@ -14,6 +14,7 @@ import type {GlobalState} from '@mattermost/types/store';
*/
import 'redux-thunk/extend-redux';
export type DispatchFunc = Dispatch;
export type GetStateFunc = () => GlobalState;
export type GenericAction = AnyAction;
@ -25,8 +26,6 @@ export type ActionResult<Data = any, Error = any> = {
error?: Error;
};
export type DispatchFunc = (action: AnyAction | NewActionFunc<unknown, any> | NewActionFuncAsync<unknown, any> | ThunkActionFunc<any>, getState?: GetStateFunc | null) => Promise<ActionResult>;
/**
* NewActionFunc should be the return type of most non-async Thunk action creators. If that action requires web app
* state, the second type parameter should be used to pass the version of GlobalState from 'types/store'.

View File

@ -3,7 +3,7 @@
import type {Store} from 'redux';
import type {DispatchFunc, GetStateFunc} from 'mattermost-redux/types/actions';
import type {NewActionFuncAsync, ThunkActionFunc} from 'mattermost-redux/types/actions';
import store from 'stores/redux_store';
@ -14,8 +14,8 @@ export abstract class ProductPlugin {
abstract uninitialize(): void;
}
export function initializeProducts() {
return (dispatch: DispatchFunc) => {
export function initializeProducts(): ThunkActionFunc<Promise<unknown>> {
return (dispatch) => {
return Promise.all([
dispatch(loadRemoteModules()),
dispatch(configureClient()),
@ -23,16 +23,16 @@ export function initializeProducts() {
};
}
function configureClient() {
function configureClient(): NewActionFuncAsync {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return (dispatch: DispatchFunc, getState: GetStateFunc) => {
return (dispatch, getState) => {
return Promise.resolve({data: true});
};
}
function loadRemoteModules() {
function loadRemoteModules(): NewActionFuncAsync {
/* eslint-disable no-console */
return async (/*dispatch: DispatchFunc, getState: GetStateFunc*/) => {
return async (/*dispatch, getState*/) => {
// const config = getConfig(getState());
/**