From d73d3460b4e89e55ecb1e51c134712fc09ba4568 Mon Sep 17 00:00:00 2001 From: Michael Kochell <6913320+mickmister@users.noreply.github.com> Date: Tue, 23 Mar 2021 11:55:23 -0400 Subject: [PATCH] [MM-33716] Update mobile command parser with webapp fixes (#5231) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 * 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 Co-authored-by: Ben Schumacher --- .../app_command_parser/app_command_parser.ts | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/app/components/autocomplete/slash_suggestion/app_command_parser/app_command_parser.ts b/app/components/autocomplete/slash_suggestion/app_command_parser/app_command_parser.ts index 0b1f17683..1a520c168 100644 --- a/app/components/autocomplete/slash_suggestion/app_command_parser/app_command_parser.ts +++ b/app/components/autocomplete/slash_suggestion/app_command_parser/app_command_parser.ts @@ -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; } +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 => { @@ -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 {