[MM-33716] Update mobile command parser with webapp fixes (#5231)

* Apps bindings support (#5012)

* Add redux related information

* Add binding loading on channel refresh

* Add channel header and post option bindings

* Fix test

* Minor fixes

* Fix snapshots

* Handle errors and show bindings only on main channel

* Update Expand Levels keys and values to match latest changes

* Add NAVIGATE call response handling.

* Add more isolation to apps related code

* Add defaults to send ephemeral

* Update variable naming

* Rename shouldProcessApps by a more meaningful appsEnabled

* Embedded forms (#5169)

* Add redux related information

* Add binding loading on channel refresh

* Add channel header and post option bindings

* Fix test

* Minor fixes

* Fix snapshots

* Handle errors and show bindings only on main channel

* Update Expand Levels keys and values to match latest changes

* Add NAVIGATE call response handling.

* Add more isolation to apps related code

* Add Embedded Forms

* Fix snapshots

* Add Embedded Forms

* Improve naming, change the root element to be a binding and improve binding handling

* Get post down on the buttons, remove unneeded variables and minor fixes from the review

* Allow undefined bindings to fillBindingsInformation and add logging for error.

* Address review feedback

* Add App Forms (#5177)

* Add App Forms

* Address feedback and self review

* Add dynamic select

* Fixes and improvements

* Add the ability to refresh on submit.

* Use AppFormValue instead of redoing the type

* Address feedback

* [MM-31508] Rename URL to Path in Call (#5186)

* Add user agent to call context (#5193)

* Remove unneeded state reference (#5196)

* Change user agent query on fetch bindings (#5201)

* Add refresh websocket event to refetch bindings (#5194)

* Add refresh websocket event to refetch bindings

* Add missing changes

* Declare socket event constant and separate the handler to a different function

* Add binding validation on binding fetch (#5200)

* Apps commands (#5107)

* Add redux related information

* Add binding loading on channel refresh

* Add channel header and post option bindings

* Fix test

* Minor fixes

* Fix snapshots

* apps modals draft

* Handle errors and show bindings only on main channel

* Update Expand Levels keys and values to match latest changes

* Add NAVIGATE call response handling.

* Add more isolation to apps related code

* reuse command parser throughout slash_suggestion component's lifecycle

* fix prop and lint

* using alert to show error message. need another way

* duplicate import

* types

* types

* types

* rename file

* copy webapp parser and test

* dependencies moved. tests pass

* move app command parser into its own folder

* converted to typescript, all tests are passing

* automated and manual tests work

* lint

* lint

* remove fall throughs with blocks

* types

* doAppCall type

* extract displayError to deps file

* test types

* lint

* fix tests

* unused import

* PR feedback

* fix imports and show errors

* types

* remove execute suggestion for mobile

* watch feature flag

* fix tests

* change form text arugment behavior to show user input and not hint

* return call response error in doAppCall

* update tests to remove hint from text field suggestions

* lint

* use new base command structure

* fix tests

* wrap appsEnabled

* typescript actions/command.ts

* update app constants

* PR feedback

* fix error handling from doAppCall action

* Use App CallRequest structure (#5212)

* error handling

* move test files

* remove unused import

Co-authored-by: Daniel Espino García <larkox@gmail.com>

* Add feature flag (#5207)

* Add feature flag

* Simplify return

* Add localization, call validation and use call type on subpath (#5221)

* Add localization, call validation and use call type on subpath

* Add more localization to the parser and bring fixes from webapp

* Fix ephemerals and channel header / post options crashes

* fix app command parser deps and alert messages

* Improve suggestion handling

* Fix test

* Fix lint

* Return errors as error

* Address PR feedback

* return error property

* fix error string wordings

Co-authored-by: Michael Kochell <6913320+mickmister@users.noreply.github.com>

* update mobile command parser with webapp fixes

Co-authored-by: Daniel Espino García <larkox@gmail.com>
Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
This commit is contained in:
Michael Kochell 2021-03-23 11:55:23 -04:00 committed by GitHub
parent 11c8454ee2
commit d73d3460b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -3,17 +3,15 @@
/* eslint-disable max-lines */
import {intlShape} from 'react-intl';
import {
AppCallRequest,
AppBinding,
AppField,
AppSelectOption,
AppCallResponse,
AppCallValues,
AppContext,
AppForm,
AppCallValues,
AutocompleteSuggestion,
AutocompleteStaticSelect,
Channel,
@ -31,14 +29,14 @@ import {
getStore,
EXECUTE_CURRENT_COMMAND_ITEM_ID,
getExecuteSuggestion,
displayError,
keyMirror,
createCallRequest,
displayError,
selectChannelByName,
selectUserByUsername,
getUserByUsername,
getChannelByNameAndTeamName,
getCurrentTeam,
selectChannelByName,
} from './app_command_parser_dependencies';
export type Store = {
@ -70,6 +68,10 @@ interface FormsCache {
getForm: (location: string, binding: AppBinding) => Promise<AppForm | undefined>;
}
interface Intl {
formatMessage(config: {id: string; defaultMessage: string}, values?: {[name: string]: any}): string;
}
export class ParsedCommand {
state: string = ParseState.Start;
command: string;
@ -84,7 +86,7 @@ export class ParsedCommand {
values: {[name: string]: string} = {};
location = '';
error = '';
intl: typeof intlShape;
intl: Intl;
constructor(command: string, formsCache: FormsCache, intl: any) {
this.command = command;
@ -166,7 +168,7 @@ export class ParsedCommand {
}
case ParseState.EndCommand: {
const binding = bindings.find((b: AppBinding) => b.label === this.incomplete.toLowerCase());
const binding = bindings.find((b: AppBinding) => b.label.toLowerCase() === this.incomplete.toLowerCase());
if (!binding) {
// gone as far as we could, this token doesn't match a sub-command.
// return the state from the last matching binding
@ -324,7 +326,7 @@ export class ParsedCommand {
case ' ':
case '\t':
case '=': {
const field = fields.find((f) => f.label === this.incomplete.toLowerCase());
const field = fields.find((f) => f.label?.toLowerCase() === this.incomplete.toLowerCase());
if (!field) {
return this.asError(this.intl.formatMessage({
id: 'apps.error.parser.unexpected_flag',
@ -539,11 +541,11 @@ export class AppCommandParser {
private store: Store;
private channelID: string;
private rootPostID?: string;
private intl: typeof intlShape;
private intl: Intl;
forms: {[location: string]: AppForm} = {};
constructor(store: Store|null, intl: typeof intlShape, channelID: string, rootPostID = '') {
constructor(store: Store|null, intl: Intl, channelID: string, rootPostID = '') {
this.store = store || getStore() as Store;
this.channelID = channelID;
this.rootPostID = rootPostID;
@ -557,7 +559,7 @@ export class AppCommandParser {
const commandBindings = this.getCommandBindings();
if (!commandBindings) {
this.displayError(this.intl.formatMessage({
id: 'apps.error.command.no_bindings',
id: 'apps.error.parser.no_bindings',
defaultMessage: 'No command bindings.',
}));
return null;
@ -681,7 +683,7 @@ export class AppCommandParser {
}
expandOptions = async (parsed: ParsedCommand, values: AppCallValues) => {
if (!parsed.form || !parsed.form.fields) {
if (!parsed.form?.fields) {
return true;
}
@ -751,6 +753,7 @@ export class AppCommandParser {
fieldName: f.name,
option: values[f.name],
}));
return;
}
channel = dispatchResult.data;
}
@ -885,7 +888,7 @@ export class AppCommandParser {
return undefined;
}
return res.data.form;
return callResponse.form;
}
getForm = async (location: string, binding: AppBinding): Promise<AppForm | undefined> => {
@ -996,7 +999,7 @@ export class AppCommandParser {
prefix = prefix.substring(1);
}
const applicable = parsed.form.fields.filter((field) => field.label && field.label.startsWith(parsed.incomplete.toLowerCase()) && !parsed.values[field.name]);
const applicable = parsed.form.fields.filter((field) => field.label && field.label.toLowerCase().startsWith(parsed.incomplete.toLowerCase()) && !parsed.values[field.name]);
if (applicable) {
return applicable.map((f) => {
return {