From 27a4fdb2cecea823fd41a4f434dd50b6cb484b2e Mon Sep 17 00:00:00 2001 From: leileizhang Date: Mon, 9 Mar 2020 23:41:05 +0800 Subject: [PATCH 1/4] fix: lu build bug when training empty intents (#2201) --- Composer/packages/client/package.json | 2 +- Composer/packages/lib/indexers/package.json | 2 +- Composer/packages/lib/indexers/src/luIndexer.ts | 2 +- Composer/packages/server/package.json | 2 +- .../language-servers/language-understanding/package.json | 2 +- Composer/yarn.lock | 8 ++++---- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Composer/packages/client/package.json b/Composer/packages/client/package.json index 4b125b00bf..ea80ad3363 100644 --- a/Composer/packages/client/package.json +++ b/Composer/packages/client/package.json @@ -20,7 +20,7 @@ "@bfc/extensions": "*", "@bfc/indexers": "*", "@bfc/shared": "*", - "@microsoft/bf-lu": "4.8.0-preview.110925", + "@microsoft/bf-lu": "4.8.0-preview.111952", "@emotion/core": "^10.0.7", "@reach/router": "^1.2.1", "axios": "^0.18.0", diff --git a/Composer/packages/lib/indexers/package.json b/Composer/packages/lib/indexers/package.json index 5cdba6f35b..953c0f7fc6 100644 --- a/Composer/packages/lib/indexers/package.json +++ b/Composer/packages/lib/indexers/package.json @@ -29,7 +29,7 @@ }, "dependencies": { "@bfc/shared": "*", - "@microsoft/bf-lu": "4.8.0-preview.110925", + "@microsoft/bf-lu": "4.8.0-preview.111952", "botbuilder-lg": "^4.8.0-preview.106823", "botframework-expressions": "^4.8.0-preview.106476", "lodash": "^4.17.15" diff --git a/Composer/packages/lib/indexers/src/luIndexer.ts b/Composer/packages/lib/indexers/src/luIndexer.ts index 8dc778af09..207707730c 100644 --- a/Composer/packages/lib/indexers/src/luIndexer.ts +++ b/Composer/packages/lib/indexers/src/luIndexer.ts @@ -15,7 +15,7 @@ const { luParser } = sectionHandler; function convertLuDiagnostic(d: any, source: string): Diagnostic { const severityMap = { ERROR: DiagnosticSeverity.Error, - WARNING: DiagnosticSeverity.Warning, + WARN: DiagnosticSeverity.Warning, INFORMATION: DiagnosticSeverity.Information, HINT: DiagnosticSeverity.Hint, }; diff --git a/Composer/packages/server/package.json b/Composer/packages/server/package.json index ce17df22c7..b55679aba0 100644 --- a/Composer/packages/server/package.json +++ b/Composer/packages/server/package.json @@ -57,7 +57,7 @@ "@bfc/lg-languageserver": "*", "@bfc/lu-languageserver": "*", "@bfc/shared": "*", - "@microsoft/bf-lu": "4.8.0-preview.110925", + "@microsoft/bf-lu": "4.8.0-preview.111952", "archiver": "^3.0.0", "axios": "^0.18.0", "azure-storage": "^2.10.3", diff --git a/Composer/packages/tools/language-servers/language-understanding/package.json b/Composer/packages/tools/language-servers/language-understanding/package.json index 3957f83c7f..cfd4d243c6 100644 --- a/Composer/packages/tools/language-servers/language-understanding/package.json +++ b/Composer/packages/tools/language-servers/language-understanding/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@microsoft/bf-cli-command": "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@microsoft/bf-cli-command/-/@microsoft/bf-cli-command-1.0.1.tgz", - "@microsoft/bf-lu": "4.8.0-preview.110925", + "@microsoft/bf-lu": "4.8.0-preview.111952", "@types/node": "^12.0.4", "express": "^4.15.2", "monaco-editor-core": "^0.17.0", diff --git a/Composer/yarn.lock b/Composer/yarn.lock index f161cf854a..df1dcb8af2 100644 --- a/Composer/yarn.lock +++ b/Composer/yarn.lock @@ -2714,10 +2714,10 @@ fs-extra "^7.0.1" tslib "~1.10.0" -"@microsoft/bf-lu@4.8.0-preview.110925": - version "4.8.0-preview.110925" - uid "8905960d5858aa9f4d94c150fdc80ac4b6947e94" - resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-4.8.0-preview.110925.tgz#8905960d5858aa9f4d94c150fdc80ac4b6947e94" +"@microsoft/bf-lu@4.8.0-preview.111952": + version "4.8.0-preview.111952" + uid d1707a5f150ab204e67122f8b1d5796ad7f656c9 + resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@microsoft/bf-lu/-/@microsoft/bf-lu-4.8.0-preview.111952.tgz#d1707a5f150ab204e67122f8b1d5796ad7f656c9" dependencies: "@azure/cognitiveservices-luis-authoring" "3.0.1" "@azure/ms-rest-azure-js" "2.0.1" From 66e5fb4f68fa0f810cf41c4c741bc0d6dc405b50 Mon Sep 17 00:00:00 2001 From: liweitian Date: Tue, 10 Mar 2020 01:46:19 +0800 Subject: [PATCH 2/4] fix: trigger creation bug (#2151) * fix bug * save tmp code * add regex intent back * update * update label text * rename onMessageActivity to onMessageReceivedMessage * update trigger type validation function * remove commented code * rename onMessageActivity to onMessageReceivedMessage & update trigger type validation function * update regex field * remove commented code * remove commented code * revert auto-saved file * update label text * fix bug * save tmp code * add regex intent back * update * update label text * rename onMessageActivity to onMessageReceivedMessage * update trigger type validation function * remove commented code * update regex field * remove commented code * remove commented code * revert auto-saved file * update label text * update label text * update regEx api * add shellapi updateRegExIntentHandler * shell api * inline regex in form editor * create new inline regex intent when no intent Co-authored-by: Long Alan Co-authored-by: Chris Whitten --- Composer/packages/client/src/ShellApi.ts | 10 +++ .../ProjectTree/TriggerCreationModal.tsx | 86 ++++++++++++++----- .../ExtensionContainer.tsx | 4 + .../client/src/pages/design/index.tsx | 18 ++-- .../packages/client/src/utils/dialogUtil.ts | 58 ++++++++++--- .../obiformeditor/demo/src/index.tsx | 1 + .../src/Form/fields/RecognizerField/index.tsx | 10 --- .../src/Form/widgets/IntentWidget.tsx | 31 ++++--- .../src/Form/widgets/RegexEditorWidget.tsx | 53 ++++++++++++ .../obiformeditor/src/schema/uischema.ts | 2 +- Composer/packages/lib/shared/src/appschema.ts | 9 +- Composer/packages/lib/shared/src/labelMap.ts | 4 + .../packages/lib/shared/src/types/schema.ts | 1 + .../packages/lib/shared/src/types/shell.ts | 1 + Composer/packages/lib/shared/src/viewUtils.ts | 2 +- .../packages/server/schemas/editor.schema | 4 +- Composer/packages/server/schemas/sdk.schema | 14 +-- 17 files changed, 230 insertions(+), 78 deletions(-) create mode 100644 Composer/packages/extensions/obiformeditor/src/Form/widgets/RegexEditorWidget.tsx diff --git a/Composer/packages/client/src/ShellApi.ts b/Composer/packages/client/src/ShellApi.ts index ed3dd20dea..11614ba51a 100644 --- a/Composer/packages/client/src/ShellApi.ts +++ b/Composer/packages/client/src/ShellApi.ts @@ -9,6 +9,7 @@ import get from 'lodash/get'; import { isExpression } from './utils'; import * as lgUtil from './utils/lgUtil'; import * as luUtil from './utils/luUtil'; +import { updateRegExIntent } from './utils/dialogUtil'; import { StoreContext } from './store'; import ApiClient from './messenger/ApiClient'; import { getDialogData, setDialogData, sanitizeDialogData } from './utils'; @@ -243,6 +244,14 @@ export const ShellApi: React.FC = () => { return await updateLuFile({ id, content }); } + async function updateRegExIntentHandler({ id, intentName, pattern }, event) { + if (isEventSourceValid(event) === false) return false; + const dialog = dialogs.find(dialog => dialog.id === id); + if (!dialog) throw new Error(`dialog ${dialogId} not found`); + const newDialog = updateRegExIntent(dialog, intentName, pattern); + return await updateDialog({ id, content: newDialog.content }); + } + async function fileHandler(fileTargetType, fileChangeType, { id, content }, event) { if (isEventSourceValid(event) === false) return false; @@ -345,6 +354,7 @@ export const ShellApi: React.FC = () => { apiClient.registerApi('addLuIntent', addLuIntentHandler); apiClient.registerApi('updateLuIntent', updateLuIntentHandler); apiClient.registerApi('removeLuIntent', removeLuIntentHandler); + apiClient.registerApi('updateRegExIntent', updateRegExIntentHandler); apiClient.registerApi('navTo', navTo); apiClient.registerApi('onFocusEvent', focusEvent); apiClient.registerApi('onFocusSteps', focusSteps); diff --git a/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx b/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx index 472df83534..a9e70383b3 100644 --- a/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx +++ b/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx @@ -17,7 +17,7 @@ import get from 'lodash/get'; import { LuEditor } from '@bfc/code-editor'; import { - addNewTrigger, + generateNewDialog, getTriggerTypes, TriggerFormData, TriggerFormDataErrors, @@ -28,6 +28,7 @@ import { getEventTypes, getActivityTypes, getMessageTypes, + regexRecognizerKey, } from '../../utils/dialogUtil'; import { addIntent } from '../../utils/luUtil'; import { StoreContext } from '../../store'; @@ -35,9 +36,13 @@ import { StoreContext } from '../../store'; import { styles, dropdownStyles, dialogWindow, intent } from './styles'; const nameRegex = /^[a-zA-Z0-9-_.]+$/; -const validateForm = (data: TriggerFormData): TriggerFormDataErrors => { +const validateForm = ( + data: TriggerFormData, + isRegEx: boolean, + regExIntents: [{ intent: string; pattern: string }] +): TriggerFormDataErrors => { const errors: TriggerFormDataErrors = {}; - const { $type, specifiedType, intent, triggerPhrases } = data; + const { $type, specifiedType, intent, triggerPhrases, regexEx } = data; if ($type === eventTypeKey && !specifiedType) { errors.specifiedType = formatMessage('Please select a event type'); @@ -47,17 +52,29 @@ const validateForm = (data: TriggerFormData): TriggerFormDataErrors => { errors.specifiedType = formatMessage('Please select an activity type'); } + if ($type === messageTypeKey && !specifiedType) { + errors.specifiedType = formatMessage('Please select a message type'); + } + if (!$type) { errors.$type = formatMessage('Please select a trigger type'); } - if (!intent || !nameRegex.test(intent)) { + if ($type === intentTypeKey && (!intent || !nameRegex.test(intent))) { errors.intent = formatMessage( 'Spaces and special characters are not allowed. Use letters, numbers, -, or _., numbers, -, and _' ); } - if (!triggerPhrases) { + if ($type === intentTypeKey && isRegEx && regExIntents.find(ri => ri.intent === intent)) { + errors.intent = `regEx ${intent} is already defined`; + } + + if ($type === intentTypeKey && isRegEx && !regexEx) { + errors.regexEx = formatMessage('Please input regEx pattern'); + } + + if ($type === intentTypeKey && !isRegEx && !triggerPhrases) { errors.triggerPhrases = formatMessage('Please input trigger phrases'); } if (data.errors.triggerPhrases) { @@ -66,7 +83,7 @@ const validateForm = (data: TriggerFormData): TriggerFormDataErrors => { return errors; }; -interface LuFilePayload { +export interface LuFilePayload { id: string; content: string; } @@ -75,7 +92,7 @@ interface TriggerCreationModalProps { dialogId: string; isOpen: boolean; onDismiss: () => void; - onSubmit: (dialog: DialogInfo, luFilePayload: LuFilePayload) => void; + onSubmit: (dialog: DialogInfo, luFilePayload?: LuFilePayload) => void; } const initialFormData: TriggerFormData = { @@ -84,6 +101,7 @@ const initialFormData: TriggerFormData = { specifiedType: '', intent: '', triggerPhrases: '', + regexEx: '', }; const triggerTypeOptions: IDropdownOption[] = getTriggerTypes(); @@ -94,10 +112,12 @@ export const TriggerCreationModal: React.FC = props = const { state } = useContext(StoreContext); const { dialogs, luFiles } = state; const luFile = luFiles.find(lu => lu.id === dialogId); - + const dialogFile = dialogs.find(dialog => dialog.id === dialogId); + const isRegEx = get(dialogFile, 'content.recognizer.$type', '') === regexRecognizerKey; + const regexIntents = get(dialogFile, 'content.recognizer.intents', []); const onClickSubmitButton = e => { e.preventDefault(); - const errors = validateForm(formData); + const errors = validateForm(formData, isRegEx, regexIntents); if (Object.keys(errors).length) { setFormData({ @@ -108,13 +128,17 @@ export const TriggerCreationModal: React.FC = props = } const content = get(luFile, 'content', ''); - const newContent = addIntent(content, { Name: formData.intent, Body: formData.triggerPhrases }); - const updateLuFile = { - id: dialogId, - content: newContent, - }; - const newDialog = addNewTrigger(dialogs, dialogId, formData); - onSubmit(newDialog, updateLuFile); + const newDialog = generateNewDialog(dialogs, dialogId, formData); + if (formData.$type === intentTypeKey && !isRegEx) { + const newContent = addIntent(content, { Name: formData.intent, Body: formData.triggerPhrases }); + const updateLuFile = { + id: dialogId, + content: newContent, + }; + onSubmit(newDialog, updateLuFile); + } else { + onSubmit(newDialog); + } onDismiss(); }; @@ -130,6 +154,10 @@ export const TriggerCreationModal: React.FC = props = setFormData({ ...formData, intent: name }); }; + const onChangeRegEx = (e, pattern) => { + setFormData({ ...formData, regexEx: pattern }); + }; + const onTriggerPhrasesChange = (body: string) => { const errors = formData.errors; const content = '#' + formData.intent + '\n' + body; @@ -142,7 +170,9 @@ export const TriggerCreationModal: React.FC = props = const activityTypes: IDropdownOption[] = getActivityTypes(); const messageTypes: IDropdownOption[] = getMessageTypes(); - const showIntentFields = formData.$type === intentTypeKey; + const showIntentName = formData.$type === intentTypeKey; + const showRegExDropDown = formData.$type === intentTypeKey && isRegEx; + const showTriggerPhrase = formData.$type === intentTypeKey && !isRegEx; const showEventDropDown = formData.$type === eventTypeKey; const showActivityDropDown = formData.$type === activityTypeKey; const showMessageDropDown = formData.$type === messageTypeKey; @@ -172,7 +202,6 @@ export const TriggerCreationModal: React.FC = props = data-testid={'triggerTypeDropDown'} defaultSelectedKey={intentTypeKey} /> - {showEventDropDown && ( = props = data-testid={'messageTypeDropDown'} /> )} - {showIntentFields && ( + {showIntentName && ( )} - {showIntentFields && } - {showIntentFields && ( + + {showRegExDropDown && ( + + )} + {showTriggerPhrase && } + {showTriggerPhrase && ( { + return apiClient.apiCall('updateRegExIntent', { id, intentName, pattern }); + }, + createDialog: () => { return apiClient.apiCall('createDialog'); }, diff --git a/Composer/packages/client/src/pages/design/index.tsx b/Composer/packages/client/src/pages/design/index.tsx index 25655f874f..b0b36a2020 100644 --- a/Composer/packages/client/src/pages/design/index.tsx +++ b/Composer/packages/client/src/pages/design/index.tsx @@ -12,12 +12,13 @@ import { globalHistory } from '@reach/router'; import get from 'lodash/get'; import { PromptTab } from '@bfc/shared'; import { getNewDesigner, seedNewDialog } from '@bfc/shared'; +import { DialogInfo } from '@bfc/indexers'; import { VisualEditorAPI } from '../../messenger/FrameAPI'; import { TestController } from '../../TestController'; import { BASEPATH, DialogDeleting } from '../../constants'; import { createSelectedPath, deleteTrigger, getbreadcrumbLabel } from '../../utils'; -import { TriggerCreationModal } from '../../components/ProjectTree/TriggerCreationModal'; +import { TriggerCreationModal, LuFilePayload } from '../../components/ProjectTree/TriggerCreationModal'; import { Conversation } from '../../components/Conversation'; import { DialogStyle } from '../../components/Modal/styles'; import { OpenConfirmModal } from '../../components/Modal/Confirm'; @@ -171,18 +172,21 @@ function DesignPage(props) { setTriggerModalVisibility(true); }; - const onTriggerCreationSubmit = (dialog, luFile) => { + const onTriggerCreationSubmit = (dialog: DialogInfo, luFile?: LuFilePayload) => { const dialogPayload = { id: dialog.id, content: dialog.content, }; - const luFilePayload = { - id: luFile.id, - content: luFile.content, - }; + if (luFile) { + const luFilePayload = { + id: luFile.id, + content: luFile.content, + }; + actions.updateLuFile(luFilePayload); + } + const index = get(dialog, 'content.triggers', []).length - 1; actions.selectTo(`triggers[${index}]`); - actions.updateLuFile(luFilePayload); actions.updateDialog(dialogPayload); }; diff --git a/Composer/packages/client/src/utils/dialogUtil.ts b/Composer/packages/client/src/utils/dialogUtil.ts index e54934034c..ded58597d9 100644 --- a/Composer/packages/client/src/utils/dialogUtil.ts +++ b/Composer/packages/client/src/utils/dialogUtil.ts @@ -24,6 +24,7 @@ export interface TriggerFormData { specifiedType: string; intent: string; triggerPhrases: string; + regexEx: string; } export interface TriggerFormDataErrors { @@ -31,6 +32,7 @@ export interface TriggerFormDataErrors { intent?: string; specifiedType?: string; triggerPhrases?: string; + regexEx?: string; } export function getDialog(dialogs: DialogInfo[], dialogId: string) { @@ -60,8 +62,15 @@ export function getFriendlyName(data) { return data.$type; } -export function insert(content, path: string, position: number | undefined, data: TriggerFormData) { +export function insert(content, path: string, position: number | undefined, data: any) { const current = get(content, path, []); + const insertAt = typeof position === 'undefined' ? current.length : position; + current.splice(insertAt, 0, data); + set(content, path, current); + return content; +} + +export function generateNewTrigger(data: TriggerFormData) { const optionalAttributes: { intent?: string; event?: string } = {}; if (data.specifiedType) { data.$type = data.specifiedType; @@ -73,23 +82,52 @@ export function insert(content, path: string, position: number | undefined, data $type: data.$type, ...seedNewDialog(data.$type, {}, optionalAttributes), }; + return newStep; +} - const insertAt = typeof position === 'undefined' ? current.length : position; - - current.splice(insertAt, 0, newStep); +export function generateRegexExpression(intent: string, pattern: string) { + return { intent, pattern }; +} - set(content, path, current); +export function createNewTrigger(dialog: DialogInfo, data: TriggerFormData): DialogInfo { + const dialogCopy = cloneDeep(dialog); + const trigger = generateNewTrigger(data); + insert(dialogCopy.content, 'triggers', undefined, trigger); + return dialogCopy; +} - return content; +export function createRegExIntent(dialog: DialogInfo, intent: string, pattern: string): DialogInfo { + const regex = generateRegexExpression(intent, pattern); + const dialogCopy = cloneDeep(dialog); + insert(dialogCopy.content, 'recognizer.intents', undefined, regex); + return dialogCopy; } -export function addNewTrigger(dialogs: DialogInfo[], dialogId: string, data: TriggerFormData): DialogInfo { - const dialogCopy = getDialog(dialogs, dialogId); - if (!dialogCopy) throw new Error(`dialog ${dialogId} does not exist`); - insert(dialogCopy.content, 'triggers', undefined, data); +export function updateRegExIntent(dialog: DialogInfo, intent: string, pattern: string): DialogInfo { + let dialogCopy = cloneDeep(dialog); + const regexIntents = get(dialogCopy, 'content.recognizer.intents', []); + const targetIntent = regexIntents.find(ri => ri.intent === intent); + if (!targetIntent) { + dialogCopy = createRegExIntent(dialog, intent, pattern); + } else { + targetIntent.pattern = pattern; + } return dialogCopy; } +export function generateNewDialog(dialogs: DialogInfo[], dialogId: string, data: TriggerFormData): DialogInfo { + //add new trigger + const dialog = dialogs.find(dialog => dialog.id === dialogId); + if (!dialog) throw new Error(`dialog ${dialogId} does not exist`); + let updatedDialog = createNewTrigger(dialog, data); + + //add regex expression + if (data.regexEx) { + updatedDialog = createRegExIntent(updatedDialog, data.intent, data.regexEx); + } + return updatedDialog; +} + export function createSelectedPath(selected: number) { return `triggers[${selected}]`; } diff --git a/Composer/packages/extensions/obiformeditor/demo/src/index.tsx b/Composer/packages/extensions/obiformeditor/demo/src/index.tsx index a399e293d7..5178b5d728 100644 --- a/Composer/packages/extensions/obiformeditor/demo/src/index.tsx +++ b/Composer/packages/extensions/obiformeditor/demo/src/index.tsx @@ -176,6 +176,7 @@ const mockShellApi = [ 'addLuIntent', 'updateLuIntent', 'removeLuIntent', + 'updateRegExIntent', 'validateExpression', 'onFocusSteps', 'onFocusEvent', diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/RecognizerField/index.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/RecognizerField/index.tsx index 5a490cfda5..70c27c0f64 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/fields/RecognizerField/index.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/RecognizerField/index.tsx @@ -11,9 +11,6 @@ import { LuFile } from '@bfc/indexers'; import { BaseField } from '../BaseField'; -import ToggleEditor from './ToggleEditor'; -import RegexEditor from './RegexEditor'; - import './styles.css'; export const RecognizerField: React.FC> = props => { @@ -127,13 +124,6 @@ export const RecognizerField: React.FC> = props responsiveMode={ResponsiveMode.large} onRenderTitle={onRenderTitle} /> - - {() => { - if (isRegex) { - return ; - } - }} - ); diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx index e5121ab40c..b659fb552f 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx @@ -10,10 +10,12 @@ import { BFDWidgetProps } from '../types'; import { WidgetLabel } from './WidgetLabel'; import { LuEditorWidget } from './LuEditorWidget'; +import { RegexEditorWidget } from './RegexEditorWidget'; const EMPTY_OPTION = { key: '', text: '' }; enum RecognizerType { + 'none', 'regex', 'luis', } @@ -29,15 +31,7 @@ function recognizerType({ content }: DialogInfo): RecognizerType | null { } } - return null; -} - -function regexIntentOptions({ content }: DialogInfo): IDropdownOption[] { - const { recognizer } = content; - return (recognizer?.intents || []).reduce( - (acc, { intent }) => (intent ? [...acc, { key: intent, text: intent }] : acc), - [EMPTY_OPTION] - ); + return RecognizerType.none; } export const IntentWidget: React.FC = props => { @@ -46,7 +40,16 @@ export const IntentWidget: React.FC = props => { const { currentDialog } = formContext; const type = recognizerType(currentDialog); - const options: IDropdownOption[] = type === RecognizerType.regex ? regexIntentOptions(currentDialog) : [EMPTY_OPTION]; + let options: IDropdownOption[] = []; + + switch (type) { + case RecognizerType.regex: + case RecognizerType.luis: + break; + default: + options = [EMPTY_OPTION]; + break; + } const handleChange = (_e, option): void => { if (option) { @@ -56,13 +59,11 @@ export const IntentWidget: React.FC = props => { return ( <> - {type === RecognizerType.luis ? ( - - ) : ( + {type === RecognizerType.none && ( <> onBlur && onBlur(id, value)} onChange={handleChange} onFocus={() => onFocus && onFocus(id, value)} @@ -74,6 +75,8 @@ export const IntentWidget: React.FC = props => { /> )} + {type === RecognizerType.luis && } + {type === RecognizerType.regex && } ); }; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/RegexEditorWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/RegexEditorWidget.tsx new file mode 100644 index 0000000000..6909cb0585 --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/RegexEditorWidget.tsx @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import formatMessage from 'format-message'; +import { RegexRecognizer } from '@bfc/shared'; +import { DialogInfo } from '@bfc/indexers'; +import { useState } from 'react'; + +import { FormContext } from '../types'; + +import { TextWidget } from '.'; + +interface RegexEditorWidgetProps { + formContext: FormContext; + name: string; + onChange?: (template?: string) => void; +} + +function getRegexIntentPattern(currentDialog: DialogInfo, intent: string): string | null { + const recognizer = currentDialog.content.recognizer as RegexRecognizer; + let pattern: string | null = null; + + if (!recognizer) { + return null; + } + + if (recognizer.intents) { + pattern = recognizer.intents.find(i => i.intent === intent)?.pattern || null; + } + + return pattern; +} +export const RegexEditorWidget: React.FC = props => { + const { formContext, name } = props; + const { currentDialog } = formContext; + const label = formatMessage('Trigger phrases (intent: #{name})', { name }); + const [localValue, setLocalValue] = useState(getRegexIntentPattern(currentDialog, name)); + const handleIntentchange = (pattern): void => { + setLocalValue(pattern); + formContext.shellApi.updateRegExIntent(currentDialog.id, name, pattern); + }; + return ( + + ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/schema/uischema.ts b/Composer/packages/extensions/obiformeditor/src/schema/uischema.ts index 01fdd5ed71..54b5796491 100644 --- a/Composer/packages/extensions/obiformeditor/src/schema/uischema.ts +++ b/Composer/packages/extensions/obiformeditor/src/schema/uischema.ts @@ -159,7 +159,7 @@ export const uiSchema: { [key in SDKTypes]?: UiSchema } = { [SDKTypes.OnInvokeActivity]: { ...triggerUiSchema, }, - [SDKTypes.OnMessageActivity]: { + [SDKTypes.OnMessageReceivedActivity]: { ...triggerUiSchema, }, [SDKTypes.OnMessageDeleteActivity]: { diff --git a/Composer/packages/lib/shared/src/appschema.ts b/Composer/packages/lib/shared/src/appschema.ts index f52fb02d27..3d9ff52432 100644 --- a/Composer/packages/lib/shared/src/appschema.ts +++ b/Composer/packages/lib/shared/src/appschema.ts @@ -2324,13 +2324,14 @@ export const appschema: OBISchema = { }, }, }, - 'Microsoft.OnMessageActivity': { + 'Microsoft.OnMessageReceivedActivity': { $role: 'unionType(Microsoft.ITriggerCondition)', - title: 'On Message activity', - description: "Actions to perform on receipt of an activity with type 'Message'. Overrides Intent trigger.", + title: 'On MessageRecieved activity', + description: + "Actions to perform on receipt of an activity with type 'MessageRecieved'. Overrides Intent trigger.", type: 'object', properties: { - ...$properties(SDKTypes.OnMessageActivity), + ...$properties(SDKTypes.OnMessageReceivedActivity), condition: { $role: 'expression', title: 'Condition', diff --git a/Composer/packages/lib/shared/src/labelMap.ts b/Composer/packages/lib/shared/src/labelMap.ts index b49e7a4714..f1a03fd2b0 100644 --- a/Composer/packages/lib/shared/src/labelMap.ts +++ b/Composer/packages/lib/shared/src/labelMap.ts @@ -175,6 +175,10 @@ export const ConceptLabels: { [key in ConceptLabelKey]?: LabelOverride } = { title: formatMessage('Message events'), subtitle: formatMessage('Message recieved activity'), }, + [SDKTypes.OnMessageReceivedActivity]: { + title: formatMessage('Message received'), + subtitle: formatMessage('Message recieved activity'), + }, [SDKTypes.OnMessageDeleteActivity]: { title: formatMessage('Message deleted'), subtitle: formatMessage('Message deleted activity'), diff --git a/Composer/packages/lib/shared/src/types/schema.ts b/Composer/packages/lib/shared/src/types/schema.ts index 6bcd5b2818..fa1330a206 100644 --- a/Composer/packages/lib/shared/src/types/schema.ts +++ b/Composer/packages/lib/shared/src/types/schema.ts @@ -74,6 +74,7 @@ export enum SDKTypes { OnIntent = 'Microsoft.OnIntent', OnInvokeActivity = 'Microsoft.OnInvokeActivity', OnMessageActivity = 'Microsoft.OnMessageActivity', + OnMessageReceivedActivity = 'Microsoft.OnMessageReceivedActivity', OnMessageDeleteActivity = 'Microsoft.OnMessageDeleteActivity', OnMessageReactionActivity = 'Microsoft.OnMessageReactionActivity', OnMessageUpdateActivity = 'Microsoft.OnMessageUpdateActivity', diff --git a/Composer/packages/lib/shared/src/types/shell.ts b/Composer/packages/lib/shared/src/types/shell.ts index 521d3600a1..cde567c97a 100644 --- a/Composer/packages/lib/shared/src/types/shell.ts +++ b/Composer/packages/lib/shared/src/types/shell.ts @@ -72,6 +72,7 @@ export interface ShellApi { removeLgTemplates: (id: string, templateNames: string[]) => Promise; addLuIntent: (id: string, intent: LuIntentSection | null) => Promise; updateLuIntent: (id: string, intentName: string, intent: LuIntentSection | null) => Promise; + updateRegExIntent: (id: string, intentName: string, pattern: string) => Promise; removeLuIntent: (id: string, intentName: string) => Promise; createDialog: () => Promise; validateExpression: (expression?: string) => Promise; diff --git a/Composer/packages/lib/shared/src/viewUtils.ts b/Composer/packages/lib/shared/src/viewUtils.ts index 923c54b228..31c92478b4 100644 --- a/Composer/packages/lib/shared/src/viewUtils.ts +++ b/Composer/packages/lib/shared/src/viewUtils.ts @@ -129,7 +129,7 @@ export const dialogGroups: DialogGroupsMap = { [DialogGroup.MESSAGE_EVENTS]: { label: 'Message events', types: [ - SDKTypes.OnMessageActivity, + SDKTypes.OnMessageReceivedActivity, SDKTypes.OnMessageDeleteActivity, SDKTypes.OnMessageReactionActivity, SDKTypes.OnMessageUpdateActivity, diff --git a/Composer/packages/server/schemas/editor.schema b/Composer/packages/server/schemas/editor.schema index 3d4c987261..672349bee7 100644 --- a/Composer/packages/server/schemas/editor.schema +++ b/Composer/packages/server/schemas/editor.schema @@ -199,8 +199,8 @@ "title": "Conversation invoked", "subtitle": "Invoke activity" }, - "Microsoft.OnMessageActivity": { - "title": "Message events", + "Microsoft.OnMessageReceivedActivity": { + "title": "Message recieved", "subtitle": "Message recieved activity" }, "Microsoft.OnMessageDeleteActivity": { diff --git a/Composer/packages/server/schemas/sdk.schema b/Composer/packages/server/schemas/sdk.schema index a1c8661f27..be2633ce59 100644 --- a/Composer/packages/server/schemas/sdk.schema +++ b/Composer/packages/server/schemas/sdk.schema @@ -351,9 +351,9 @@ "$ref": "#/definitions/Microsoft.OnInvokeActivity" }, { - "title": "Microsoft.OnMessageActivity", - "description": "Actions to perform on receipt of an activity with type 'Message'. Overrides Intent trigger.", - "$ref": "#/definitions/Microsoft.OnMessageActivity" + "title": "Microsoft.OnMessageReceivedActivity", + "description": "Actions to perform on receipt of an activity with type 'MessageReceived'. Overrides Intent trigger.", + "$ref": "#/definitions/Microsoft.OnMessageReceivedActivity" }, { "title": "Microsoft.OnMessageDeleteActivity", @@ -4891,9 +4891,9 @@ "$ref": "#/definitions/Microsoft.OnInvokeActivity" }, { - "title": "Microsoft.OnMessageActivity", + "title": "Microsoft.OnMessageReceivedActivity", "description": "Actions to perform on receipt of an activity with type 'Message'. Overrides Intent trigger.", - "$ref": "#/definitions/Microsoft.OnMessageActivity" + "$ref": "#/definitions/Microsoft.OnMessageReceivedActivity" }, { "title": "Microsoft.OnMessageDeleteActivity", @@ -8184,7 +8184,7 @@ } ] }, - "Microsoft.OnMessageActivity": { + "Microsoft.OnMessageReceivedActivity": { "$role": "union(Microsoft.ITriggerCondition)", "title": "On Message activity", "description": "Actions to perform on receipt of an activity with type 'Message'. Overrides Intent trigger.", @@ -8195,7 +8195,7 @@ "description": "Defines the valid properties for the component you are configuring (from a dialog .schema file)", "type": "string", "pattern": "^[a-zA-Z][a-zA-Z0-9.]*$", - "const": "Microsoft.OnMessageActivity" + "const": "Microsoft.OnMessageReceivedActivity" }, "$copy": { "title": "$copy", From 79f9040fc0a1d6c13900b892a0be106519ba0a67 Mon Sep 17 00:00:00 2001 From: zeye <2295905420@qq.com> Date: Tue, 10 Mar 2020 04:50:08 +0800 Subject: [PATCH 3/4] defense lg copy API failure (#2198) Co-authored-by: Chris Whitten --- Composer/packages/extensions/visual-designer/src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Composer/packages/extensions/visual-designer/src/index.tsx b/Composer/packages/extensions/visual-designer/src/index.tsx index 974b59904f..8896a1c83d 100644 --- a/Composer/packages/extensions/visual-designer/src/index.tsx +++ b/Composer/packages/extensions/visual-designer/src/index.tsx @@ -76,7 +76,7 @@ const VisualDesigner: React.FC = ({ clipboardActions: clipboardActions || [], updateLgTemplate, getLgTemplates, - copyLgTemplate, + copyLgTemplate: (id: string, from: string, to?: string) => copyLgTemplate(id, from, to).catch(() => ''), removeLgTemplate, removeLgTemplates, removeLuIntent, From ceb8186eca00c81f74d31a633d40dfdf455259f2 Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Mon, 9 Mar 2020 14:59:50 -0700 Subject: [PATCH 4/4] release: update changelog (#2204) * add a11y to tags and add additional memebers * update changelog --- CHANGELOG.md | 51 +++++++++++++++++++++++++++++++++++ scripts/generate-changelog.js | 26 +++++++++--------- 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0f67e1b60..aee5732f2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,57 @@ ## Releases +### 03-09-2020 + +#### Added + +- feat: Remove input LU when deconstructing prompts ([#2180](https://github.com/microsoft/BotFramework-Composer/pull/2180)) ([@tdurnford](https://github.com/tdurnford)) +- feat: Add cross train before luis publish ([#2069](https://github.com/microsoft/BotFramework-Composer/pull/2069)) ([@cwhitten](https://github.com/cwhitten)) +- feat: Added inline lu to prompts ([#2159](https://github.com/microsoft/BotFramework-Composer/pull/2159)) ([@cwhitten](https://github.com/cwhitten)) +- feat: implement new action design to improve readability ([#2136](https://github.com/microsoft/BotFramework-Composer/pull/2136)) ([@cwhitten](https://github.com/cwhitten)) +- feat: repaint ui for setProperties in visual editor ([#2017](https://github.com/microsoft/BotFramework-Composer/pull/2017)) ([@alanlong9278](https://github.com/alanlong9278)) +- feat: Update package and schema to 200216 ([#1997](https://github.com/microsoft/BotFramework-Composer/pull/1997)) ([@luhan2017](https://github.com/luhan2017)) +- feat: update new trigger modal according to design ([#1786](https://github.com/microsoft/BotFramework-Composer/pull/1786)) ([@liweitian](https://github.com/liweitian)) +- feat: display 6 actions as contentless node ([#2108](https://github.com/microsoft/BotFramework-Composer/pull/2108)) ([@yeze322](https://github.com/yeze322)) +- feat: support multi-line node block in Visual Editor ([#2005](https://github.com/microsoft/BotFramework-Composer/pull/2005)) ([@yeze322](https://github.com/yeze322)) +- feat: add more help links ([#2070](https://github.com/microsoft/BotFramework-Composer/pull/2070)) ([@a-b-r-o-w-n](https://github.com/a-b-r-o-w-n)) +- feat: support inline LU section editing ([#1994](https://github.com/microsoft/BotFramework-Composer/pull/1994)) ([@zhixzhan](https://github.com/zhixzhan)) + +#### Fixed + +- fix: trigger creation bug ([#2151](https://github.com/microsoft/BotFramework-Composer/pull/2151)) ([@liweitian](https://github.com/liweitian)) +- fix: lu build bug when training empty intents ([#2201](https://github.com/microsoft/BotFramework-Composer/pull/2201)) ([@lei9444](https://github.com/lei9444)) +- fix: use nightly build to replace the private bf-lu package ([#2190](https://github.com/microsoft/BotFramework-Composer/pull/2190)) ([@lei9444](https://github.com/lei9444)) +- fix: Moved value field to user tab and removed inline lu from attachment input ([#2194](https://github.com/microsoft/BotFramework-Composer/pull/2194)) ([@tdurnford](https://github.com/tdurnford)) +- fix: load schema files when loading bot project ([#2170](https://github.com/microsoft/BotFramework-Composer/pull/2170)) ([@a-b-r-o-w-n](https://github.com/a-b-r-o-w-n)) +- fix: deployment script, decouple debugging and deployment settings ([#2153](https://github.com/microsoft/BotFramework-Composer/pull/2153)) ([@zidaneymar](https://github.com/zidaneymar)) +- fix: Double scroll bars in dialog's properties pane ([#2163](https://github.com/microsoft/BotFramework-Composer/pull/2163)) ([@alanlong9278](https://github.com/alanlong9278)) +- fix: lg template display wrong in visual & form editor ([#2191](https://github.com/microsoft/BotFramework-Composer/pull/2191)) ([@alanlong9278](https://github.com/alanlong9278)) +- fix: remove edit button in lu all up view ([#2146](https://github.com/microsoft/BotFramework-Composer/pull/2146)) ([@cwhitten](https://github.com/cwhitten)) +- a11y: Use header tag for trigger in visual editor ([#2128](https://github.com/microsoft/BotFramework-Composer/pull/2128)) ([@cwhitten](https://github.com/cwhitten)) +- fix: update lu format link ([#2107](https://github.com/microsoft/BotFramework-Composer/pull/2107)) ([@liweitian](https://github.com/liweitian)) +- fix: resolve known bugs in LU LSP. ([#2098](https://github.com/microsoft/BotFramework-Composer/pull/2098)) ([@cosmicshuai](https://github.com/cosmicshuai)) +- fix: no longer show duplicate lg error notifications ([#2100](https://github.com/microsoft/BotFramework-Composer/pull/2100)) ([@zhixzhan](https://github.com/zhixzhan)) +- fix: replace animated screenshots with a static screenshot ([#2045](https://github.com/microsoft/BotFramework-Composer/pull/2045)) ([@benbrown](https://github.com/benbrown)) +- fix: support copy actions across dialogs ([#2198](https://github.com/microsoft/BotFramework-Composer/pull/2198)) ([@yeze322](https://github.com/yeze322)) +- fix: Default ActivityProcessed to true (bool) ([#2189](https://github.com/microsoft/BotFramework-Composer/pull/2189)) ([@cwhitten](https://github.com/cwhitten)) +- a11y: add name for nodeMenu, arrow and endNode ([#2131](https://github.com/microsoft/BotFramework-Composer/pull/2131)) ([@cwhitten](https://github.com/cwhitten)) +- a11y: add role, name, posinset for paste in edgeMenu ([#2126](https://github.com/microsoft/BotFramework-Composer/pull/2126)) ([@alanlong9278](https://github.com/alanlong9278)) +- fix: fix 'sort()' function of steps and cases in visual editor ([#2166](https://github.com/microsoft/BotFramework-Composer/pull/2166)) ([@yeze322](https://github.com/yeze322)) + +#### Changed + +- style: fix hover state nodes ui ([#2065](https://github.com/microsoft/BotFramework-Composer/pull/2065)) ([@alanlong9278](https://github.com/alanlong9278)) + +#### Other + +- ci: add a11y pr title prefix for accessibility prs ([#2171](https://github.com/microsoft/BotFramework-Composer/pull/2171)) ([@a-b-r-o-w-n](https://github.com/a-b-r-o-w-n)) +- docs: update docs to fix LU file format link ([#2071](https://github.com/microsoft/BotFramework-Composer/pull/2071)) ([@vishwacsena](https://github.com/vishwacsena)) +- chore: merge stable release into master ([@a-b-r-o-w-n](https://github.com/a-b-r-o-w-n)) +- docs: clarify setup ([#2145](https://github.com/microsoft/BotFramework-Composer/pull/2145)) ([@DaraOladapo](https://github.com/DaraOladapo)) +- docs: update dotnet requirement in setup docs ([#2160](https://github.com/microsoft/BotFramework-Composer/pull/2160)) ([@vkacherov](https://github.com/vkacherov)) +- samples: Update HttpRequest sample ([#2161](https://github.com/microsoft/BotFramework-Composer/pull/2161)) ([@luhan2017](https://github.com/luhan2017)) + ### 02-21-2020 #### Added diff --git a/scripts/generate-changelog.js b/scripts/generate-changelog.js index 90ab14515f..aed65cec88 100644 --- a/scripts/generate-changelog.js +++ b/scripts/generate-changelog.js @@ -5,24 +5,26 @@ const PULL_URL = "https://github.com/microsoft/BotFramework-Composer/pull"; const AUTHORS = { "Andy Brown": "a-b-r-o-w-n", + "Ben Brown": "benbrown", "Chris Whitten": "cwhitten", - "Kamran Iqbal": "Kaiqb", "Dong Lei": "boydc2014", + "Hongyang Du (hond)": "Danieladu", + "Kamran Iqbal": "Kaiqb", "Long Alan": "alanlong9278", + "Lu Han": "luhan2017", + "Pooja Nagpal": "p-nagpal", + "Qi Kang": "zidaneymar", + "Shuai Wang": "cosmicshuai", "TJ Durnford": "tdurnford", - leileizhang: "lei9444", - zeye: "yeze322", + "Vishwac Sena Kannan": "vishwacsena", + "Weitian Li": "liweitian", "Zhixiang Zhan": "zhixzhan", - zhixzhan: "zhixzhan", - "Shuai Wang": "cosmicshuai", + leileizhang: "lei9444", liweitian: "liweitian", - "Ben Brown": "benbrown", - "Pooja Nagpal": "p-nagpal", - xieofxie: "xieofxie", - "Lu Han": "luhan2017", VanyLaw: "VanyLaw", - "Hongyang Du (hond)": "Danieladu", - "Weitian Li": "liweitian" + xieofxie: "xieofxie", + zeye: "yeze322", + zhixzhan: "zhixzhan" }; const getLog = () => @@ -37,7 +39,7 @@ const getDate = () => const SECTIONS = { Added: ["feat"], - Fixed: ["fix"], + Fixed: ["fix", "a11y"], Changed: ["refactor", "style"], Other: [] };