Skip to content

Commit

Permalink
Merge branch 'main' into notification
Browse files Browse the repository at this point in the history
  • Loading branch information
cwhitten authored Sep 25, 2020
2 parents 2c26f7e + ad90706 commit f777c90
Show file tree
Hide file tree
Showing 49 changed files with 1,203 additions and 863 deletions.
2 changes: 1 addition & 1 deletion Composer/packages/adaptive-form/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
const { createConfig } = require('@bfc/test-utils');

module.exports = createConfig('adaptive-form', 'react', {
coveragePathIgnorePatterns: ['defaultRecognizers.ts', 'defaultRoleSchema.ts', 'defaultUiSchema.ts'],
coveragePathIgnorePatterns: ['defaultRoleSchema.ts', 'defaultUiSchema.ts'],
});
17 changes: 8 additions & 9 deletions Composer/packages/adaptive-form/src/components/FormTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ interface FormTitleProps {
const FormTitle: React.FC<FormTitleProps> = (props) => {
const { description, schema, formData, uiOptions = {} } = props;
const { shellApi, ...shellData } = useShellApi();
const { currentDialog } = shellData;
const recognizers = useRecognizerConfig();
const selectedRecognizer = recognizers.find((r) => r.isSelected(currentDialog?.content?.recognizer));
const { currentRecognizer: selectedRecognizer } = useRecognizerConfig();
// use a ref because the syncIntentName is debounced and we need the most current version to invoke the api
const shell = useRef({
data: shellData,
Expand All @@ -69,12 +67,13 @@ const FormTitle: React.FC<FormTitleProps> = (props) => {
debounce(async (newIntentName?: string, data?: any) => {
if (newIntentName && selectedRecognizer) {
const normalizedIntentName = newIntentName?.replace(/[^a-zA-Z0-9-_]+/g, '');
await selectedRecognizer.renameIntent(
data?.intent,
normalizedIntentName,
shell.current.data,
shell.current.api
);
typeof selectedRecognizer.renameIntent === 'function' &&
(await selectedRecognizer.renameIntent(
data?.intent,
normalizedIntentName,
shell.current.data,
shell.current.api
));
}
}, 400),
[]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React from 'react';
import { FieldProps } from '@bfc/extension-client';
import { JsonEditor } from '@bfc/code-editor';

export const CustomRecognizerField: React.FC<FieldProps> = (props) => {
const { value, onChange } = props;
return (
<JsonEditor
key="customRecognizerField"
height={200}
id="customRecognizerField"
value={value as object}
onChange={onChange}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,29 @@
// Licensed under the MIT License.

import React from 'react';
import { FieldProps, useShellApi, useRecognizerConfig, FieldWidget } from '@bfc/extension-client';
import { FieldProps, useRecognizerConfig } from '@bfc/extension-client';
import formatMessage from 'format-message';
import { SDKKinds } from '@bfc/shared';

import { FieldLabel } from '../FieldLabel';

const IntentField: React.FC<FieldProps> = (props) => {
const { id, description, uiOptions, value, required, onChange } = props;
const { currentDialog } = useShellApi();
const recognizers = useRecognizerConfig();
const { currentRecognizer } = useRecognizerConfig();

const Editor = currentRecognizer?.intentEditor;
const label = formatMessage('Trigger phrases (intent: #{intentName})', { intentName: value });

const handleChange = () => {
onChange(value);
};

const recognizer = recognizers.find((r) => r.isSelected(currentDialog?.content?.recognizer));
let Editor: FieldWidget | undefined;
if (recognizer && recognizer.id === SDKKinds.CrossTrainedRecognizerSet) {
Editor = recognizers.find((r) => r.id === SDKKinds.LuisRecognizer)?.editor;
} else {
Editor = recognizer?.editor;
}
const label = formatMessage('Trigger phrases (intent: #{intentName})', { intentName: value });

return (
<React.Fragment>
<FieldLabel description={description} helpLink={uiOptions?.helpLink} id={id} label={label} required={required} />
{Editor ? (
<Editor {...props} onChange={handleChange} />
) : (
formatMessage('No Editor for {type}', { type: recognizer?.id })
formatMessage('No Editor for {type}', { type: currentRecognizer?.id })
)}
</React.Fragment>
);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/** @jsx jsx */
import { jsx } from '@emotion/core';
import React, { useMemo } from 'react';
import { FieldProps, useShellApi, useRecognizerConfig } from '@bfc/extension-client';
import { MicrosoftIRecognizer } from '@bfc/shared';
import { Dropdown, ResponsiveMode, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import formatMessage from 'format-message';

import { FieldLabel } from '../../FieldLabel';

import { useMigrationEffect } from './useMigrationEffect';
import { mapDropdownOptionToRecognizerSchema } from './mappers';
import { getDropdownOptions } from './getDropdownOptions';

export const RecognizerField: React.FC<FieldProps<MicrosoftIRecognizer>> = (props) => {
const { value, id, label, description, uiOptions, required, onChange } = props;
const { shellApi, ...shellData } = useShellApi();

useMigrationEffect(value, onChange);
const { recognizers: recognizerConfigs, currentRecognizer } = useRecognizerConfig();
const dropdownOptions = useMemo(() => getDropdownOptions(recognizerConfigs), [recognizerConfigs]);

const RecognizerEditor = currentRecognizer?.recognizerEditor;
const widget = RecognizerEditor ? <RecognizerEditor {...props} /> : null;

const submit = (_, option?: IDropdownOption): void => {
if (!option) return;

const recognizerDefinition = mapDropdownOptionToRecognizerSchema(option, recognizerConfigs);

const seedNewRecognizer = recognizerDefinition?.seedNewRecognizer;
const recognizerInstance =
typeof seedNewRecognizer === 'function'
? seedNewRecognizer(shellData, shellApi)
: { $kind: option.key as string, intents: [] }; // fallback to default Recognizer instance;
onChange(recognizerInstance);
};

return (
<React.Fragment>
<FieldLabel description={description} helpLink={uiOptions?.helpLink} id={id} label={label} required={required} />
<Dropdown
data-testid="recognizerTypeDropdown"
label={formatMessage('Recognizer Type')}
options={dropdownOptions}
responsiveMode={ResponsiveMode.large}
selectedKey={currentRecognizer?.id}
onChange={submit}
/>
{widget}
</React.Fragment>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { SDKKinds } from '@bfc/shared';

export const defaultRecognizerOrder = [SDKKinds.CrossTrainedRecognizerSet, SDKKinds.RegexRecognizer];

export const recognizerOrderMap: { [$kind: string]: number } = defaultRecognizerOrder.reduce((result, $kind, index) => {
result[$kind] = index;
return result;
}, {});
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { RecognizerSchema, FallbackRecognizerKey } from '@bfc/extension-client';

import { recognizerOrderMap } from './defaultRecognizerOrder';
import { mapRecognizerSchemaToDropdownOption } from './mappers';

const getRankScore = (r: RecognizerSchema) => {
// Always put disabled recognizer behind. Handle 'disabled' before 'default'.
if (r.disabled) return Number.MAX_VALUE;
// Always put default recognzier ahead.
if (r.default) return -1;
// Put fallback recognizer behind.
if (r.id === FallbackRecognizerKey) return Number.MAX_VALUE - 1;
return recognizerOrderMap[r.id] ?? Number.MAX_VALUE - 1;
};

export const getDropdownOptions = (recognizerConfigs: RecognizerSchema[]) => {
return recognizerConfigs
.filter((r) => !r.disabled)
.sort((r1, r2) => {
return getRankScore(r1) - getRankScore(r2);
})
.map(mapRecognizerSchemaToDropdownOption);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export { RecognizerField } from './RecognizerField';
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { RecognizerSchema } from '@bfc/extension-client';
import { IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';

export const mapDropdownOptionToRecognizerSchema = (option: IDropdownOption, recognizerConfigs: RecognizerSchema[]) => {
return recognizerConfigs.find((r) => r.id === option.key);
};

export const mapRecognizerSchemaToDropdownOption = (recognizerSchema: RecognizerSchema): IDropdownOption => {
const { id, displayName } = recognizerSchema;
const recognizerName = typeof displayName === 'function' ? displayName({}) : displayName;
return { key: id, text: recognizerName || id };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { useShellApi, ChangeHandler } from '@bfc/extension-client';
import { useEffect } from 'react';
import { MicrosoftIRecognizer } from '@bfc/shared';

export const useMigrationEffect = (
recognizer: MicrosoftIRecognizer | undefined,
onChangeRecognizer: ChangeHandler<MicrosoftIRecognizer>
) => {
const { qnaFiles, luFiles, currentDialog, locale } = useShellApi();

useEffect(() => {
// this logic is for handling old bot with `recognizer = undefined'
if (recognizer === undefined) {
const qnaFile = qnaFiles.find((f) => f.id === `${currentDialog.id}.${locale}`);
const luFile = luFiles.find((f) => f.id === `${currentDialog.id}.${locale}`);
if (qnaFile && luFile) {
onChangeRecognizer(`${currentDialog.id}.lu.qna`);
}
}

// transform lu recognizer to crosstrained for old bot
if (recognizer === `${currentDialog.id}.lu`) {
onChangeRecognizer(`${currentDialog.id}.lu.qna`);
}
}, [recognizer]);
};
Loading

0 comments on commit f777c90

Please sign in to comment.