[MM-34746] Fix ephemeral error message response (#5304) (#5360)

* fix ephemeral error message response

* extract helpers for posting call responses

(cherry picked from commit 3eaa538707)

Co-authored-by: Michael Kochell <6913320+mickmister@users.noreply.github.com>
This commit is contained in:
Mattermost Build 2021-04-29 17:26:51 +02:00 committed by GitHub
parent 3f9a941aa1
commit a5297c328c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 149 additions and 89 deletions

View file

@ -2,8 +2,11 @@
// See LICENSE.txt for license information.
import {Client4} from '@client/rest';
import {ActionFunc} from '@mm-redux/types/actions';
import {AppCallResponse, AppForm, AppCallRequest, AppCallType} from '@mm-redux/types/apps';
import {ActionFunc, DispatchFunc} from '@mm-redux/types/actions';
import {AppCallResponse, AppForm, AppCallRequest, AppCallType, AppContext} from '@mm-redux/types/apps';
import {Post} from '@mm-redux/types/posts';
import {AppCallTypes, AppCallResponseTypes} from '@mm-redux/constants/apps';
import {handleGotoLocation} from '@mm-redux/actions/integrations';
import {showModal} from './navigation';
@ -12,6 +15,8 @@ import CompassIcon from '@components/compass_icon';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import EphemeralStore from '@store/ephemeral_store';
import {makeCallErrorResponse} from '@utils/apps';
import {sendEphemeralPost} from '@actions/views/post';
import {CommandArgs} from '@mm-redux/types/integrations';
export function doAppCall<Res=unknown>(call: AppCallRequest, type: AppCallType, intl: any): ActionFunc {
return async (dispatch, getState) => {
@ -114,3 +119,47 @@ const showAppForm = async (form: AppForm, call: AppCallRequest, theme: Theme) =>
const passProps = {form, call};
showModal('AppForm', form.title, passProps, options);
};
export function postEphemeralCallResponseForPost(response: AppCallResponse, message: string, post: Post): ActionFunc {
return (dispatch: DispatchFunc) => {
return dispatch(sendEphemeralPost(
message,
post.channel_id,
post.root_id || post.id,
response.app_metadata?.bot_user_id,
));
};
}
export function postEphemeralCallResponseForChannel(response: AppCallResponse, message: string, channelID: string): ActionFunc {
return (dispatch: DispatchFunc) => {
return dispatch(sendEphemeralPost(
message,
channelID,
'',
response.app_metadata?.bot_user_id,
));
};
}
export function postEphemeralCallResponseForContext(response: AppCallResponse, message: string, context: AppContext): ActionFunc {
return (dispatch: DispatchFunc) => {
return dispatch(sendEphemeralPost(
message,
context.channel_id,
context.root_id || context.post_id,
response.app_metadata?.bot_user_id,
));
};
}
export function postEphemeralCallResponseForCommandArgs(response: AppCallResponse, message: string, args: CommandArgs): ActionFunc {
return (dispatch: DispatchFunc) => {
return dispatch(sendEphemeralPost(
message,
args.channel_id,
args.root_id,
response.app_metadata?.bot_user_id,
));
};
}

View file

@ -8,13 +8,13 @@ import {executeCommand as executeCommandService} from '@mm-redux/actions/integra
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
import {AppCallResponseTypes, AppCallTypes} from '@mm-redux/constants/apps';
import {DispatchFunc, GetStateFunc, ActionFunc} from '@mm-redux/types/actions';
import {CommandArgs} from '@mm-redux/types/integrations';
import {AppCommandParser} from '@components/autocomplete/slash_suggestion/app_command_parser/app_command_parser';
import {doAppCall} from '@actions/apps';
import {doAppCall, postEphemeralCallResponseForCommandArgs} from '@actions/apps';
import {appsEnabled} from '@utils/apps';
import {AppCallResponse} from '@mm-redux/types/apps';
import {sendEphemeralPost} from './post';
export function executeCommand(message: string, channelId: string, rootId: string, intl: typeof intlShape): ActionFunc {
return async (dispatch: DispatchFunc, getState: GetStateFunc) => {
@ -22,7 +22,7 @@ export function executeCommand(message: string, channelId: string, rootId: strin
const teamId = getCurrentTeamId(state);
const args = {
const args: CommandArgs = {
channel_id: channelId,
team_id: teamId,
root_id: rootId,
@ -65,7 +65,7 @@ export function executeCommand(message: string, channelId: string, rootId: strin
switch (callResp.type) {
case AppCallResponseTypes.OK:
if (callResp.markdown) {
dispatch(sendEphemeralPost(callResp.markdown, args.channel_id, args.parent_id, callResp.app_metadata?.bot_user_id));
dispatch(postEphemeralCallResponseForCommandArgs(callResp, callResp.markdown, args));
}
return {data: {}};
case AppCallResponseTypes.FORM:

View file

@ -49,7 +49,6 @@ export {getUserByUsername as selectUserByUsername} from '@mm-redux/selectors/ent
export {getUserByUsername} from '@mm-redux/actions/users';
export {getChannelByNameAndTeamName} from '@mm-redux/actions/channels';
export {sendEphemeralPost} from '@actions/views/post';
export {doAppCall} from '@actions/apps';
export {createCallRequest} from '@utils/apps';

View file

@ -11,18 +11,18 @@ import {getStatusColors} from '@utils/message_attachment_colors';
import ButtonBindingText from './button_binding_text';
import {Theme} from '@mm-redux/types/preferences';
import {ActionResult} from '@mm-redux/types/actions';
import {AppBinding, AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps';
import {AppBinding} from '@mm-redux/types/apps';
import {Post} from '@mm-redux/types/posts';
import {DoAppCall, PostEphemeralCallResponseForPost} from 'types/actions/apps';
import {AppExpandLevels, AppBindingLocations, AppCallTypes, AppCallResponseTypes} from '@mm-redux/constants/apps';
import {createCallContext, createCallRequest} from '@utils/apps';
import {Channel} from '@mm-redux/types/channels';
import {SendEphemeralPost} from 'types/actions/posts';
type Props = {
actions: {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
doAppCall: DoAppCall;
getChannel: (channelId: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
postEphemeralCallResponseForPost: PostEphemeralCallResponseForPost;
};
post: Post;
binding: AppBinding;
@ -72,14 +72,13 @@ export default class ButtonBinding extends PureComponent<Props> {
this.setState({executing: false});
}
const ephemeral = (message: string) => this.props.actions.sendEphemeralPost(message, this.props.post.channel_id, this.props.post.root_id, res.data?.app_metadata?.bot_user_id);
if (res.error) {
const errorResponse = res.error;
const errorMessage = errorResponse.error || intl.formatMessage(
{id: 'apps.error.unknown',
defaultMessage: 'Unknown error occurred.',
});
ephemeral(errorMessage);
this.props.actions.postEphemeralCallResponseForPost(errorResponse, errorMessage, post);
return;
}
@ -88,7 +87,7 @@ export default class ButtonBinding extends PureComponent<Props> {
switch (callResp.type) {
case AppCallResponseTypes.OK:
if (callResp.markdown) {
ephemeral(callResp.markdown);
this.props.actions.postEphemeralCallResponseForPost(callResp, callResp.markdown, post);
}
return;
case AppCallResponseTypes.NAVIGATE:
@ -104,7 +103,7 @@ export default class ButtonBinding extends PureComponent<Props> {
type: callResp.type,
},
);
ephemeral(errorMessage);
this.props.actions.postEphemeralCallResponseForPost(callResp, errorMessage, post);
}
}
}, 4000);

View file

@ -8,15 +8,13 @@ import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {GlobalState} from '@mm-redux/types/store';
import {ActionFunc, ActionResult, GenericAction} from '@mm-redux/types/actions';
import {AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps';
import {doAppCall} from '@actions/apps';
import {DoAppCall, PostEphemeralCallResponseForPost} from 'types/actions/apps';
import {doAppCall, postEphemeralCallResponseForPost} from '@actions/apps';
import {getPost} from '@mm-redux/selectors/entities/posts';
import ButtonBinding from './button_binding';
import {getChannel} from '@mm-redux/actions/channels';
import {sendEphemeralPost} from '@actions/views/post';
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
import {SendEphemeralPost} from 'types/actions/posts';
type OwnProps = {
postId: string;
@ -31,9 +29,9 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
}
type Actions = {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
doAppCall: DoAppCall;
getChannel: (channelId: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
postEphemeralCallResponseForPost: PostEphemeralCallResponseForPost;
}
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
@ -41,7 +39,7 @@ function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
actions: bindActionCreators<ActionCreatorsMapObject<ActionFunc>, Actions>({
doAppCall,
getChannel,
sendEphemeralPost,
postEphemeralCallResponseForPost,
}, dispatch),
};
}

View file

@ -5,16 +5,14 @@ import {ActionCreatorsMapObject, bindActionCreators, Dispatch} from 'redux';
import {connect} from 'react-redux';
import {GlobalState} from '@mm-redux/types/store';
import {doAppCall} from '@actions/apps';
import {ActionFunc, ActionResult, GenericAction} from '@mm-redux/types/actions';
import {AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps';
import {SendEphemeralPost} from 'types/actions/posts';
import {DoAppCall, PostEphemeralCallResponseForPost} from 'types/actions/apps';
import {getPost} from '@mm-redux/selectors/entities/posts';
import MenuBinding from './menu_binding';
import {getChannel} from '@mm-redux/actions/channels';
import {sendEphemeralPost} from '@actions/views/post';
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
import {doAppCall, postEphemeralCallResponseForPost} from '@actions/apps';
type OwnProps = {
postId: string;
@ -28,9 +26,9 @@ function mapStateToProps(state: GlobalState, ownProps: OwnProps) {
}
type Actions = {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
doAppCall: DoAppCall;
getChannel: (channelId: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
postEphemeralCallResponseForPost: PostEphemeralCallResponseForPost;
}
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
@ -38,7 +36,7 @@ function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
actions: bindActionCreators<ActionCreatorsMapObject<ActionFunc>, Actions>({
doAppCall,
getChannel,
sendEphemeralPost,
postEphemeralCallResponseForPost,
}, dispatch),
};
}

View file

@ -7,18 +7,18 @@ import AutocompleteSelector from 'app/components/autocomplete_selector';
import {intlShape} from 'react-intl';
import {PostActionOption} from '@mm-redux/types/integration_actions';
import {Post} from '@mm-redux/types/posts';
import {AppBinding, AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps';
import {AppBinding} from '@mm-redux/types/apps';
import {ActionResult} from '@mm-redux/types/actions';
import {DoAppCall, PostEphemeralCallResponseForPost} from 'types/actions/apps';
import {AppExpandLevels, AppBindingLocations, AppCallTypes, AppCallResponseTypes} from '@mm-redux/constants/apps';
import {Channel} from '@mm-redux/types/channels';
import {createCallContext, createCallRequest} from '@utils/apps';
import {SendEphemeralPost} from 'types/actions/posts';
type Props = {
actions: {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
doAppCall: DoAppCall;
getChannel: (channelId: string) => Promise<ActionResult>;
sendEphemeralPost: SendEphemeralPost;
postEphemeralCallResponseForPost: PostEphemeralCallResponseForPost;
};
binding?: AppBinding;
post: Post;
@ -82,16 +82,14 @@ export default class MenuBinding extends PureComponent<Props, State> {
{post: AppExpandLevels.EXPAND_ALL},
);
const res = await actions.doAppCall(call, AppCallTypes.SUBMIT, this.context.intl);
const ephemeral = (message: string) => this.props.actions.sendEphemeralPost(message, this.props.post.channel_id, this.props.post.root_id, res.data?.app_metadata?.bot_user_id);
const res = await actions.doAppCall(call, AppCallTypes.SUBMIT, intl);
if (res.error) {
const errorResponse = res.error;
const errorMessage = errorResponse.error || intl.formatMessage({
id: 'apps.error.unknown',
defaultMessage: 'Unknown error occurred.',
});
ephemeral(errorMessage);
this.props.actions.postEphemeralCallResponseForPost(res.error, errorMessage, post);
return;
}
@ -99,7 +97,7 @@ export default class MenuBinding extends PureComponent<Props, State> {
switch (callResp.type) {
case AppCallResponseTypes.OK:
if (callResp.markdown) {
ephemeral(callResp.markdown);
this.props.actions.postEphemeralCallResponseForPost(callResp, callResp.markdown, post);
}
return;
case AppCallResponseTypes.NAVIGATE:
@ -112,7 +110,7 @@ export default class MenuBinding extends PureComponent<Props, State> {
}, {
type: callResp.type,
});
ephemeral(errorMessage);
this.props.actions.postEphemeralCallResponseForPost(callResp, errorMessage, post);
}
}
};

View file

@ -18,11 +18,12 @@ import {dismissModal} from 'app/actions/navigation';
import DialogIntroductionText from './dialog_introduction_text';
import {Theme} from '@mm-redux/types/preferences';
import {AppCallRequest, AppCallResponse, AppField, AppForm, AppFormValue, AppFormValues, AppLookupResponse, AppSelectOption, FormResponseData} from '@mm-redux/types/apps';
import {AppCallRequest, AppField, AppForm, AppFormValue, AppFormValues, AppLookupResponse, AppSelectOption, FormResponseData} from '@mm-redux/types/apps';
import {DialogElement} from '@mm-redux/types/integrations';
import {AppCallResponseTypes} from '@mm-redux/constants/apps';
import AppsFormField from './apps_form_field';
import {preventDoubleTap} from '@utils/tap';
import {DoAppCallResult} from 'types/actions/apps';
export type Props = {
call: AppCallRequest;
@ -32,9 +33,9 @@ export type Props = {
values: {
[name: string]: string;
};
}) => Promise<{data?: AppCallResponse<FormResponseData>, error?: AppCallResponse<FormResponseData>}>;
performLookupCall: (field: AppField, values: AppFormValues, userInput: string) => Promise<{data?: AppCallResponse<AppLookupResponse>, error?: AppCallResponse<AppLookupResponse>}>;
refreshOnSelect: (field: AppField, values: AppFormValues, value: AppFormValue) => Promise<{data?: AppCallResponse<FormResponseData>, error?: AppCallResponse<FormResponseData>}>;
}) => Promise<DoAppCallResult<FormResponseData>>;
performLookupCall: (field: AppField, values: AppFormValues, userInput: string) => Promise<DoAppCallResult<AppLookupResponse>>;
refreshOnSelect: (field: AppField, values: AppFormValues, value: AppFormValue) => Promise<DoAppCallResult<FormResponseData>>;
};
theme: Theme;
componentId: string;

View file

@ -5,18 +5,18 @@ import React, {PureComponent} from 'react';
import {intlShape} from 'react-intl';
import {Theme} from '@mm-redux/types/preferences';
import {AppCallResponse, AppCallRequest, AppField, AppForm, AppFormValues, FormResponseData, AppCallType, AppLookupResponse} from '@mm-redux/types/apps';
import {AppCallResponse, AppCallRequest, AppField, AppForm, AppFormValues, FormResponseData, AppLookupResponse} from '@mm-redux/types/apps';
import {AppCallResponseTypes, AppCallTypes} from '@mm-redux/constants/apps';
import AppsFormComponent from './apps_form_component';
import {makeCallErrorResponse} from '@utils/apps';
import {SendEphemeralPost} from 'types/actions/posts';
import {DoAppCall, DoAppCallResult, PostEphemeralCallResponseForContext} from 'types/actions/apps';
export type Props = {
form?: AppForm;
call?: AppCallRequest;
actions: {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse<any>, error?: AppCallResponse<any>}>;
sendEphemeralPost: SendEphemeralPost;
doAppCall: DoAppCall<any>;
postEphemeralCallResponseForContext: PostEphemeralCallResponseForContext;
};
theme: Theme;
componentId: string;
@ -81,7 +81,7 @@ export default class AppsFormContainer extends PureComponent<Props, State> {
switch (callResp.type) {
case AppCallResponseTypes.OK:
if (callResp.markdown) {
this.props.actions.sendEphemeralPost(callResp.markdown, call.context.channel_id, call.context.root_id || call.context.post_id, callResp.app_metadata?.bot_user_id);
this.props.actions.postEphemeralCallResponseForContext(callResp, callResp.markdown, call.context);
}
break;
case AppCallResponseTypes.FORM:
@ -102,7 +102,7 @@ export default class AppsFormContainer extends PureComponent<Props, State> {
return res;
}
refreshOnSelect = async (field: AppField, values: AppFormValues): Promise<{data?: AppCallResponse<FormResponseData>, error?: AppCallResponse<FormResponseData>}> => {
refreshOnSelect = async (field: AppField, values: AppFormValues): Promise<DoAppCallResult<FormResponseData>> => {
const intl = this.context.intl;
const makeErrorMsg = (message: string) => intl.formatMessage(
{
@ -171,7 +171,7 @@ export default class AppsFormContainer extends PureComponent<Props, State> {
return res;
};
performLookupCall = async (field: AppField, values: AppFormValues, userInput: string): Promise<{data?: AppCallResponse<AppLookupResponse>, error?: AppCallResponse<AppLookupResponse>}> => {
performLookupCall = async (field: AppField, values: AppFormValues, userInput: string): Promise<DoAppCallResult<AppLookupResponse>> => {
const intl = this.context.intl;
const makeErrorMsg = (message: string) => intl.formatMessage(
{

View file

@ -5,19 +5,17 @@ import {ActionCreatorsMapObject, bindActionCreators, Dispatch} from 'redux';
import {connect} from 'react-redux';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {doAppCall} from '@actions/apps';
import {doAppCall, postEphemeralCallResponseForContext} from '@actions/apps';
import {AppCallResponse, AppCallRequest, AppCallType} from '@mm-redux/types/apps';
import {GlobalState} from '@mm-redux/types/store';
import {ActionFunc, GenericAction} from '@mm-redux/types/actions';
import {SendEphemeralPost} from 'types/actions/posts';
import AppsFormContainer from './apps_form_container';
import {sendEphemeralPost} from '@actions/views/post';
import {DoAppCall, PostEphemeralCallResponseForContext} from 'types/actions/apps';
type Actions = {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
sendEphemeralPost: SendEphemeralPost;
doAppCall: DoAppCall;
postEphemeralCallResponseForContext: PostEphemeralCallResponseForContext;
};
function mapStateToProps(state: GlobalState) {
@ -30,7 +28,7 @@ function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
return {
actions: bindActionCreators<ActionCreatorsMapObject<ActionFunc>, Actions>({
doAppCall,
sendEphemeralPost,
postEphemeralCallResponseForContext,
}, dispatch),
};
}

View file

@ -8,13 +8,13 @@ import {intlShape, injectIntl} from 'react-intl';
import Separator from '@screens/channel_info/separator';
import ChannelInfoRow from '../channel_info_row';
import {AppBinding, AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps';
import {AppBinding} from '@mm-redux/types/apps';
import {Theme} from '@mm-redux/types/preferences';
import {Channel} from '@mm-redux/types/channels';
import {AppCallResponseTypes, AppCallTypes} from '@mm-redux/constants/apps';
import {dismissModal} from '@actions/navigation';
import {createCallContext, createCallRequest} from '@utils/apps';
import {SendEphemeralPost} from 'types/actions/posts';
import {DoAppCall, PostEphemeralCallResponseForChannel} from 'types/actions/apps';
type Props = {
bindings: AppBinding[];
@ -24,8 +24,8 @@ type Props = {
intl: typeof intlShape;
currentTeamId: string;
actions: {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
sendEphemeralPost: SendEphemeralPost;
doAppCall: DoAppCall;
postEphemeralCallResponseForChannel: PostEphemeralCallResponseForChannel;
}
}
@ -63,8 +63,8 @@ type OptionProps = {
intl: typeof intlShape;
currentTeamId: string;
actions: {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
sendEphemeralPost: SendEphemeralPost;
doAppCall: DoAppCall;
postEphemeralCallResponseForChannel: PostEphemeralCallResponseForChannel;
},
}
@ -79,7 +79,7 @@ class Option extends React.PureComponent<OptionProps, OptionState> {
onPress = async () => {
const {binding, currentChannel, currentTeamId, intl} = this.props;
const {doAppCall, sendEphemeralPost} = this.props.actions;
const {doAppCall, postEphemeralCallResponseForChannel} = this.props.actions;
if (this.state.submitting) {
return;
@ -121,11 +121,10 @@ class Option extends React.PureComponent<OptionProps, OptionState> {
}
const callResp = res.data!;
const ephemeral = (message: string) => sendEphemeralPost(message, currentChannel.id, '', callResp.app_metadata?.bot_user_id);
switch (callResp.type) {
case AppCallResponseTypes.OK:
if (callResp.markdown) {
ephemeral(callResp.markdown);
postEphemeralCallResponseForChannel(callResp, callResp.markdown, currentChannel.id);
}
break;
case AppCallResponseTypes.NAVIGATE:

View file

@ -9,15 +9,13 @@ import {AppBindingLocations} from '@mm-redux/constants/apps';
import {getCurrentChannel} from '@mm-redux/selectors/entities/channels';
import {GlobalState} from '@mm-redux/types/store';
import {GenericAction, ActionFunc} from '@mm-redux/types/actions';
import {AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps';
import {DoAppCall, PostEphemeralCallResponseForChannel} from 'types/actions/apps';
import {appsEnabled} from '@utils/apps';
import {doAppCall} from '@actions/apps';
import {doAppCall, postEphemeralCallResponseForChannel} from '@actions/apps';
import Bindings from './bindings';
import {sendEphemeralPost} from '@actions/views/post';
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
import {SendEphemeralPost} from 'types/actions/posts';
function mapStateToProps(state: GlobalState) {
const apps = appsEnabled(state);
@ -33,15 +31,15 @@ function mapStateToProps(state: GlobalState) {
}
type Actions = {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
sendEphemeralPost: SendEphemeralPost;
doAppCall: DoAppCall;
postEphemeralCallResponseForChannel: PostEphemeralCallResponseForChannel;
}
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
return {
actions: bindActionCreators<ActionCreatorsMapObject<ActionFunc>, Actions>({
doAppCall,
sendEphemeralPost,
postEphemeralCallResponseForChannel,
}, dispatch),
};
}

View file

@ -8,13 +8,13 @@ import {intlShape, injectIntl} from 'react-intl';
import {isSystemMessage} from '@mm-redux/utils/post_utils';
import PostOption from '../post_option';
import {AppBinding, AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps';
import {AppBinding, AppCallResponse} from '@mm-redux/types/apps';
import {Theme} from '@mm-redux/types/preferences';
import {Post} from '@mm-redux/types/posts';
import {UserProfile} from '@mm-redux/types/users';
import {AppCallResponseTypes, AppCallTypes, AppExpandLevels} from '@mm-redux/constants/apps';
import {createCallContext, createCallRequest} from '@utils/apps';
import {SendEphemeralPost} from 'types/actions/posts';
import {DoAppCall, PostEphemeralCallResponseForPost} from 'types/actions/apps';
type Props = {
bindings: AppBinding[],
@ -26,8 +26,8 @@ type Props = {
appsEnabled: boolean,
intl: typeof intlShape,
actions: {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
sendEphemeralPost: SendEphemeralPost;
doAppCall: DoAppCall;
postEphemeralCallResponseForPost: PostEphemeralCallResponseForPost;
}
}
@ -72,15 +72,15 @@ type OptionProps = {
closeWithAnimation: () => void,
intl: typeof intlShape,
actions: {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
sendEphemeralPost: SendEphemeralPost;
doAppCall: DoAppCall;
postEphemeralCallResponseForPost: PostEphemeralCallResponseForPost;
},
}
class Option extends React.PureComponent<OptionProps> {
onPress = async () => {
const {closeWithAnimation, post, teamID, binding, intl} = this.props;
const {doAppCall, sendEphemeralPost} = this.props.actions;
const {doAppCall, postEphemeralCallResponseForPost} = this.props.actions;
if (!binding.call) {
return;
@ -118,11 +118,10 @@ class Option extends React.PureComponent<OptionProps> {
}
const callResp = (res as {data: AppCallResponse}).data;
const ephemeral = (message: string) => sendEphemeralPost(message, post.channel_id, post.root_id || post.id, callResp.app_metadata?.bot_user_id);
switch (callResp.type) {
case AppCallResponseTypes.OK:
if (callResp.markdown) {
ephemeral(callResp.markdown);
postEphemeralCallResponseForPost(callResp, callResp.markdown, post);
}
break;
case AppCallResponseTypes.NAVIGATE:

View file

@ -7,21 +7,19 @@ import {bindActionCreators, Dispatch, ActionCreatorsMapObject} from 'redux';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {GlobalState} from '@mm-redux/types/store';
import {AppCallRequest, AppCallResponse, AppCallType} from '@mm-redux/types/apps';
import {GenericAction, ActionFunc} from '@mm-redux/types/actions';
import {getAppsBindings} from '@mm-redux/selectors/entities/apps';
import {AppBindingLocations} from '@mm-redux/constants/apps';
import {getCurrentUser} from '@mm-redux/selectors/entities/users';
import {doAppCall} from '@actions/apps';
import {doAppCall, postEphemeralCallResponseForPost} from '@actions/apps';
import {appsEnabled} from '@utils/apps';
import Bindings from './bindings';
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
import {sendEphemeralPost} from '@actions/views/post';
import {Post} from '@mm-redux/types/posts';
import {getChannel} from '@mm-redux/selectors/entities/channels';
import {SendEphemeralPost} from 'types/actions/posts';
import {DoAppCall, PostEphemeralCallResponseForPost} from 'types/actions/apps';
type OwnProps = {
post: Post;
@ -43,15 +41,15 @@ function mapStateToProps(state: GlobalState, props: OwnProps) {
}
type Actions = {
doAppCall: (call: AppCallRequest, type: AppCallType, intl: any) => Promise<{data?: AppCallResponse, error?: AppCallResponse}>;
sendEphemeralPost: SendEphemeralPost;
doAppCall: DoAppCall;
postEphemeralCallResponseForPost: PostEphemeralCallResponseForPost;
}
function mapDispatchToProps(dispatch: Dispatch<GenericAction>) {
return {
actions: bindActionCreators<ActionCreatorsMapObject<ActionFunc>, Actions>({
doAppCall,
sendEphemeralPost,
postEphemeralCallResponseForPost,
}, dispatch),
};
}

26
types/actions/apps.d.ts vendored Normal file
View file

@ -0,0 +1,26 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {AppCallRequest, AppCallResponse, AppCallType, AppContext} from '@mm-redux/types/apps';
import {Post} from '@mm-redux/types/posts';
export type DoAppCallResult<Res=unknown> = {
data?: AppCallResponse<Res>;
error?: AppCallResponse<Res>;
}
export interface DoAppCall<Res=unknown> {
(call: AppCallRequest, type: AppCallType, intl: any): Promise<DoAppCallResult<Res>>;
}
export interface PostEphemeralCallResponseForPost {
(response: AppCallResponse, message: string, post: Post): void;
}
export interface PostEphemeralCallResponseForChannel {
(response: AppCallResponse, message: string, channelID: string): void;
}
export interface PostEphemeralCallResponseForContext {
(response: AppCallResponse, message: string, context: AppContext): void;
}