diff --git a/Composer/packages/adaptive-form/src/components/fields/IntentField.tsx b/Composer/packages/adaptive-form/src/components/fields/IntentField.tsx index 96e2dcd8d6..9b7922acdc 100644 --- a/Composer/packages/adaptive-form/src/components/fields/IntentField.tsx +++ b/Composer/packages/adaptive-form/src/components/fields/IntentField.tsx @@ -1,26 +1,45 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import React from 'react'; -import { FieldProps, useRecognizerConfig } from '@bfc/extension-client'; +import { DialogInfo, FieldProps, useRecognizerConfig, useShellApi } from '@bfc/extension-client'; import formatMessage from 'format-message'; +import get from 'lodash/get'; +import React from 'react'; import { FieldLabel } from '../FieldLabel'; +const isLuisRecognizer = (dialog: DialogInfo) => { + if (!dialog) return false; + const recognizer = get(dialog, 'content.recognizer', ''); + return typeof recognizer === 'string' && recognizer.endsWith('.lu.qna'); +}; + +const luisEntityHelpUrl = 'https://docs.microsoft.com/en-us/composer/concept-language-understanding#utterances'; + const IntentField: React.FC = (props) => { - const { id, description, uiOptions, value, required, onChange } = props; + const { id, uiOptions, value, required, onChange } = props; const { currentRecognizer } = useRecognizerConfig(); + const { currentDialog } = useShellApi(); const Editor = currentRecognizer?.intentEditor; const label = formatMessage('Trigger phrases'); + let description = props.description; + let helpLink = uiOptions.helpLink; + if (isLuisRecognizer(currentDialog)) { + description = formatMessage( + 'Trigger phrases are inputs from users that will be used to train your LUIS model. This follows .lu file format.' + ); + helpLink = luisEntityHelpUrl; + } + const handleChange = () => { onChange(value); }; return ( - + {Editor ? ( ) : ( diff --git a/Composer/packages/client/src/components/TriggerCreationModal/TriggerCreationModal.tsx b/Composer/packages/client/src/components/TriggerCreationModal/TriggerCreationModal.tsx index 3cc727d1ed..c1a8b0634f 100644 --- a/Composer/packages/client/src/components/TriggerCreationModal/TriggerCreationModal.tsx +++ b/Composer/packages/client/src/components/TriggerCreationModal/TriggerCreationModal.tsx @@ -12,7 +12,7 @@ import { useRecoilValue } from 'recoil'; import { TriggerFormData, TriggerFormDataErrors } from '../../utils/dialogUtil'; import { userSettingsState } from '../../recoilModel/atoms'; -import { dialogsSelectorFamily } from '../../recoilModel'; +import { currentDialogState, dialogsSelectorFamily, localeState, luFilesState } from '../../recoilModel'; import { isRegExRecognizerType, resolveRecognizer$kind } from '../../utils/dialogValidator'; import TelemetryClient from '../../telemetry/TelemetryClient'; @@ -50,6 +50,11 @@ export const TriggerCreationModal: React.FC = (props) const isRegEx = isRegExRecognizerType(dialogFile); const regexIntents = (dialogFile?.content?.recognizer as RegexRecognizer)?.intents ?? []; + const luFiles = useRecoilValue(luFilesState(projectId)); + const locale = useRecoilValue(localeState(projectId)); + const currentDialog = useRecoilValue(currentDialogState({ projectId, dialogId })); + const luFile = luFiles.find((f) => f.id === `${currentDialog?.id}.${locale}`); + const [formData, setFormData] = useState(initialFormData); const [selectedType, setSelectedType] = useState(SDKKinds.OnIntent); @@ -76,7 +81,8 @@ export const TriggerCreationModal: React.FC = (props) setFormData, userSettings, projectId, - dialogId + dialogId, + luFile ); return ( diff --git a/Composer/packages/client/src/components/TriggerCreationModal/resolveTriggerWidget.tsx b/Composer/packages/client/src/components/TriggerCreationModal/resolveTriggerWidget.tsx index 025908beca..0c272c1207 100644 --- a/Composer/packages/client/src/components/TriggerCreationModal/resolveTriggerWidget.tsx +++ b/Composer/packages/client/src/components/TriggerCreationModal/resolveTriggerWidget.tsx @@ -6,7 +6,7 @@ import formatMessage from 'format-message'; import { Label } from 'office-ui-fabric-react/lib/Label'; import { TextField } from 'office-ui-fabric-react/lib/TextField'; import { PlaceHolderSectionName } from '@bfc/indexers/lib/utils/luUtil'; -import { UserSettings, DialogInfo, SDKKinds } from '@bfc/shared'; +import { UserSettings, DialogInfo, SDKKinds, LuFile } from '@bfc/shared'; import { LuEditor, inlineModePlaceholder } from '@bfc/code-editor'; import { TriggerFormData, TriggerFormDataErrors } from '../../utils/dialogUtil'; @@ -22,7 +22,8 @@ export function resolveTriggerWidget( setFormData: (data: TriggerFormData) => void, userSettings: UserSettings, projectId: string, - dialogId: string + dialogId: string, + luFile?: LuFile ) { const isRegEx = isRegExRecognizerType(dialogFile); const isLUISnQnA = isLUISnQnARecognizerType(dialogFile) || isPVARecognizerType(dialogFile); @@ -99,6 +100,7 @@ export function resolveTriggerWidget( editorSettings={userSettings.codeEditor} errorMessage={formData.errors.triggerPhrases} height={225} + luFile={luFile} luOption={{ projectId, fileId: dialogId, diff --git a/Composer/packages/extension-client/src/hooks/useRecognizerConfig.ts b/Composer/packages/extension-client/src/hooks/useRecognizerConfig.ts index 0c0b548e2f..209c3d9218 100644 --- a/Composer/packages/extension-client/src/hooks/useRecognizerConfig.ts +++ b/Composer/packages/extension-client/src/hooks/useRecognizerConfig.ts @@ -64,7 +64,7 @@ export function useRecognizerConfig(): RecognizerSchemaConfig { const recognizerWidgets = plugins.widgets?.recognizer ?? {}; const schemas = Object.entries(plugins.uiSchema) - .filter(([_, uiOptions]) => uiOptions && uiOptions.recognizer) + .filter(([_, uiOptions]) => uiOptions?.recognizer) .map(([$kind, uiOptions]) => { const recognizerOptions = uiOptions?.recognizer as RecognizerOptions; const intentEditor = resolveRecognizerWidget(recognizerOptions.intentEditor, recognizerWidgets); diff --git a/Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx b/Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx index 830fa5fb78..ac3849eadd 100644 --- a/Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx +++ b/Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx @@ -86,11 +86,11 @@ export const LuLabelingMenu = ({ editor, luFile, onMenuToggled, onInsertEntity } [onInsertEntity] ); - const { menuProps } = useLabelingMenuProps('filter', luFile, itemClick, { + const { menuProps, noEntities } = useLabelingMenuProps('filter', luFile, itemClick, { menuHeaderText: formatMessage('Tag entity'), }); - return menuTargetElm ? ( + return menuTargetElm && !noEntities ? (