diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/UserInput.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/UserInput.tsx index 44aac5ef1f..97553ed0f0 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/UserInput.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/UserInput.tsx @@ -10,11 +10,13 @@ import { JSONSchema6 } from 'json-schema'; import { SDKTypes, MicrosoftInputDialog, ChoiceInput, ConfirmInput } from '@bfc/shared'; import { TextWidget, SelectWidget } from '../../widgets'; +import { LuEditorWidget } from '../../widgets/LuEditorWidget'; import { field } from './styles'; import { GetSchema, PromptFieldChangeHandler } from './types'; import { ChoiceInputSettings } from './ChoiceInput'; import { ConfirmInputSettings } from './ConfirmInput'; +import { DialogInfo } from '@bfc/indexers/lib/type'; const getOptions = (enumSchema: JSONSchema6) => { if (!enumSchema || !enumSchema.enum || !Array.isArray(enumSchema.enum)) { @@ -24,16 +26,28 @@ const getOptions = (enumSchema: JSONSchema6) => { return enumSchema.enum.map(o => ({ label: o as string, value: o as string })); }; +const usesLuisRecognizer = ({ content }: DialogInfo) => { + return typeof content?.recognizer === 'string'; +}; + interface UserInputProps extends FieldProps { onChange: PromptFieldChangeHandler; getSchema: GetSchema; } export const UserInput: React.FC = props => { - const { onChange, getSchema, idSchema, formData, errorSchema } = props; + const { formContext, onChange, getSchema, idSchema, formData, errorSchema } = props; + const { const: type } = getSchema('$type'); + const [, promptType] = (type as string).split('.'); + const intentName = `${promptType}.response-${formData?.$designer?.id}`; return ( + {usesLuisRecognizer(formContext.currentDialog) && ( +
+ +
+ )}
= props => { const { formContext } = props; const { shellApi, focusedTab, focusedSteps } = formContext; - const promptSettingsIdSchema = ({ __id: props.idSchema.__id + 'promptSettings' } as unknown) as IdSchema; const getSchema: GetSchema = field => { const fieldSchema = get(props.schema, ['properties', field]); @@ -43,38 +41,23 @@ export const PromptField: React.FC = props => { return ( -
- - - - - - - - - - - -
- -
-
- - - -
-
+ + + + + + + + + + + +
); }; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/styles.ts b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/styles.ts index aecd3cf0cf..6cc18679b6 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/styles.ts +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/styles.ts @@ -21,10 +21,6 @@ export const tabs: Partial = { }, }; -export const tabsContainer = css` - border-bottom: 1px solid #c8c6c4; -`; - export const validationItemInput = css` display: flex; align-items: center; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx index bc3579bb6d..e5121ab40c 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx @@ -4,7 +4,6 @@ import React from 'react'; import { Dropdown, ResponsiveMode, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown'; import formatMessage from 'format-message'; -import { RegexRecognizer } from '@bfc/shared'; import { DialogInfo } from '@bfc/indexers'; import { BFDWidgetProps } from '../types'; @@ -19,58 +18,35 @@ enum RecognizerType { 'luis', } -function recognizerType(currentDialog: DialogInfo): RecognizerType | null { - const recognizer = currentDialog.content.recognizer; - if (!recognizer) { - return null; - } +function recognizerType({ content }: DialogInfo): RecognizerType | null { + const { recognizer } = content; - if (typeof recognizer === 'object' && recognizer.$type === 'Microsoft.RegexRecognizer') { - return RecognizerType.regex; - } else if (typeof recognizer === 'string') { - return RecognizerType.luis; + if (recognizer) { + if (typeof recognizer === 'object' && recognizer.$type === 'Microsoft.RegexRecognizer') { + return RecognizerType.regex; + } else if (typeof recognizer === 'string') { + return RecognizerType.luis; + } } return null; } -function regexIntentOptions(currentDialog: DialogInfo): IDropdownOption[] { - const recognizer = currentDialog.content.recognizer as RegexRecognizer; - let options: IDropdownOption[] = [EMPTY_OPTION]; - - if (!recognizer) { - return options; - } - - if (recognizer.intents) { - options = options.concat(recognizer.intents.map(i => ({ key: i.intent, text: i.intent }))); - } - - return options; +function regexIntentOptions({ content }: DialogInfo): IDropdownOption[] { + const { recognizer } = content; + return (recognizer?.intents || []).reduce( + (acc, { intent }) => (intent ? [...acc, { key: intent, text: intent }] : acc), + [EMPTY_OPTION] + ); } export const IntentWidget: React.FC = props => { const { disabled, onChange, id, onFocus, onBlur, value, formContext, placeholder, label, schema } = props; const { description } = schema; const { currentDialog } = formContext; - let options: IDropdownOption[] = []; - let widgetLabel = label; - let isLuisSelected = false; - switch (recognizerType(currentDialog)) { - case RecognizerType.regex: - options = regexIntentOptions(currentDialog); - isLuisSelected = false; - break; - case RecognizerType.luis: - widgetLabel = `Trigger phrases(intent name: #${value || ''})`; - isLuisSelected = true; - break; - default: - options = [EMPTY_OPTION]; - isLuisSelected = false; - break; - } + const type = recognizerType(currentDialog); + const options: IDropdownOption[] = type === RecognizerType.regex ? regexIntentOptions(currentDialog) : [EMPTY_OPTION]; const handleChange = (_e, option): void => { if (option) { @@ -80,21 +56,24 @@ export const IntentWidget: React.FC = props => { return ( <> - - {!isLuisSelected && ( - onBlur && onBlur(id, value)} - onChange={handleChange} - onFocus={() => onFocus && onFocus(id, value)} - options={options} - selectedKey={value || null} - responsiveMode={ResponsiveMode.large} - disabled={disabled || options.length === 1} - placeholder={options.length > 1 ? placeholder : formatMessage('No intents configured for this dialog')} - /> + {type === RecognizerType.luis ? ( + + ) : ( + <> + + onBlur && onBlur(id, value)} + onChange={handleChange} + onFocus={() => onFocus && onFocus(id, value)} + options={options} + selectedKey={value || null} + responsiveMode={ResponsiveMode.large} + disabled={disabled || options.length === 1} + placeholder={options.length > 1 ? placeholder : formatMessage('No intents configured for this dialog')} + /> + )} - {isLuisSelected && } ); }; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/LuEditorWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/LuEditorWidget.tsx index 0d05aac956..c551e5bdab 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/LuEditorWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/LuEditorWidget.tsx @@ -2,18 +2,20 @@ // Licensed under the MIT License. import React from 'react'; -import { LuEditor } from '@bfc/code-editor'; import debounce from 'lodash/debounce'; -import { LuIntentSection } from '@bfc/shared'; +import formatMessage from 'format-message'; +import { LuEditor } from '@bfc/code-editor'; import { LuFile, filterSectionDiagnostics } from '@bfc/indexers'; +import { LuIntentSection } from '@bfc/shared'; import { FormContext } from '../types'; +import { WidgetLabel } from './WidgetLabel'; interface LuEditorWidgetProps { formContext: FormContext; name: string; height?: number | string; - onChange: (template?: string) => void; + onChange?: (template?: string) => void; } export class LuEditorWidget extends React.Component { @@ -33,7 +35,7 @@ export class LuEditorWidget extends React.Component { formContext: FormContext; name: string; luFileId: string; - luFile: LuFile | null; + luFile?: LuFile; luIntent: LuIntentSection; state = { localValue: '' }; debounceUpdate; @@ -64,44 +66,50 @@ export class LuEditorWidget extends React.Component { }); if (this.luFileId) { if (body) { - this.updateLuIntent(body); + this.debounceUpdate(body); } else { this.formContext.shellApi.removeLuIntent(this.luFileId, this.name); } } }; + render() { - const diagnostic = this.luFile && filterSectionDiagnostics(this.luFile.diagnostics, this.luIntent)[0]; + const { height = 250 } = this.props; + const { luFile, luFileId, luIntent, name } = this; + const diagnostic = luFile && filterSectionDiagnostics(luFile.diagnostics, luIntent)[0]; const errorMsg = diagnostic ? diagnostic.message.split('error message: ')[diagnostic.message.split('error message: ').length - 1] : ''; - const luOption = { - fileId: this.luFileId, - sectionId: this.luIntent?.Name, - }; - const height = this.props.height || 250; + + const label = formatMessage('Trigger phrases (intent: #{name})', { name }); return ( - + <> + + + ); } }