diff --git a/Composer/packages/adaptive-form/src/AdaptiveFormContext.ts b/Composer/packages/adaptive-form/src/AdaptiveFormContext.ts new file mode 100644 index 0000000000..750a5fd925 --- /dev/null +++ b/Composer/packages/adaptive-form/src/AdaptiveFormContext.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { createContext, useContext } from 'react'; +import { JSONSchema7 } from '@bfc/extension-client'; + +interface IAdaptiveFormContext { + focusedTab?: string; + baseSchema: JSONSchema7; + onFocusedTab?: (focusedTab: string) => void; +} + +export const AdaptiveFormContext = createContext({ baseSchema: {} }); +export const useAdaptiveFormContext = () => useContext(AdaptiveFormContext); + +export default AdaptiveFormContext; diff --git a/Composer/packages/adaptive-form/src/components/AdaptiveForm.tsx b/Composer/packages/adaptive-form/src/components/AdaptiveForm.tsx index 32aaf5d8c3..1899521ae8 100644 --- a/Composer/packages/adaptive-form/src/components/AdaptiveForm.tsx +++ b/Composer/packages/adaptive-form/src/components/AdaptiveForm.tsx @@ -8,6 +8,8 @@ import { FormErrors, JSONSchema7, UIOptions } from '@bfc/extension-client'; import ErrorBoundary from 'react-error-boundary'; import formatMessage from 'format-message'; +import AdaptiveFormContext from '../AdaptiveFormContext'; + import { SchemaField } from './SchemaField'; import FormTitle from './FormTitle'; import ErrorInfo from './ErrorInfo'; @@ -25,11 +27,13 @@ export interface AdaptiveFormProps { // eslint-disable-next-line @typescript-eslint/no-explicit-any formData?: any; uiOptions: UIOptions; + focusedTab?: string; + onFocusedTab?: (tab: string) => void; onChange: (value: any) => void; } export const AdaptiveForm: React.FC = function AdaptiveForm(props) { - const { errors, formData, schema, uiOptions, onChange } = props; + const { errors, focusedTab, formData, schema, uiOptions, onChange, onFocusedTab } = props; if (!formData || !schema) { return ( @@ -45,24 +49,26 @@ export const AdaptiveForm: React.FC = function AdaptiveForm(p return ( - onChange({ ...formData, ...newData })} - /> - + + onChange({ ...formData, ...newData })} + /> + + ); }; diff --git a/Composer/packages/adaptive-form/src/components/fields/FieldSets.tsx b/Composer/packages/adaptive-form/src/components/fields/FieldSets.tsx index 29472506b7..946207b84d 100644 --- a/Composer/packages/adaptive-form/src/components/fields/FieldSets.tsx +++ b/Composer/packages/adaptive-form/src/components/fields/FieldSets.tsx @@ -17,7 +17,11 @@ const Fieldsets: React.FC> = (props) => { return ( {fieldsets.map(({ schema, uiOptions, title, defaultExpanded }, key) => ( - + ))} diff --git a/Composer/packages/adaptive-form/src/components/fields/PivotFieldsets.tsx b/Composer/packages/adaptive-form/src/components/fields/PivotFieldsets.tsx new file mode 100644 index 0000000000..8cb471c49a --- /dev/null +++ b/Composer/packages/adaptive-form/src/components/fields/PivotFieldsets.tsx @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import React from 'react'; +import { FieldProps } from '@bfc/extension-client'; +import { IPivotStyles, Pivot, PivotItem, PivotLinkSize } from 'office-ui-fabric-react/lib/components/Pivot'; + +import { getFieldsets } from '../../utils'; +import { useAdaptiveFormContext } from '../../AdaptiveFormContext'; + +import { ObjectField } from './ObjectField'; + +const styles: { tabs: Partial } = { + tabs: { + root: { + display: 'flex', + padding: '0 18px', + }, + link: { + flex: 1, + }, + linkIsSelected: { + flex: 1, + }, + }, +}; + +const PivotFieldsets: React.FC> = (props) => { + const { schema, uiOptions: baseUiOptions, value } = props; + const { focusedTab, onFocusedTab: handleFocusTab } = useAdaptiveFormContext(); + const fieldsets = getFieldsets(schema, baseUiOptions, value); + + const handleTabChange = (item?: PivotItem) => { + if (item?.props.itemKey && handleFocusTab) { + handleFocusTab(item.props.itemKey); + } + }; + + return ( +
+ + {fieldsets.map(({ schema, uiOptions, title, itemKey }) => ( + + + + ))} + +
+ ); +}; + +export { PivotFieldsets }; diff --git a/Composer/packages/adaptive-form/src/components/fields/index.ts b/Composer/packages/adaptive-form/src/components/fields/index.ts index 24246f3a97..66949564b2 100644 --- a/Composer/packages/adaptive-form/src/components/fields/index.ts +++ b/Composer/packages/adaptive-form/src/components/fields/index.ts @@ -13,6 +13,7 @@ export * from './ObjectArrayField'; export * from './ObjectField'; export * from './OneOfField'; export * from './OpenObjectField'; +export * from './PivotFieldsets'; export * from './RecognizerField'; export * from './RegexIntentField'; export * from './QnAActionsField'; diff --git a/Composer/packages/adaptive-form/src/index.ts b/Composer/packages/adaptive-form/src/index.ts index 2b9715fc07..45459b07f2 100644 --- a/Composer/packages/adaptive-form/src/index.ts +++ b/Composer/packages/adaptive-form/src/index.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { AdaptiveForm } from './components'; +export * from './AdaptiveFormContext'; export * from './components'; export * from './utils'; diff --git a/Composer/packages/adaptive-form/src/utils/resolveFieldWidget.ts b/Composer/packages/adaptive-form/src/utils/resolveFieldWidget.ts index 73e86e2a38..4bfbe1dfac 100644 --- a/Composer/packages/adaptive-form/src/utils/resolveFieldWidget.ts +++ b/Composer/packages/adaptive-form/src/utils/resolveFieldWidget.ts @@ -73,7 +73,7 @@ export function resolveFieldWidget( if (schema.additionalProperties) { return DefaultFields.OpenObjectField; } else if (uiOptions?.fieldsets) { - return DefaultFields.Fieldsets; + return uiOptions.pivotFieldsets ? DefaultFields.PivotFieldsets : DefaultFields.Fieldsets; } else { return DefaultFields.ObjectField; } diff --git a/Composer/packages/client/src/pages/design/PropertyEditor.tsx b/Composer/packages/client/src/pages/design/PropertyEditor.tsx index 4c605dc421..03e887bafc 100644 --- a/Composer/packages/client/src/pages/design/PropertyEditor.tsx +++ b/Composer/packages/client/src/pages/design/PropertyEditor.tsx @@ -25,7 +25,8 @@ function resolveBaseSchema(schema: JSONSchema7, $kind: string): JSONSchema7 | un const PropertyEditor: React.FC = () => { const { shellApi, ...shellData } = useShellApi(); - const { currentDialog, data: formData = {}, focusPath, focusedSteps, schemas } = shellData; + const { currentDialog, data: formData = {}, focusPath, focusedSteps, focusedTab, schemas } = shellData; + const { onFocusSteps } = shellApi; const [localData, setLocalData] = useState(formData as MicrosoftAdaptiveDialog); @@ -108,14 +109,20 @@ const PropertyEditor: React.FC = () => { setLocalData(newData); }; + const handleFocusTab = (focusedTab) => { + onFocusSteps(focusedSteps, focusedTab); + }; + return (
); diff --git a/Composer/packages/extension-client/src/types/formSchema.ts b/Composer/packages/extension-client/src/types/formSchema.ts index 29ccd633c9..bebf908b80 100644 --- a/Composer/packages/extension-client/src/types/formSchema.ts +++ b/Composer/packages/extension-client/src/types/formSchema.ts @@ -10,9 +10,10 @@ type UIOptionValue = R | UIOptionFunc; type UIOptionFunc = (data: D) => R; export interface Fieldset { - title: string; + title: UIOptionValue; fields?: string[]; defaultExpanded?: boolean; + itemKey?: string; } export interface UIOptions { @@ -42,6 +43,8 @@ export interface UIOptions { label?: UIOptionValue; /** Set order of fields. Use * for all other fields. */ order?: UIOptionValue<(string | [string, string])[]>; + /** Renders fieldsets in a tabbed view when true */ + pivotFieldsets?: true; /** Placeholder override. If undefined, schema.examples are used. */ placeholder?: UIOptionValue; /** Define ui options on fields that are children of this field. */ diff --git a/Composer/packages/ui-plugins/prompts/src/ExpectedResponsesField.tsx b/Composer/packages/ui-plugins/prompts/src/ExpectedResponsesField.tsx new file mode 100644 index 0000000000..02909aea64 --- /dev/null +++ b/Composer/packages/ui-plugins/prompts/src/ExpectedResponsesField.tsx @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import React from 'react'; +import { FieldLabel, useAdaptiveFormContext } from '@bfc/adaptive-form'; +import { FieldProps, useRecognizerConfig, useShellApi } from '@bfc/extension-client'; +import formatMessage from 'format-message'; +import { LuMetaData, LuType } from '@bfc/shared'; + +const expectedResponsesPlaceholder = () => + formatMessage(`> add some expected user responses: +> - Please remind me to '{itemTitle=buy milk}' +> - remind me to '{itemTitle}' +> - add '{itemTitle}' to my todo list +> +> entity definitions: +> @ ml itemTitle +`); + +const ExpectedResponsesField: React.FC = (props) => { + const { id, description } = props; + const { designerId } = useShellApi(); + const { currentRecognizer } = useRecognizerConfig(); + const { baseSchema: schema } = useAdaptiveFormContext(); + + const { const: $kind } = schema?.properties?.$kind as { const: string }; + + const intentName = new LuMetaData(new LuType($kind).toString(), designerId).toString(); + const label = formatMessage('Expected responses (intent: #{intentName})', { intentName }); + + const Editor = currentRecognizer?.intentEditor; + + return Editor ? ( + + + {}} + /> + + ) : null; +}; + +export { ExpectedResponsesField }; diff --git a/Composer/packages/ui-plugins/prompts/src/PromptField/BotAsks.tsx b/Composer/packages/ui-plugins/prompts/src/PromptField/BotAsks.tsx deleted file mode 100644 index 1ee37f69e4..0000000000 --- a/Composer/packages/ui-plugins/prompts/src/PromptField/BotAsks.tsx +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import React from 'react'; -import { MicrosoftInputDialog } from '@bfc/shared'; -import { SchemaField } from '@bfc/adaptive-form'; - -import { PromptFieldProps } from './types'; - -const BotAsks: React.FC> = (props) => { - const { onChange, getSchema, uiOptions, value, getError, definitions, depth, id } = props; - - return ( - - ); -}; - -export { BotAsks }; diff --git a/Composer/packages/ui-plugins/prompts/src/PromptField/ChoiceInputSettings.tsx b/Composer/packages/ui-plugins/prompts/src/PromptField/ChoiceInputSettings.tsx deleted file mode 100644 index fdc9c78314..0000000000 --- a/Composer/packages/ui-plugins/prompts/src/PromptField/ChoiceInputSettings.tsx +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** @jsx jsx */ -import { jsx, css } from '@emotion/core'; -import React, { Fragment } from 'react'; -import formatMessage from 'format-message'; -import { ChoiceInput, ConfirmInput } from '@bfc/shared'; -import { SchemaField } from '@bfc/adaptive-form'; - -import { PromptFieldProps } from './types'; - -const styles = { - choiceOptions: css` - margin-left: 0; - margin-right: 0; - - label: ChoiceOptions; - `, -}; - -interface ChoiceInputSettingsProps extends PromptFieldProps { - choiceProperty: 'choices' | 'confirmChoices'; -} - -const ChoiceInputSettings: React.FC = (props) => { - const { choiceProperty, getSchema, value, id, onChange, uiOptions, getError, definitions, depth } = props; - - return ( - - {}} - onChange={onChange(choiceProperty)} - onFocus={() => {}} - /> - {}} - onChange={onChange('choiceOptions')} - onFocus={() => {}} - /> - {getSchema('appendChoices') && ( - - )} - - ); -}; - -export { ChoiceInputSettings }; diff --git a/Composer/packages/ui-plugins/prompts/src/PromptField/UserInput.tsx b/Composer/packages/ui-plugins/prompts/src/PromptField/UserInput.tsx deleted file mode 100644 index 3f781c2932..0000000000 --- a/Composer/packages/ui-plugins/prompts/src/PromptField/UserInput.tsx +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** @jsx jsx */ -import { jsx } from '@emotion/core'; -import React, { Fragment } from 'react'; -import { SDKKinds, MicrosoftInputDialog, ChoiceInput, ConfirmInput, LuMetaData, LuType } from '@bfc/shared'; -import { FieldLabel, SchemaField } from '@bfc/adaptive-form'; -import { JSONSchema7, useShellApi, useRecognizerConfig } from '@bfc/extension-client'; -import formatMessage from 'format-message'; - -import { PromptFieldProps } from './types'; -import { ChoiceInputSettings } from './ChoiceInputSettings'; - -const getOptions = (enumSchema: JSONSchema7) => { - if (!enumSchema || !enumSchema.enum || !Array.isArray(enumSchema.enum)) { - return []; - } - - return enumSchema.enum.map((o) => o as string); -}; - -const expectedResponsesPlaceholder = () => - formatMessage(`> add some expected user responses: -> - Please remind me to '{itemTitle=buy milk}' -> - remind me to '{itemTitle}' -> - add '{itemTitle}' to my todo list -> -> entity definitions: -> @ ml itemTitle -`); - -const UserInput: React.FC> = (props) => { - const { onChange, getSchema, value, id, uiOptions, getError, definitions, depth, schema = {} } = props; - const { designerId } = useShellApi(); - const { currentRecognizer } = useRecognizerConfig(); - - const { const: $kind } = (schema?.properties?.$kind as { const: string }) || {}; - const intentName = new LuMetaData(new LuType($kind).toString(), designerId).toString(); - const intentLabel = formatMessage('Expected responses (intent: #{intentName})', { intentName }); - - const Editor = currentRecognizer?.intentEditor; - - return ( - - - {getSchema('outputFormat') && ( - - )} - - {Editor && $kind !== SDKKinds.AttachmentInput && ( - - - {}} /> - - )} - {getSchema('defaultLocale') && ( - - )} - {getSchema('style') && ( - - )} - {value?.$kind === SDKKinds.ChoiceInput && ( - - )} - {value?.$kind === SDKKinds.ConfirmInput && ( - - )} - - ); -}; - -export { UserInput }; diff --git a/Composer/packages/ui-plugins/prompts/src/PromptField/index.tsx b/Composer/packages/ui-plugins/prompts/src/PromptField/index.tsx deleted file mode 100644 index 4e9e3227f9..0000000000 --- a/Composer/packages/ui-plugins/prompts/src/PromptField/index.tsx +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import React from 'react'; -import { Pivot, PivotLinkSize, PivotItem } from 'office-ui-fabric-react/lib/Pivot'; -import get from 'lodash/get'; -import { FieldProps, useShellApi } from '@bfc/extension-client'; -import { SchemaField } from '@bfc/adaptive-form'; -import { PromptTab, PromptTabTitles } from '@bfc/shared'; - -import { tabs } from './styles'; -import { BotAsks } from './BotAsks'; -import { UserInput } from './UserInput'; -import { GetSchema, PromptFieldChangeHandler, InputDialogKeys } from './types'; - -const OTHER_FIELDS: InputDialogKeys[] = [ - 'unrecognizedPrompt', - 'validations', - 'invalidPrompt', - 'defaultValueResponse', - 'maxTurnCount', - 'defaultValue', - 'allowInterruptions', - 'alwaysPrompt', - 'recognizerOptions', -]; - -const PromptField: React.FC = (props) => { - const { shellApi, focusedSteps, focusedTab } = useShellApi(); - - const getSchema: GetSchema = (field) => { - const fieldSchema = get(props.schema, ['properties', field]); - - return fieldSchema; - }; - - const getError = (field) => { - if (typeof props.rawErrors === 'object') { - return props.rawErrors[field]; - } - }; - - const updateField: PromptFieldChangeHandler = (field) => (data) => { - props.onChange({ ...props.value, [field]: data }); - }; - - const handleTabChange = (item?: PivotItem) => { - if (item) { - shellApi.onFocusSteps(focusedSteps, item.props.itemKey); - } - }; - - return ( -
- - - - - - - - - {OTHER_FIELDS.filter((f) => getSchema(f)).map((f) => ( - - ))} - - -
- ); -}; - -export { PromptField }; diff --git a/Composer/packages/ui-plugins/prompts/src/PromptField/styles.ts b/Composer/packages/ui-plugins/prompts/src/PromptField/styles.ts deleted file mode 100644 index 5baeb898ab..0000000000 --- a/Composer/packages/ui-plugins/prompts/src/PromptField/styles.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { IPivotStyles } from 'office-ui-fabric-react/lib/Pivot'; -import { css } from '@emotion/core'; - -export const tabs: Partial = { - root: { - display: 'flex', - padding: '0 18px', - }, - link: { - flex: 1, - }, - linkIsSelected: { - flex: 1, - }, - itemContainer: { - padding: '12px 18px', - }, -}; - -export const settingsFields = css` - display: flex; - flex-wrap: wrap; - position: relative; - align-items: flex-end; - - label: SettingsField; -`; - -export const settingsFieldHalf = css` - flex: 1; - overflow: hidden; - - label: SettingsFieldHalf; - - & + & { - margin-left: 16px; - } -`; diff --git a/Composer/packages/ui-plugins/prompts/src/PromptField/types.ts b/Composer/packages/ui-plugins/prompts/src/PromptField/types.ts deleted file mode 100644 index c1d17a7dd9..0000000000 --- a/Composer/packages/ui-plugins/prompts/src/PromptField/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import { FieldProps, JSONSchema7 } from '@bfc/extension-client'; -import { MicrosoftInputDialog, ChoiceInput, ConfirmInput } from '@bfc/shared'; - -export type InputDialogKeys = keyof MicrosoftInputDialog | keyof ChoiceInput | keyof ConfirmInput; -export type PromptFieldChangeHandler = (field: InputDialogKeys) => (data: any) => void; -export type GetSchema = (field: InputDialogKeys) => JSONSchema7; -export type GetError = (field: InputDialogKeys) => string | string[] | undefined; - -export interface PromptFieldProps extends Omit, 'onChange'> { - onChange: PromptFieldChangeHandler; - getSchema: GetSchema; - getError: GetError; -} diff --git a/Composer/packages/ui-plugins/prompts/src/index.tsx b/Composer/packages/ui-plugins/prompts/src/index.tsx index db3048e914..a47933646d 100644 --- a/Composer/packages/ui-plugins/prompts/src/index.tsx +++ b/Composer/packages/ui-plugins/prompts/src/index.tsx @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +/** @jsx jsx */ +import { jsx } from '@emotion/core'; import React from 'react'; import { FlowWidget, PluginConfig, UIOptions } from '@bfc/extension-client'; import { SDKKinds, getInputType, PromptTab, PromptTabTitles } from '@bfc/shared'; @@ -8,7 +10,26 @@ import { VisualEditorColors as Colors, ListOverview, BorderedDiv, FixedInfo } fr import formatMessage from 'format-message'; import { StringField, JsonField } from '@bfc/adaptive-form'; -import { PromptField } from './PromptField'; +import { ExpectedResponsesField } from './ExpectedResponsesField'; + +const PROMPTS_ORDER = [ + '*', + 'unrecognizedPrompt', + 'validations', + 'invalidPrompt', + 'defaultValueResponse', + 'maxTurnCount', + 'defaultValue', + 'allowInterruptions', + 'alwaysPrompt', + 'recognizerOptions', +]; + +const createPromptFieldSet = (userAskFields: string[]) => [ + { title: PromptTabTitles[PromptTab.BOT_ASKS], itemKey: PromptTab.BOT_ASKS, fields: ['prompt'] }, + { title: PromptTabTitles[PromptTab.USER_INPUT], itemKey: PromptTab.USER_INPUT, fields: userAskFields }, + { title: PromptTabTitles[PromptTab.OTHER], itemKey: PromptTab.OTHER }, +]; const choiceSchema: UIOptions = { order: ['value', 'synonyms', 'actions', '*'], @@ -71,9 +92,9 @@ const generateInputSchema = (inputBody?, inputFooter?): FlowWidget => ({ const PropertyInfo = (data) => data.property ? ( - <> + {data.property} = Input({getInputType(data.$kind)}) - + ) : null; const ChoiceInputBody = (data) => @@ -91,7 +112,7 @@ const ChoiceInputBody = (data) => }} /> ) : ( - <>{data.choices} + {data.choices} ); const ChoiceInputSchema = generateInputSchema(ChoiceInputBody, PropertyInfo); @@ -101,8 +122,10 @@ const config: PluginConfig = { uiSchema: { [SDKKinds.AttachmentInput]: { form: { - field: PromptField, + fieldsets: createPromptFieldSet(['property', 'outputFormat', 'value']), helpLink: 'https://aka.ms/bfc-ask-for-user-input', + order: PROMPTS_ORDER, + pivotFieldsets: true, properties: { prompt: { label: () => formatMessage('Prompt for Attachment'), @@ -118,8 +141,19 @@ const config: PluginConfig = { }, [SDKKinds.ChoiceInput]: { form: { - field: PromptField, + fieldsets: createPromptFieldSet([ + 'property', + 'outputFormat', + 'value', + 'expectedResponses', + 'defaultLocale', + 'style', + 'choices', + 'choiceOptions', + ]), helpLink: 'https://aka.ms/bfc-ask-for-user-input', + order: PROMPTS_ORDER, + pivotFieldsets: true, properties: { prompt: { label: () => formatMessage('Prompt with multi-choice'), @@ -133,14 +167,29 @@ const config: PluginConfig = { placeholder: () => formatMessage('Expression'), ...choiceSchema, }, + expectedResponses: { + additionalField: true, + field: ExpectedResponsesField, + }, }, }, flow: ChoiceInputSchema, }, [SDKKinds.ConfirmInput]: { form: { - field: PromptField, + fieldsets: createPromptFieldSet([ + 'property', + 'outputFormat', + 'value', + 'expectedResponses', + 'defaultLocale', + 'style', + 'confirmChoices', + 'choiceOptions', + ]), helpLink: 'https://aka.ms/bfc-ask-for-user-input', + order: PROMPTS_ORDER, + pivotFieldsets: true, properties: { prompt: { label: () => formatMessage('Prompt for confirmation'), @@ -154,14 +203,20 @@ const config: PluginConfig = { label: () => formatMessage('Confirm Choices'), ...choiceSchema, }, + expectedResponses: { + additionalField: true, + field: ExpectedResponsesField, + }, }, }, flow: BaseInputSchema, }, [SDKKinds.DateTimeInput]: { form: { - field: PromptField, + fieldsets: createPromptFieldSet(['property', 'outputFormat', 'value', 'expectedResponses']), helpLink: 'https://aka.ms/bfc-ask-for-user-input', + order: PROMPTS_ORDER, + pivotFieldsets: true, properties: { prompt: { label: () => formatMessage('Prompt for a date'), @@ -171,14 +226,20 @@ const config: PluginConfig = { helpLink: 'https://aka.ms/bf-composer-docs-ask-input#prompt-settings-and-validation', placeholder: () => formatMessage('Add new validation rule here'), }, + expectedResponses: { + additionalField: true, + field: ExpectedResponsesField, + }, }, }, flow: BaseInputSchema, }, [SDKKinds.NumberInput]: { form: { - field: PromptField, + fieldsets: createPromptFieldSet(['property', 'outputFormat', 'value', 'expectedResponses', 'defaultLocale']), helpLink: 'https://aka.ms/bfc-ask-for-user-input', + order: PROMPTS_ORDER, + pivotFieldsets: true, properties: { prompt: { label: () => formatMessage('Prompt for a number'), @@ -188,14 +249,20 @@ const config: PluginConfig = { helpLink: 'https://aka.ms/bf-composer-docs-ask-input#prompt-settings-and-validation', placeholder: () => formatMessage('Add new validation rule here'), }, + expectedResponses: { + additionalField: true, + field: ExpectedResponsesField, + }, }, }, flow: BaseInputSchema, }, [SDKKinds.TextInput]: { form: { - field: PromptField, + fieldsets: createPromptFieldSet(['property', 'outputFormat', 'value', 'expectedResponses']), helpLink: 'https://aka.ms/bfc-ask-for-user-input', + order: PROMPTS_ORDER, + pivotFieldsets: true, properties: { prompt: { label: () => formatMessage('Prompt for text'), @@ -205,6 +272,10 @@ const config: PluginConfig = { helpLink: 'https://aka.ms/bf-composer-docs-ask-input#prompt-settings-and-validation', placeholder: () => formatMessage('Add new validation rule here'), }, + expectedResponses: { + additionalField: true, + field: ExpectedResponsesField, + }, }, }, flow: BaseInputSchema,