diff --git a/BotProject/CSharp/Schemas/sdk.schema b/BotProject/CSharp/Schemas/sdk.schema index c071385d77..2f1e13ade5 100644 --- a/BotProject/CSharp/Schemas/sdk.schema +++ b/BotProject/CSharp/Schemas/sdk.schema @@ -645,7 +645,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -1033,7 +1033,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -1410,7 +1410,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -1814,7 +1814,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -4333,7 +4333,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -4572,7 +4572,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -6885,7 +6885,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] diff --git a/Composer/packages/extensions/obiformeditor/package.json b/Composer/packages/extensions/obiformeditor/package.json index 04d5914975..ec8d649d0c 100644 --- a/Composer/packages/extensions/obiformeditor/package.json +++ b/Composer/packages/extensions/obiformeditor/package.json @@ -24,7 +24,8 @@ "watch": "yarn build:ts --watch" }, "dependencies": { - "@bfcomposer/react-jsonschema-form": "1.6.2", + "@bfcomposer/react-jsonschema-form": "1.6.5", + "@emotion/core": "^10.0.17", "@uifabric/fluent-theme": "7.1.4", "@uifabric/styling": "7.7.1", "classnames": "^2.2.6", @@ -35,6 +36,7 @@ "lodash.isequal": "^4.5.0", "lodash.merge": "^4.6.1", "lodash.omit": "^4.5.0", + "lodash.pick": "^4.4.0", "nanoid": "^2.0.1", "office-ui-fabric-react": "7.37.1", "react-error-boundary": "^1.2.5", @@ -60,6 +62,7 @@ "@types/lodash.isequal": "^4.5.5", "@types/lodash.merge": "^4.6.6", "@types/lodash.omit": "^4.5.6", + "@types/lodash.pick": "^4.4.6", "@types/lodash.startcase": "^4.4.6", "@types/nanoid": "^1.2.1", "@types/react": "16.9.0", diff --git a/Composer/packages/extensions/obiformeditor/src/Form/FieldTemplate.tsx b/Composer/packages/extensions/obiformeditor/src/Form/FieldTemplate.tsx index 240d051be7..a3fd574153 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/FieldTemplate.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/FieldTemplate.tsx @@ -13,5 +13,5 @@ export default function FieldTemplate(props: FieldTemplateProps) { return null; } - return <>{children}; + return
{children}
; } diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/EditableField.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/EditableField.tsx new file mode 100644 index 0000000000..3cea6036ec --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/EditableField.tsx @@ -0,0 +1,83 @@ +import React, { useState, useEffect } from 'react'; +import { TextField, ITextFieldStyles, ITextFieldProps } from 'office-ui-fabric-react'; +import { NeutralColors } from '@uifabric/fluent-theme'; +import { mergeStyles } from '@uifabric/styling'; + +interface EditableFieldProps extends ITextFieldProps { + onChange: (e: any, newTitle?: string) => void; + styleOverrides?: Partial; + placeholder?: string; + fontSize?: string; +} + +export const EditableField: React.FC = props => { + const { styleOverrides = {}, placeholder, fontSize, onChange, onBlur, value, ...rest } = props; + const [editing, setEditing] = useState(false); + const [hasFocus, setHasFocus] = useState(false); + const [localValue, setLocalValue] = useState(value); + const [hasBeenEdited, setHasBeenEdited] = useState(false); + + useEffect(() => { + if (!hasBeenEdited) { + setLocalValue(value); + } + }, [value]); + + const handleChange = (_e: any, newValue?: string) => { + setLocalValue(newValue); + setHasBeenEdited(true); + onChange(_e, newValue); + }; + + const handleCommit = (e: React.FocusEvent) => { + setHasFocus(false); + setEditing(false); + onBlur && onBlur(e); + }; + + let borderColor: string | undefined = undefined; + + if (!editing) { + borderColor = localValue ? 'transparent' : NeutralColors.gray30; + } + + return ( +
setEditing(true)} onMouseLeave={() => !hasFocus && setEditing(false)}> + setHasFocus(true)} + onChange={handleChange} + autoComplete="off" + {...rest} + /> +
+ ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/BotAsks.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/BotAsks.tsx new file mode 100644 index 0000000000..8708435738 --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/BotAsks.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { FieldProps } from '@bfcomposer/react-jsonschema-form'; +import formatMessage from 'format-message'; + +import { TextareaWidget } from '../../widgets'; + +import { GetSchema, PromptFieldChangeHandler } from './types'; + +interface BotAsksProps extends FieldProps { + onChange: PromptFieldChangeHandler; + getSchema: GetSchema; +} + +export const BotAsks: React.FC = props => { + const { onChange, getSchema, idSchema, formData, formContext } = props; + + return ( + <> + + + ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/ChoiceOptions.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/ChoiceOptions.tsx new file mode 100644 index 0000000000..c760eaec5b --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/ChoiceOptions.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import formatMessage from 'format-message'; +import { IdSchema } from '@bfcomposer/react-jsonschema-form'; +import { JSONSchema6 } from 'json-schema'; +import get from 'lodash.get'; + +import { field } from '../styles'; +import { TextWidget, CheckboxWidget } from '../../../widgets'; +import { FormContext } from '../../../types'; + +interface ChoiceOptionsProps { + idSchema: IdSchema; + schema: JSONSchema6; + formData: IChoiceOption; + onChange: (field: keyof IChoiceOption) => (data: any) => void; + formContext: FormContext; +} + +export const ChoiceOptions: React.FC = props => { + const { schema, formData, onChange, idSchema, formContext } = props; + + const optionSchema = (field: keyof IChoiceOption): JSONSchema6 => { + return get(schema, ['properties', field]); + }; + + return ( + <> +
+ +
+
+ +
+
+ +
+
+ +
+ + ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/Choices.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/Choices.tsx new file mode 100644 index 0000000000..a08f768910 --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/Choices.tsx @@ -0,0 +1,194 @@ +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import React, { useState } from 'react'; +import { JSONSchema6 } from 'json-schema'; +import formatMessage from 'format-message'; +import { TextField, IconButton, IContextualMenuItem } from 'office-ui-fabric-react'; +import { NeutralColors, FontSizes } from '@uifabric/fluent-theme'; + +import { field, choiceItemContainer, choiceItemValue, choiceItemSynonyms } from '../styles'; +import { swap, remove } from '../../../utils'; +// import { FormContext } from '../../../types'; +import { WidgetLabel } from '../../../widgets/WidgetLabel'; +import { EditableField } from '../../EditableField'; + +interface ChoiceItemProps { + index: number; + choice: IChoice; + hasMoveUp: boolean; + hasMoveDown: boolean; + onReorder: (a: number, b: number) => void; + onDelete: (idx: number) => void; + onEdit: (idx: number, value?: IChoice) => void; +} + +interface ChoicesProps { + id: string; + schema: JSONSchema6; + formData?: IChoice[]; + label: string; + onChange: (data: IChoice[]) => void; +} + +const ChoiceItem: React.FC = props => { + const { choice, index, onEdit, hasMoveUp, hasMoveDown, onReorder, onDelete } = props; + + const contextItems: IContextualMenuItem[] = [ + { + key: 'moveUp', + text: 'Move Up', + iconProps: { iconName: 'CaretSolidUp' }, + disabled: !hasMoveUp, + onClick: () => onReorder(index, index - 1), + }, + { + key: 'moveDown', + text: 'Move Down', + iconProps: { iconName: 'CaretSolidDown' }, + disabled: !hasMoveDown, + onClick: () => onReorder(index, index + 1), + }, + { + key: 'remove', + text: 'Remove', + iconProps: { iconName: 'Cancel' }, + onClick: () => onDelete(index), + }, + ]; + + const handleEdit = (field: 'value' | 'synonyms') => (_e: any, val?: string) => { + if (field === 'synonyms') { + onEdit(index, { ...choice, synonyms: val ? val.split(', ') : [] }); + } else { + onEdit(index, { ...choice, value: val }); + } + }; + + return ( +
+
+ +
+
+ +
+
+ +
+
+ ); +}; + +export const Choices: React.FC = props => { + const { onChange, formData = [], id, label } = props; + const [newChoice, setNewChoice] = useState(null); + const [errorMsg, setErrorMsg] = useState(''); + + const handleReorder = (aIdx: number, bIdx: number) => { + onChange(swap(formData, aIdx, bIdx)); + }; + + const handleDelete = (idx: number) => { + onChange(remove(formData, idx)); + }; + + const handleEdit = (idx, val) => { + const choices = [...(formData || [])]; + choices[idx] = val; + onChange(choices); + }; + + const handleNewChoiceEdit = (field: 'value' | 'synonyms') => (_e: any, data?: string) => { + if (field === 'synonyms') { + setNewChoice({ ...newChoice, synonyms: data ? data.split(', ') : [] }); + } else { + setNewChoice({ ...newChoice, value: data }); + } + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key.toLowerCase() === 'enter') { + e.preventDefault(); + + if (newChoice) { + if (newChoice.value) { + onChange([...formData, newChoice]); + setNewChoice(null); + setErrorMsg(''); + } else { + setErrorMsg(formatMessage('value required')); + } + } + } + }; + + return ( + +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ {formData && + formData.map((c, i) => ( + 0} + hasMoveUp={i !== formData.length - 1} + /> + ))} +
+
+ ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/index.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/index.tsx new file mode 100644 index 0000000000..ecea6fd134 --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ChoiceInput/index.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { FieldProps, IdSchema } from '@bfcomposer/react-jsonschema-form'; +import formatMessage from 'format-message'; +import { JSONSchema6 } from 'json-schema'; + +import { PromptFieldChangeHandler, GetSchema } from '../types'; +import { CheckboxWidget } from '../../../widgets'; +import { field } from '../styles'; + +import { Choices } from './Choices'; +import { ChoiceOptions } from './ChoiceOptions'; + +interface ChoiceInputSettingsProps extends FieldProps { + onChange: PromptFieldChangeHandler; + getSchema: GetSchema; +} + +export const ChoiceInputSettings: React.FC = props => { + const { getSchema, formData, idSchema, onChange, formContext } = props; + + const updateChoiceOptions = (field: keyof IChoiceOption) => (data: any) => { + const updater = onChange('choiceOptions'); + updater({ ...formData.choiceOptions, [field]: data }); + }; + + const recognizerOptionsSchema = getSchema('recognizerOptions'); + + return ( + <> + + +
+ +
+
+ onChange('recognizerOptions')({ noValue: data })} + schema={recognizerOptionsSchema.properties ? (recognizerOptionsSchema.properties.noValue as JSONSchema6) : {}} + id={idSchema.recognizerOptions && idSchema.recognizerOptions.__id} + value={formData.recognizerOptions} + label={formatMessage('Recognizer options: no value')} + formContext={formContext} + /> +
+ + ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ConfirmInput.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ConfirmInput.tsx new file mode 100644 index 0000000000..c2d8819dde --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/ConfirmInput.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { FieldProps, IdSchema } from '@bfcomposer/react-jsonschema-form'; +import formatMessage from 'format-message'; + +import { PromptFieldChangeHandler, GetSchema } from './types'; +import { Choices } from './ChoiceInput/Choices'; +import { ChoiceOptions } from './ChoiceInput/ChoiceOptions'; + +interface ConfirmInputSettingsProps extends FieldProps { + onChange: PromptFieldChangeHandler; + getSchema: GetSchema; +} + +export const ConfirmInputSettings: React.FC = props => { + const { getSchema, formData, idSchema, onChange, formContext } = props; + + const updateChoiceOptions = (field: keyof IChoiceOption) => (data: any) => { + const updater = onChange('choiceOptions'); + updater({ ...formData.choiceOptions, [field]: data }); + }; + + return ( + <> + + + + ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/Exceptions.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/Exceptions.tsx new file mode 100644 index 0000000000..4e8ab19b4c --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/Exceptions.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { FieldProps } from '@bfcomposer/react-jsonschema-form'; +import formatMessage from 'format-message'; + +import { TextareaWidget } from '../../widgets'; + +import { Validations } from './Validations'; +import { field } from './styles'; +import { PromptFieldChangeHandler, GetSchema } from './types'; + +interface ExceptionsProps extends FieldProps { + onChange: PromptFieldChangeHandler; + getSchema: GetSchema; +} + +export const Exceptions: React.FC = props => { + const { onChange, getSchema, idSchema, formData, errorSchema } = props; + + return ( + <> +
+ +
+ +
+ +
+
+ +
+ + ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/PromptSettings.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/PromptSettings.tsx new file mode 100644 index 0000000000..4b629c3da8 --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/PromptSettings.tsx @@ -0,0 +1,73 @@ +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import formatMessage from 'format-message'; +import { FieldProps } from '@bfcomposer/react-jsonschema-form'; + +import { TextWidget, SelectWidget, CheckboxWidget } from '../../widgets'; + +import { field, settingsFields, settingsFieldHalf, settingsFieldFull, settingsFieldInline } from './styles'; +import { PromptFieldChangeHandler, GetSchema } from './types'; + +interface PromptSettingsrops extends FieldProps { + onChange: PromptFieldChangeHandler; + getSchema: GetSchema; +} + +export const PromptSettings: React.FC = props => { + const { formData, idSchema, getSchema, onChange, errorSchema } = props; + + const interruptionOptions = (getSchema('allowInterruptions').enum || []).map(o => ({ + label: o as string, + value: o as string, + })); + + return ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/UserAnswers.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/UserAnswers.tsx new file mode 100644 index 0000000000..428e75e9ab --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/UserAnswers.tsx @@ -0,0 +1,101 @@ +import React from 'react'; +import { FieldProps } from '@bfcomposer/react-jsonschema-form'; +import formatMessage from 'format-message'; +import { JSONSchema6 } from 'json-schema'; +import { SDKTypes } from 'shared-menus'; + +import { TextWidget, SelectWidget } from '../../widgets'; + +import { field } from './styles'; +import { GetSchema, PromptFieldChangeHandler } from './types'; +import { ChoiceInputSettings } from './ChoiceInput'; +import { ConfirmInputSettings } from './ConfirmInput'; + +const getOptions = (enumSchema: JSONSchema6) => { + if (!enumSchema || !enumSchema.enum || !Array.isArray(enumSchema.enum)) { + return []; + } + + return enumSchema.enum.map(o => ({ label: o as string, value: o as string })); +}; + +interface UserAnswersProps extends FieldProps { + onChange: PromptFieldChangeHandler; + getSchema: GetSchema; +} + +export const UserAnswers: React.FC = props => { + const { onChange, getSchema, idSchema, formData, errorSchema } = props; + + return ( + <> +
+ +
+ {getSchema('outputFormat') && ( +
+ +
+ )} +
+ +
+ {getSchema('defaultLocale') && ( +
+ +
+ )} + {getSchema('style') && ( +
+ +
+ )} + {formData.$type === SDKTypes.ChoiceInput && } + {formData.$type === SDKTypes.ConfirmInput && ( + + )} + + ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/Validations.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/Validations.tsx new file mode 100644 index 0000000000..939bc6fc41 --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/Validations.tsx @@ -0,0 +1,166 @@ +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import React, { useState } from 'react'; +import formatMessage from 'format-message'; +import { JSONSchema6 } from 'json-schema'; +import { IconButton, IContextualMenuItem } from 'office-ui-fabric-react'; +import { NeutralColors, FontSizes } from '@uifabric/fluent-theme'; + +import { swap, remove } from '../../utils'; +import { ExpressionWidget } from '../../widgets/ExpressionWidget'; +import { FormContext } from '../../types'; + +import { validationItem, validationItemValue, field } from './styles'; + +interface ValidationItemProps { + index: number; + value: string; + hasMoveUp: boolean; + hasMoveDown: boolean; + onReorder: (a: number, b: number) => void; + onDelete: (idx: number) => void; + formContext: FormContext; + schema: JSONSchema6; + onEdit: (idx: number, value?: string) => void; +} + +const ValidationItem: React.FC = props => { + const { value, hasMoveDown, hasMoveUp, onReorder, onDelete, index, formContext, onEdit, schema } = props; + + // This needs to return true to dismiss the menu after a click. + const fabricMenuItemClickHandler = fn => e => { + fn(e); + return true; + }; + + const contextItems: IContextualMenuItem[] = [ + { + key: 'moveUp', + text: 'Move Up', + iconProps: { iconName: 'CaretSolidUp' }, + disabled: !hasMoveUp, + onClick: fabricMenuItemClickHandler(() => onReorder(index, index - 1)), + }, + { + key: 'moveDown', + text: 'Move Down', + iconProps: { iconName: 'CaretSolidDown' }, + disabled: !hasMoveDown, + onClick: fabricMenuItemClickHandler(() => onReorder(index, index + 1)), + }, + { + key: 'remove', + text: 'Remove', + iconProps: { iconName: 'Cancel' }, + onClick: fabricMenuItemClickHandler(() => onDelete(index)), + }, + ]; + + const handleEdit = (_e: any, newVal?: string) => { + onEdit(index, newVal); + }; + + const handleBlur = () => { + if (!value) { + onDelete(index); + } + }; + + return ( +
+
+ +
+ +
+ ); +}; + +interface ValidationsProps { + onChange: (newData: string[]) => void; + formData: string[]; + schema: JSONSchema6; + id: string; + formContext: FormContext; +} + +export const Validations: React.FC = props => { + const { schema, id, formData, formContext } = props; + const [newValidation, setNewValidation] = useState(''); + + const handleChange = (_e: any, newValue?: string) => { + setNewValidation(newValue || ''); + }; + + const submitNewValidation = (e: React.KeyboardEvent) => { + if (e.key.toLowerCase() === 'enter') { + e.preventDefault(); + + if (newValidation) { + props.onChange([...props.formData, newValidation]); + setNewValidation(''); + } + } + }; + + const handleReorder = (aIdx: number, bIdx: number) => { + props.onChange(swap(props.formData, aIdx, bIdx)); + }; + + const handleDelete = (idx: number) => { + props.onChange(remove(props.formData, idx)); + }; + + const handleEdit = (idx, val) => { + const validationsCopy = [...props.formData]; + validationsCopy[idx] = val; + props.onChange(validationsCopy); + }; + + return ( +
+
+ +
+
+ {formData.map((v, i) => ( + + ))} +
+
+ ); +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/index.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/index.tsx new file mode 100644 index 0000000000..7c479b2b90 --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/index.tsx @@ -0,0 +1,62 @@ +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import React from 'react'; +import { FieldProps, IdSchema } from '@bfcomposer/react-jsonschema-form'; +import formatMessage from 'format-message'; +import { Pivot, PivotLinkSize, PivotItem } from 'office-ui-fabric-react'; +import get from 'lodash.get'; + +import { BaseField } from '../BaseField'; + +import { tabs, tabsContainer, settingsContainer } from './styles'; +import { BotAsks } from './BotAsks'; +import { UserAnswers } from './UserAnswers'; +import { Exceptions } from './Exceptions'; +import { PromptSettings } from './PromptSettings'; +import { GetSchema, PromptFieldChangeHandler } from './types'; + +export const PromptField: React.FC = props => { + const promptSettingsIdSchema = ({ __id: props.idSchema.__id + 'promptSettings' } as unknown) as IdSchema; + + const getSchema: GetSchema = field => { + const fieldSchema = get(props.schema, ['properties', field]); + + return fieldSchema; + }; + + const updateField: PromptFieldChangeHandler = field => data => { + props.onChange({ ...props.formData, [field]: data }); + }; + + 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 new file mode 100644 index 0000000000..ed7ca6d68d --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/styles.ts @@ -0,0 +1,79 @@ +import { IPivotStyles } from 'office-ui-fabric-react'; +import { css } from '@emotion/core'; + +export const tabs: Partial = { + root: { + display: 'flex', + padding: '0 18px', + }, + link: { + flex: 1, + }, + linkIsSelected: { + flex: 1, + }, + itemContainer: { + padding: '24px 18px', + }, +}; + +export const tabsContainer = css` + border-bottom: 1px solid #c8c6c4; +`; + +export const validationItem = css` + display: flex; + align-items: center; + padding-left: 10px; + + & + & { + margin-top: 10px; + } +`; + +export const validationItemValue = css` + flex: 1; +`; + +export const field = css` + margin: 10px 0; +`; + +export const settingsContainer = css` + /* padding: 24px 0; */ +`; + +export const settingsFields = css` + display: flex; + flex-wrap: wrap; +`; + +export const settingsFieldFull = css` + flex-basis: 100%; +`; + +export const settingsFieldHalf = css` + flex: 1; + + & + & { + margin-left: 36px; + } +`; + +export const settingsFieldInline = css` + margin: 0; +`; + +export const choiceItemContainer = (align: string = 'center') => css` + display: flex; + align-items: ${align}; +`; + +export const choiceItemValue = css` + width: 180px; +`; + +export const choiceItemSynonyms = css` + flex: 1; + margin-left: 20px; +`; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/types.ts b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/types.ts new file mode 100644 index 0000000000..dd1e9c1191 --- /dev/null +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/PromptField/types.ts @@ -0,0 +1,5 @@ +import { JSONSchema6 } from 'json-schema'; + +export type InputDialogKeys = keyof MicrosoftInputDialog | keyof ChoiceInput | keyof ConfirmInput; +export type PromptFieldChangeHandler = (field: InputDialogKeys) => (data: any) => void; +export type GetSchema = (field: InputDialogKeys) => JSONSchema6; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/RootField.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/RootField.tsx index d21014a72f..a43b5b7d51 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/fields/RootField.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/RootField.tsx @@ -1,14 +1,15 @@ import { startCase, get } from 'lodash'; -import React, { useState } from 'react'; +import React from 'react'; import { FontClassNames, FontWeights } from '@uifabric/styling'; import classnames from 'classnames'; import { JSONSchema6 } from 'json-schema'; -import { NeutralColors, FontSizes } from '@uifabric/fluent-theme'; -import { TextField } from 'office-ui-fabric-react'; -import formatMessage from 'format-message'; +import { FontSizes } from '@uifabric/fluent-theme'; +import formatMessage, { date } from 'format-message'; import { FormContext } from '../types'; +import { EditableField } from './EditableField'; + const overrideDefaults = { collapsable: true, defaultCollapsed: false, @@ -27,60 +28,13 @@ interface RootFieldProps { title?: string; } -interface EditableTitleProps { - title: string; - onChange: (newTitle?: string) => void; -} - -const EditableTitle: React.FC = props => { - const [editing, setEditing] = useState(false); - const [hasFocus, setHasFocus] = useState(false); - const [title, setTitle] = useState(props.title); - - const handleChange = (_e: any, newValue?: string) => { - setTitle(newValue); - props.onChange(newValue); - }; - - const handleCommit = () => { - setHasFocus(false); - setEditing(false); - }; - - return ( -
setEditing(true)} onMouseLeave={() => !hasFocus && setEditing(false)}> - setHasFocus(true)} - onChange={handleChange} - autoComplete="off" - /> -
- ); -}; - export const RootField: React.FC = props => { const { title, name, description, schema, formData, formContext } = props; const { currentDialog, editorSchema, isRoot } = formContext; const sdkOverrides = get(editorSchema, ['content', 'SDKOverrides', formData.$type], overrideDefaults); - const handleTitleChange = (newTitle?: string): void => { + const handleTitleChange = (e: any, newTitle?: string): void => { if (props.onChange) { props.onChange({ ...formData, $designer: { ...formData.$designer, name: newTitle } }); } @@ -89,7 +43,7 @@ export const RootField: React.FC = props => { const getTitle = (): string => { const dialogName = isRoot && currentDialog.displayName; - return dialogName || sdkOverrides.title || title || schema.title || startCase(name); + return formData.$designer.name || dialogName || sdkOverrides.title || title || schema.title || startCase(name); }; const getDescription = (): string => { @@ -99,7 +53,12 @@ export const RootField: React.FC = props => { return (
- + {sdkOverrides.description !== false && (description || schema.description) && (

= props => { {get(formData, '$designer.updatedAt') - ? formatMessage('{ updatedAt, date, short } { updatedAt, time }', { - updatedAt: Date.parse(get(formData, '$designer.updatedAt')), - }) + ? date(Date.parse(get(formData, '$designer.updatedAt')), 'short') : 'N/A'}

diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/index.tsx b/Composer/packages/extensions/obiformeditor/src/Form/fields/index.tsx index c632d84ce2..c7cc59d759 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/fields/index.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/index.tsx @@ -3,6 +3,7 @@ import './styles.css'; export * from './CasesField'; export * from './CodeField'; export * from './JsonField'; +export * from './PromptField'; export * from './RecognizerField'; export * from './RulesField'; export * from './SelectorField'; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/styles.css b/Composer/packages/extensions/obiformeditor/src/Form/styles.css index 44933f3c25..0b4f5fdfc4 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/styles.css +++ b/Composer/packages/extensions/obiformeditor/src/Form/styles.css @@ -6,34 +6,6 @@ */ } -.FieldTemplate { - display: flex; - flex-direction: column; - padding: 0 18px; -} - -.FieldTemplate--inline { - flex-direction: row; - align-items: center; - margin-top: 14px; -} - -.FieldTemplate--inline>label { - margin-right: 8px; - margin-top: 0; -} - -.FieldTemplate--reverse { - flex-direction: row-reverse; - justify-content: flex-end; - align-items: center; -} - -.FieldTemplate--reverse>label { - margin-right: 0; - margin-left: 8px; -} - .FieldTemplateInfo:focus { outline: 1px solid #323130; } diff --git a/Composer/packages/extensions/obiformeditor/src/Form/types.ts b/Composer/packages/extensions/obiformeditor/src/Form/types.ts index 5035604fb0..621a73aa3a 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/types.ts +++ b/Composer/packages/extensions/obiformeditor/src/Form/types.ts @@ -1,4 +1,5 @@ import { WidgetProps, FieldProps, ObjectFieldTemplateProps } from '@bfcomposer/react-jsonschema-form'; +import { JSONSchema6 } from 'json-schema'; import { ShellApi, LuFile, LgFile, DialogInfo } from '../types'; @@ -28,9 +29,12 @@ export interface BFDFieldProps extends FieldProps { formContext: FormContext; } -export interface BFDWidgetProps extends WidgetProps { +export interface BFDWidgetProps extends Partial { + id: string; + schema: JSONSchema6; + onChange: (data: any) => void; formContext: FormContext; - options: { + options?: { label?: string | false; enumOptions?: EnumOption[]; }; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/CheckboxWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/CheckboxWidget.tsx index ca4486c42a..c6aad1347d 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/CheckboxWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/CheckboxWidget.tsx @@ -1,10 +1,11 @@ import React from 'react'; import { Checkbox } from 'office-ui-fabric-react'; -import { WidgetProps } from '@bfcomposer/react-jsonschema-form'; + +import { BFDWidgetProps } from '../types'; import { WidgetLabel } from './WidgetLabel'; -export function CheckboxWidget(props: WidgetProps) { +export function CheckboxWidget(props: BFDWidgetProps) { const { onChange, onBlur, onFocus, value, label, id, schema } = props; const { description } = schema; @@ -14,10 +15,15 @@ export function CheckboxWidget(props: WidgetProps) { id={id} checked={Boolean(value)} onChange={(_, checked?: boolean) => onChange(checked)} - onBlur={() => onBlur(id, Boolean(value))} - onFocus={() => onFocus(id, Boolean(value))} + onBlur={() => onBlur && onBlur(id, Boolean(value))} + onFocus={() => onFocus && onFocus(id, Boolean(value))} />
); } + +CheckboxWidget.defaultProps = { + schema: {}, + options: {}, +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/DateTimeWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/DateTimeWidget.tsx index f4c8f14c85..f4f0e66fcf 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/DateTimeWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/DateTimeWidget.tsx @@ -19,8 +19,8 @@ export function DateTimeWidget(props: BFDWidgetProps) { onBlur(id, value)} - onFocus={() => onFocus(id, value)} + onBlur={() => onBlur && onBlur(id, value)} + onFocus={() => onFocus && onFocus(id, value)} onSelectDate={onSelectDate} value={value ? new Date(value) : undefined} /> diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/DialogSelectWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/DialogSelectWidget.tsx index 83467eee31..0a0e5446f1 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/DialogSelectWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/DialogSelectWidget.tsx @@ -90,8 +90,8 @@ export const DialogSelectWidget: React.FC = props => { onBlur(id, value)} - onFocus={() => onFocus(id, value)} + onBlur={() => onBlur && onBlur(id, value)} + onFocus={() => onFocus && onFocus(id, value)} options={options} selectedKey={comboboxTitle ? 'customTitle' : value || ''} onItemClick={handleChange} diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/ExpressionWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/ExpressionWidget.tsx index 0bc8588d69..506c3f3976 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/ExpressionWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/ExpressionWidget.tsx @@ -4,6 +4,7 @@ import { TextField, ITextFieldProps } from 'office-ui-fabric-react'; import { JSONSchema6 } from 'json-schema'; import { FormContext } from '../types'; +import { EditableField } from '../fields/EditableField'; import { WidgetLabel } from './WidgetLabel'; @@ -24,13 +25,15 @@ const getErrorMessage = () => interface ExpresionWidgetProps extends ITextFieldProps { formContext: FormContext; - rawErrors: string[]; + rawErrors?: string[]; schema: JSONSchema6; onChange: (event: React.FormEvent, newValue?: string) => void; + /** Set to true to display as inline text that is editable on hover */ + editable?: boolean; } export const ExpressionWidget: React.FC = props => { - const { rawErrors, formContext, schema, id, label, ...rest } = props; + const { rawErrors, formContext, schema, id, label, editable, ...rest } = props; const { shellApi } = formContext; const { description } = schema; @@ -52,10 +55,12 @@ export const ExpressionWidget: React.FC = props => { return ''; }; + const Field = editable ? EditableField : TextField; + return ( <> - + ); }; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx index 8571b3affa..36c2d41352 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/IntentWidget.tsx @@ -91,9 +91,9 @@ export const IntentWidget: React.FC = props => { onBlur(id, value)} + onBlur={() => onBlur && onBlur(id, value)} onChange={handleChange} - onFocus={() => onFocus(id, value)} + onFocus={() => onFocus && onFocus(id, value)} options={options} selectedKey={value || null} responsiveMode={ResponsiveMode.large} diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/RadioWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/RadioWidget.tsx index c06acb98ca..1ac321275d 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/RadioWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/RadioWidget.tsx @@ -20,9 +20,9 @@ export function RadioWidget(props: RadioWidgetProps) { onBlur(id, value)} + onBlur={() => onBlur && onBlur(id, value)} onChange={(e, option?: IChoiceGroupOption) => onChange(option ? option.key : null)} - onFocus={() => onFocus(id, value)} + onFocus={() => onFocus && onFocus(id, value)} options={choices} selectedKey={value} /> diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/SelectWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/SelectWidget.tsx index 122c5d0f59..8b07a6aa8d 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/SelectWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/SelectWidget.tsx @@ -23,9 +23,9 @@ export const SelectWidget: React.FunctionComponent = props => onBlur(id, value)} + onBlur={() => onBlur && onBlur(id, value)} onChange={handleChange} - onFocus={() => onFocus(id, value)} + onFocus={() => onFocus && onFocus(id, value)} options={options.enumOptions.map(o => ({ key: o.value, text: o.label, @@ -39,3 +39,9 @@ export const SelectWidget: React.FunctionComponent = props => ); }; + +SelectWidget.defaultProps = { + schema: {}, + onBlur: () => {}, + onFocus: () => {}, +}; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/TextWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/TextWidget.tsx index fba7a4d9df..7c06a0e70c 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/TextWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/TextWidget.tsx @@ -46,7 +46,7 @@ export function TextWidget(props: BFDWidgetProps) { onChange(newValue); // need to allow form data to propagate before flushing to state - setTimeout(() => onBlur(id, value)); + setTimeout(() => onBlur && onBlur(id, value)); }; const step = type === 'integer' ? 1 : 0.1; @@ -74,9 +74,9 @@ export function TextWidget(props: BFDWidgetProps) { id, value, autoComplete: 'off', - onBlur: () => onBlur(id, value), + onBlur: () => onBlur && onBlur(id, value), onChange: (_, newValue?: string) => onChange(newValue), - onFocus: () => onFocus(id, value), + onFocus: () => onFocus && onFocus(id, value), placeholder: placeholderText, readOnly: Boolean(schema.const) || readonly, }; @@ -103,4 +103,7 @@ export function TextWidget(props: BFDWidgetProps) { TextWidget.defaultProps = { schema: {}, + options: {}, + onBlur: () => {}, + onFocus: () => {}, }; diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/TextareaWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/TextareaWidget.tsx index 8d388d5e78..d21e1deccf 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/TextareaWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/TextareaWidget.tsx @@ -1,10 +1,11 @@ import React from 'react'; import { TextField } from 'office-ui-fabric-react'; -import { WidgetProps } from '@bfcomposer/react-jsonschema-form'; + +import { BFDWidgetProps } from '../types'; import { WidgetLabel } from './WidgetLabel'; -export const TextareaWidget: React.FunctionComponent = props => { +export const TextareaWidget: React.FunctionComponent = props => { const { onBlur, onChange, onFocus, readonly, value, placeholder, schema, id, disabled, label } = props; const { description, examples = [] } = schema; @@ -21,9 +22,9 @@ export const TextareaWidget: React.FunctionComponent = props => { disabled={disabled} id={id} multiline - onBlur={() => onBlur(id, value)} + onBlur={() => onBlur && onBlur(id, value)} onChange={(_, newValue?: string) => onChange(newValue)} - onFocus={() => onFocus(id, value)} + onFocus={() => onFocus && onFocus(id, value)} placeholder={placeholderText} readOnly={readonly} value={value} @@ -39,4 +40,7 @@ export const TextareaWidget: React.FunctionComponent = props => { TextareaWidget.defaultProps = { schema: {}, + options: {}, + onBlur: () => {}, + onFocus: () => {}, }; diff --git a/Composer/packages/extensions/obiformeditor/src/schema/appschema.ts b/Composer/packages/extensions/obiformeditor/src/schema/appschema.ts index 8b0fb8c6b9..f46e798432 100644 --- a/Composer/packages/extensions/obiformeditor/src/schema/appschema.ts +++ b/Composer/packages/extensions/obiformeditor/src/schema/appschema.ts @@ -1,4 +1,14 @@ import { JSONSchema6 } from 'json-schema'; +import { SDKTypes } from 'shared-menus'; + +export const PROMPT_TYPES = [ + SDKTypes.AttachmentInput, + SDKTypes.ChoiceInput, + SDKTypes.ConfirmInput, + SDKTypes.DateTimeInput, + SDKTypes.NumberInput, + SDKTypes.TextInput, +]; export const FIELDS_TO_HIDE = [ '$id', @@ -259,7 +269,7 @@ export const appschema: JSONSchema6 = { type: 'integer', title: 'Max Turn Count', description: 'The max retry count for this prompt.', - default: 2147483647, + default: 3, examples: [3], }, validations: { @@ -575,7 +585,7 @@ export const appschema: JSONSchema6 = { type: 'integer', title: 'Max Turn Count', description: 'The max retry count for this prompt.', - default: 2147483647, + default: 3, examples: [3], }, validations: { @@ -641,11 +651,11 @@ export const appschema: JSONSchema6 = { title: 'Value', description: 'the value to return when selected.', }, - action: { - title: 'Action', - description: 'Card action for the choice', - type: 'object', - }, + // action: { + // title: 'Action', + // description: 'Card action for the choice', + // type: 'object', + // }, synonyms: { type: 'array', title: 'Synonyms', @@ -840,7 +850,7 @@ export const appschema: JSONSchema6 = { type: 'integer', title: 'Max Turn Count', description: 'The max retry count for this prompt.', - default: 2147483647, + default: 3, examples: [3], }, validations: { @@ -933,31 +943,29 @@ export const appschema: JSONSchema6 = { }, confirmChoices: { type: 'array', - items: [ - { - type: 'object', - properties: { - value: { + items: { + type: 'object', + properties: { + value: { + type: 'string', + title: 'Value', + description: 'the value to return when selected.', + }, + // action: { + // title: 'Action', + // description: 'Card action for the choice', + // type: 'object', + // }, + synonyms: { + type: 'array', + title: 'Synonyms', + description: 'The list of synonyms to recognize in addition to the value. This is optional.', + items: { type: 'string', - title: 'Value', - description: 'the value to return when selected.', - }, - action: { - title: 'Action', - description: 'Card action for the choice', - type: 'object', - }, - synonyms: { - type: 'array', - title: 'Synonyms', - description: 'The list of synonyms to recognize in addition to the value. This is optional.', - items: { - type: 'string', - }, }, }, }, - ], + }, }, }, additionalProperties: false, @@ -1165,7 +1173,7 @@ export const appschema: JSONSchema6 = { type: 'integer', title: 'Max Turn Count', description: 'The max retry count for this prompt.', - default: 2147483647, + default: 3, examples: [3], }, validations: { @@ -3127,7 +3135,7 @@ export const appschema: JSONSchema6 = { type: 'integer', title: 'Max Turn Count', description: 'The max retry count for this prompt.', - default: 2147483647, + default: 3, examples: [3], }, validations: { @@ -3318,7 +3326,7 @@ export const appschema: JSONSchema6 = { type: 'integer', title: 'Max Turn Count', description: 'The max retry count for this prompt.', - default: 2147483647, + default: 3, examples: [3], }, validations: { @@ -5081,7 +5089,7 @@ export const appschema: JSONSchema6 = { type: 'integer', title: 'Max Turn Count', description: 'The max retry count for this prompt.', - default: 2147483647, + default: 3, examples: [3], }, validations: { diff --git a/Composer/packages/extensions/obiformeditor/src/schema/types.d.ts b/Composer/packages/extensions/obiformeditor/src/schema/types.d.ts index 5046376262..752c893caf 100644 --- a/Composer/packages/extensions/obiformeditor/src/schema/types.d.ts +++ b/Composer/packages/extensions/obiformeditor/src/schema/types.d.ts @@ -14,6 +14,8 @@ interface BaseSchema { /* Union of components which implement the IActivityTemplate interface */ type MicrosoftIActivityTemplate = string; +type MicrosoftIExpression = string; + interface IBaseDialog extends BaseSchema { /** This is that will be passed in as InputProperty and also set as the OutputProperty */ property?: string; @@ -23,15 +25,6 @@ interface IBaseDialog extends BaseSchema { outputProperty?: string; } -declare enum ListStyle { - None = 'None', - Auto = 'Auto', - Inline = 'Inline', - List = 'List', - SuggestedAction = 'SuggestedAction', - HeroCard = 'HeroCard', -} - interface OpenObject { [x: string]: T; } @@ -46,53 +39,116 @@ interface IChoice { synonyms?: string[]; } +type IListStyle = 'None' | 'Auto' | 'Inline' | 'List' | 'SuggestedAction' | 'HeroCard'; + +interface IChoiceOption { + /** Character used to separate individual choices when there are more than 2 choices */ + inlineSeparator?: string; + /** Separator inserted between the choices when their are only 2 choices */ + inlineOr?: string; + /** Separator inserted between the last 2 choices when their are more than 2 choices. */ + inlineOrMore?: string; + /** If true, inline and list style choices will be prefixed with the index of the choice. */ + includeNumbers?: boolean; +} + +interface IConfirmChoice { + /** the value to return when selected. */ + value?: string; + /** Card action for the choice */ + action?: OpenObject; + /** The list of synonyms to recognize in addition to the value. This is optional. */ + synonyms?: string[]; +} + +interface IRecognizerOption { + /** If true, the choices value field will NOT be search over */ + noValue?: boolean; +} + /** - * Steps + * Inputs */ -/** This represents a dialog which gathers a choice responses */ -interface ChoiceInput extends IBaseDialog { +interface InputDialog extends BaseSchema { + /** (Optional) id for the dialog */ + id: string; /** The message to send to as prompt for this input. */ - prompt?: MicrosoftIActivityTemplate; - /** The message to send to prompt again. */ - retryPrompt?: MicrosoftIActivityTemplate; - /** The message to send to when then input was not recognized or not valid for the input type. */ - invalidPrompt?: MicrosoftIActivityTemplate; - /** The kind of choice list style to generate */ - style?: ListStyle; + prompt: MicrosoftIActivityTemplate; + /** The message to send if the last input is not recognized. */ + unrecognizedPrompt: MicrosoftIActivityTemplate; + /** The message to send to when then input was not valid for the input type. */ + invalidPrompt: MicrosoftIActivityTemplate; + /** The message to send to when max turn count has been exceeded and the default value is selected as the value. */ + defaultValueResponse: MicrosoftIActivityTemplate; + /** The max retry count for this prompt. */ + maxTurnCount: number; + /** Expressions to validate an input. */ + validations: MicrosoftIExpression[]; + /** The expression that you evaluated for input. */ + value: MicrosoftIExpression; + /** Property that this input dialog is bound to */ + property: MicrosoftIExpression; + /** Value to return if the value expression can't be evaluated. */ + defaultValue: MicrosoftIExpression; + /** If set to true this will always prompt the user regardless if you already have the value or not. */ + alwaysPrompt: boolean; + /** Always will always consult parent dialogs first, never will not consult parent dialogs, notRecognized will consult parent only when it's not recognized */ + allowInterruptions: 'always' | 'never' | 'notRecognized'; +} - choicesProperty?: string; +/** This represents a dialog which gathers an attachment such as image or music */ +interface AttachmentInput extends Partial { + /** The attachment output format. */ + outputFormat?: 'all' | 'first'; +} +/** This represents a dialog which gathers a choice responses */ +interface ChoiceInput extends Partial { + /** The output format. */ + outputFormat?: 'value' | 'index'; choices?: IChoice[]; + /** Compose an output activity containing a set of choices */ + appendChoices?: boolean; + /** The prompts default locale that should be recognized. */ + defaultLocale?: string; + /** The kind of choice list style to generate */ + style?: IListStyle; + choiceOptions?: IChoiceOption; + recognizerOptions?: IRecognizerOption; } -/** A dialog step that executes custom code */ -interface CodeStep extends IBaseDialog { - codeHandler: string; +/** This represents a dialog which gathers a yes/no style responses */ +interface ConfirmInput extends Partial { + outputFormat: undefined; + /** The prompts default locale that should be recognized. */ + defaultLocale?: string; + /** The kind of choice list style to generate */ + style?: IListStyle; + choiceOptions?: IChoiceOption; + confirmChoices?: IConfirmChoice[]; } -/** This represents a dialog which gathers a yes/no style responses */ -interface ConfirmInput extends IBaseDialog { - /** The message to send to as prompt for this input. */ - prompt?: MicrosoftIActivityTemplate; - /** The message to send to prompt again. */ - retryPrompt?: MicrosoftIActivityTemplate; - /** The message to send to when then input was not recognized or not valid for the input type. */ - invalidPrompt?: MicrosoftIActivityTemplate; +interface DateTimeInput extends Partial { + outputFormat: undefined; + /** The prompts default locale that should be recognized. */ + defaultLocale?: string; +} +interface NumberInput extends Partial { + /** The output format. */ + outputFormat?: 'float' | 'integer'; + /** The prompts default locale that should be recognized. */ + defaultLocale?: string; } /** This represents a dialog which gathers a text from the user */ -interface TextInput extends IBaseDialog { - /** The message to send to as prompt for this input. */ - prompt?: MicrosoftIActivityTemplate; - /** The message to send to prompt again. */ - retryPrompt?: MicrosoftIActivityTemplate; - /** The message to send to when then input was not recognized or not valid for the input type. */ - invalidPrompt?: MicrosoftIActivityTemplate; - /** A regular expression pattern which must match */ - pattern?: string; +interface TextInput extends Partial { + /** The output format. */ + outputFormat?: 'none' | 'trim' | 'lowercase' | 'uppercase'; } +type MicrosoftInputDialog = AttachmentInput | ChoiceInput | ConfirmInput | DateTimeInput | NumberInput | TextInput; + /** * Recognizers */ diff --git a/Composer/packages/extensions/obiformeditor/src/schema/uischema.ts b/Composer/packages/extensions/obiformeditor/src/schema/uischema.ts index 571bd3c6d8..8eca0bdb81 100644 --- a/Composer/packages/extensions/obiformeditor/src/schema/uischema.ts +++ b/Composer/packages/extensions/obiformeditor/src/schema/uischema.ts @@ -1,20 +1,19 @@ +import { SDKTypes } from 'shared-menus'; +import { UiSchema } from '@bfcomposer/react-jsonschema-form'; + +import { PROMPT_TYPES } from './appschema'; + const globalHidden = ['property', 'inputBindings', 'outputBinding', 'id', 'tags']; -const activityFields = { - prompt: { - 'ui:widget': 'TextareaWidget', - }, - unrecognizedPrompt: { - 'ui:widget': 'TextareaWidget', - }, - invalidPrompt: { - 'ui:widget': 'TextareaWidget', - }, - 'ui:hidden': ['id', 'tags', 'value', 'inputBindings', 'outputBinding'], -}; +const promptFieldsSchemas = PROMPT_TYPES.reduce((schemas, type) => { + schemas[type] = { + 'ui:field': 'PromptField', + }; + return schemas; +}, {}); -export const uiSchema = { - 'Microsoft.AdaptiveDialog': { +export const uiSchema: { [key in SDKTypes]?: UiSchema } = { + [SDKTypes.AdaptiveDialog]: { recognizer: { 'ui:field': 'RecognizerField', }, @@ -27,19 +26,13 @@ export const uiSchema = { 'ui:order': ['property', 'outputBinding', 'recognizer', 'events', '*'], 'ui:hidden': ['autoEndDialog', 'generator', ...globalHidden], }, - 'Microsoft.BeginDialog': { + [SDKTypes.BeginDialog]: { dialog: { 'ui:widget': 'DialogSelectWidget', }, 'ui:hidden': ['inputBindings', 'outputBinding'], }, - 'Microsoft.CodeStep': { - codeHandler: { - 'ui:field': 'CodeField', - }, - 'ui:hidden': [...globalHidden], - }, - 'Microsoft.ConditionalSelector': { + [SDKTypes.ConditionalSelector]: { ifFalse: { 'ui:field': 'SelectorField', }, @@ -48,30 +41,30 @@ export const uiSchema = { }, 'ui:hidden': [...globalHidden], }, - 'Microsoft.EditActions': { + [SDKTypes.EditActions]: { actions: { 'ui:field': 'StepsField', }, }, - 'Microsoft.Foreach': { + [SDKTypes.Foreach]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['listProperty', 'valueProperty', 'indexProperty', 'actions', '*'], }, - 'Microsoft.ForeachPage': { + [SDKTypes.ForeachPage]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['listProperty', 'pageSize', 'valueProperty', 'actions', '*'], }, - 'Microsoft.HttpRequest': { + [SDKTypes.HttpRequest]: { body: { 'ui:field': 'JsonField', }, 'ui:order': ['method', 'url', 'body', 'property', 'responseTypes', 'headers', '*'], }, - 'Microsoft.IfCondition': { + [SDKTypes.IfCondition]: { actions: { 'ui:field': 'StepsField', }, @@ -80,73 +73,63 @@ export const uiSchema = { }, 'ui:hidden': [...globalHidden], }, - 'Microsoft.IfPropertyRule': { - conditionals: { - items: { - events: { - 'ui:field': 'RulesField', - }, - }, - }, - 'ui:hidden': [...globalHidden], - }, - 'Microsoft.OnActivity': { + [SDKTypes.OnActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnBeginDialog': { + [SDKTypes.OnBeginDialog]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnConversationUpdateActivity': { + [SDKTypes.OnConversationUpdateActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnDialogEvent': { + [SDKTypes.OnDialogEvent]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['events', 'constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnEndOfConversationActivity': { + [SDKTypes.OnEndOfConversationActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnEvent': { + [SDKTypes.OnEvent]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnEventActivity': { + [SDKTypes.OnEventActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnHandoffActivity': { + [SDKTypes.OnHandoffActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnIntent': { + [SDKTypes.OnIntent]: { intent: { 'ui:widget': 'IntentWidget', }, @@ -156,172 +139,62 @@ export const uiSchema = { 'ui:order': ['intent', 'constraint', 'entities', '*'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnInvokeActivity': { + [SDKTypes.OnInvokeActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnMessageActivity': { + [SDKTypes.OnMessageActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnMessageDeleteActivity': { + [SDKTypes.OnMessageDeleteActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnMessageReactionActivity': { + [SDKTypes.OnMessageReactionActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnMessageUpdateActivity': { + [SDKTypes.OnMessageUpdateActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnTypingActivity': { + [SDKTypes.OnTypingActivity]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.OnUnknownIntent': { + [SDKTypes.OnUnknownIntent]: { actions: { 'ui:field': 'StepsField', }, 'ui:order': ['constraint', '*', 'actions'], 'ui:hidden': [...globalHidden], }, - 'Microsoft.MostSpecificSelector': { + [SDKTypes.MostSpecificSelector]: { selector: { 'ui:field': 'SelectorField', }, 'ui:hidden': [...globalHidden], }, - 'Microsoft.TextInput': { - prompt: { - 'ui:widget': 'TextareaWidget', - }, - unrecognizedPrompt: { - 'ui:widget': 'TextareaWidget', - }, - invalidPrompt: { - 'ui:widget': 'TextareaWidget', - }, - 'ui:order': [ - 'prompt', - 'property', - 'outputFormat', - 'validations', - 'unrecognizedPrompt', - 'invalidPrompt', - 'maxTurnCount', - 'value', - 'defaultValue', - '*', - ], - }, - 'Microsoft.NumberInput': { - prompt: { - 'ui:widget': 'TextareaWidget', - }, - unrecognizedPrompt: { - 'ui:widget': 'TextareaWidget', - }, - invalidPrompt: { - 'ui:widget': 'TextareaWidget', - }, - 'ui:order': [ - 'prompt', - 'property', - 'outputFormat', - 'validations', - 'unrecognizedPrompt', - 'invalidPrompt', - 'maxTurnCount', - 'value', - 'defaultValue', - '*', - ], - }, - 'Microsoft.ConfirmInput': { - prompt: { - 'ui:widget': 'TextareaWidget', - }, - unrecognizedPrompt: { - 'ui:widget': 'TextareaWidget', - }, - invalidPrompt: { - 'ui:widget': 'TextareaWidget', - }, - 'ui:order': [ - 'prompt', - 'property', - 'style', - 'defaultLocale', - 'validations', - 'unrecognizedPrompt', - 'invalidPrompt', - 'maxTurnCount', - 'value', - 'defaultValue', - '*', - ], - // ConfirmInput defaults to YES/NO. using confirmchoices is complex - // - must provide yes/no in special format along with alternatives that have to be handled - // TODO: Implement confirmChoices-specific widget with appropriate business events. - 'ui:hidden': ['confirmChoices'], - }, - 'Microsoft.ChoiceInput': { - prompt: { - 'ui:widget': 'TextareaWidget', - }, - unrecognizedPrompt: { - 'ui:widget': 'TextareaWidget', - }, - invalidPrompt: { - 'ui:widget': 'TextareaWidget', - }, - choices: { - items: { - value: { - 'ui:options': { - label: false, - }, - }, - }, - }, - ...activityFields, - 'ui:order': [ - 'prompt', - 'property', - 'outputFormat', - 'style', - 'defaultLocale', - 'choices', - 'validations', - 'unrecognizedPrompt', - 'invalidPrompt', - 'maxTurnCount', - 'value', - 'defaultValue', - '*', - ], - }, - 'Microsoft.OAuthInput': { + [SDKTypes.OAuthInput]: { prompt: { 'ui:widget': 'TextareaWidget', }, @@ -333,42 +206,13 @@ export const uiSchema = { }, 'ui:order': ['connectionName', '*'], }, - 'Microsoft.AttachmentInput': { - prompt: { - 'ui:widget': 'TextareaWidget', - }, - unrecognizedPrompt: { - 'ui:widget': 'TextareaWidget', - }, - invalidPrompt: { - 'ui:widget': 'TextareaWidget', - }, - 'ui:order': [ - 'prompt', - 'property', - 'outputFormat', - 'validations', - 'unrecognizedPrompt', - 'invalidPrompt', - 'maxTurnCount', - 'value', - 'defaultValue', - '*', - ], - }, - 'Microsoft.ReplaceDialog': { + [SDKTypes.ReplaceDialog]: { dialog: { 'ui:widget': 'DialogSelectWidget', }, 'ui:hidden': [...globalHidden], }, - 'Microsoft.Rule': { - actions: { - 'ui:field': 'StepsField', - }, - 'ui:hidden': [...globalHidden], - }, - 'Microsoft.SwitchCondition': { + [SDKTypes.SwitchCondition]: { cases: { 'ui:field': 'CasesField', }, @@ -377,24 +221,11 @@ export const uiSchema = { }, 'ui:hidden': [...globalHidden], }, - 'Microsoft.SendActivity': { + [SDKTypes.SendActivity]: { activity: { 'ui:field': 'LgEditorField', }, 'ui:hidden': [...globalHidden], }, - 'Microsoft.DateTimeInput': { - prompt: { - 'ui:widget': 'TextareaWidget', - }, - unrecognizedPrompt: { - 'ui:widget': 'TextareaWidget', - }, - invalidPrompt: { - 'ui:widget': 'TextareaWidget', - }, - defaultValue: { - 'ui:widget': 'DateTimeWidget', - }, - }, + ...promptFieldsSchemas, }; diff --git a/Composer/packages/server/schemas/sdk.schema b/Composer/packages/server/schemas/sdk.schema index 175312c93c..7749e87e8a 100644 --- a/Composer/packages/server/schemas/sdk.schema +++ b/Composer/packages/server/schemas/sdk.schema @@ -645,7 +645,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -1033,7 +1033,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -1410,7 +1410,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -1814,7 +1814,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -4333,7 +4333,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -4572,7 +4572,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] @@ -6885,7 +6885,7 @@ "type": "integer", "title": "Max Turn Count", "description": "The max retry count for this prompt.", - "default": 2147483647, + "default": 3, "examples": [ 3 ] diff --git a/Composer/yarn.lock b/Composer/yarn.lock index 81a6d472b7..fef239d2d5 100644 --- a/Composer/yarn.lock +++ b/Composer/yarn.lock @@ -1352,6 +1352,13 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.5.5": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.2.tgz#c3d6e41b304ef10dcf13777a33e7694ec4a9a6dd" + integrity sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg== + dependencies: + regenerator-runtime "^0.13.2" + "@babel/template@^7.0.0", "@babel/template@^7.1.0", "@babel/template@^7.2.2", "@babel/template@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.0.tgz#12474e9c077bae585c5d835a95c0b0b790c25c8b" @@ -1430,10 +1437,10 @@ resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/monaco-editor/-/@bfcomposer/monaco-editor-0.17.4.tgz#bc2d75c48fcbee1121ee4c168c508de81bcd2ee9" integrity sha1-vC11xI/L7hEh7kwWjFCN6BvNLuk= -"@bfcomposer/react-jsonschema-form@1.6.2": - version "1.6.2" - resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/react-jsonschema-form/-/@bfcomposer/react-jsonschema-form-1.6.2.tgz#0615d0b8d84c180d58386489dee3de6370fd47f0" - integrity sha1-BhXQuNhMGA1YOGSJ3uPeY3D9R/A= +"@bfcomposer/react-jsonschema-form@1.6.5": + version "1.6.5" + resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/react-jsonschema-form/-/@bfcomposer/react-jsonschema-form-1.6.5.tgz#afd08049270eb00afe305cc756fd200011e12b4c" + integrity sha1-r9CASScOsAr+MFzHVv0gABHhK0w= dependencies: ajv "^6.7.0" babel-runtime "^6.26.0" @@ -1498,6 +1505,16 @@ "@emotion/babel-plugin-jsx-pragmatic" "^0.1.3" babel-plugin-emotion "^10.0.14" +"@emotion/cache@^10.0.17": + version "10.0.19" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.19.tgz#d258d94d9c707dcadaf1558def968b86bb87ad71" + integrity sha512-BoiLlk4vEsGBg2dAqGSJu0vJl/PgVtCYLBFJaEO8RmQzPugXewQCXZJNXTDFaRlfCs0W+quesayav4fvaif5WQ== + dependencies: + "@emotion/sheet" "0.9.3" + "@emotion/stylis" "0.8.4" + "@emotion/utils" "0.11.2" + "@emotion/weak-memoize" "0.2.4" + "@emotion/cache@^10.0.9": version "10.0.9" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.9.tgz#e0c7b7a289f7530edcfad4dcf3858bd2e5700a6f" @@ -1508,6 +1525,18 @@ "@emotion/utils" "0.11.1" "@emotion/weak-memoize" "0.2.2" +"@emotion/core@^10.0.17": + version "10.0.17" + resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.17.tgz#3367376709721f4ee2068cff54ba581d362789d8" + integrity sha512-gykyjjr0sxzVuZBVTVK4dUmYsorc2qLhdYgSiOVK+m7WXgcYTKZevGWZ7TLAgTZvMelCTvhNq8xnf8FR1IdTbg== + dependencies: + "@babel/runtime" "^7.5.5" + "@emotion/cache" "^10.0.17" + "@emotion/css" "^10.0.14" + "@emotion/serialize" "^0.11.10" + "@emotion/sheet" "0.9.3" + "@emotion/utils" "0.11.2" + "@emotion/core@^10.0.7": version "10.0.9" resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.9.tgz#f8afbccb0011100680f5dc94657b410c6aa1350e" @@ -1519,6 +1548,15 @@ "@emotion/sheet" "0.9.2" "@emotion/utils" "0.11.1" +"@emotion/css@^10.0.14": + version "10.0.14" + resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.14.tgz#95dacabdd0e22845d1a1b0b5968d9afa34011139" + integrity sha512-MozgPkBEWvorcdpqHZE5x1D/PLEHUitALQCQYt2wayf4UNhpgQs2tN0UwHYS4FMy5ROBH+0ALyCFVYJ/ywmwlg== + dependencies: + "@emotion/serialize" "^0.11.8" + "@emotion/utils" "0.11.2" + babel-plugin-emotion "^10.0.14" + "@emotion/css@^10.0.9": version "10.0.9" resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.9.tgz#ea0df431965a308f6cb1d61386df8ad61e5befb5" @@ -1538,6 +1576,11 @@ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.7.2.tgz#53211e564604beb9befa7a4400ebf8147473eeef" integrity sha512-RMtr1i6E8MXaBWwhXL3yeOU8JXRnz8GNxHvaUfVvwxokvayUY0zoBeWbKw1S9XkufmGEEdQd228pSZXFkAln8Q== +"@emotion/hash@0.7.3": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.7.3.tgz#a166882c81c0c6040975dd30df24fae8549bd96f" + integrity sha512-14ZVlsB9akwvydAdaEnVnvqu6J2P6ySv39hYyl/aoB6w/V+bXX0tay8cF6paqbgZsN2n5Xh15uF4pE+GvE+itw== + "@emotion/is-prop-valid@^0.7.3": version "0.7.3" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz#a6bf4fa5387cbba59d44e698a4680f481a8da6cc" @@ -1555,6 +1598,22 @@ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.2.tgz#7f4c71b7654068dfcccad29553520f984cc66b30" integrity sha512-hnHhwQzvPCW1QjBWFyBtsETdllOM92BfrKWbUTmh9aeOlcVOiXvlPsK4104xH8NsaKfg86PTFsWkueQeUfMA/w== +"@emotion/memoize@0.7.3": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.3.tgz#5b6b1c11d6a6dddf1f2fc996f74cf3b219644d78" + integrity sha512-2Md9mH6mvo+ygq1trTeVp2uzAKwE2P7In0cRpD/M9Q70aH8L+rxMLbb3JCN2JoSWsV2O+DdFjfbbXoMoLBczow== + +"@emotion/serialize@^0.11.10", "@emotion/serialize@^0.11.8": + version "0.11.11" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.11.tgz#c92a5e5b358070a7242d10508143306524e842a4" + integrity sha512-YG8wdCqoWtuoMxhHZCTA+egL0RSGdHEc+YCsmiSBPBEDNuVeMWtjEWtGrhUterSChxzwnWBXvzSxIFQI/3sHLw== + dependencies: + "@emotion/hash" "0.7.3" + "@emotion/memoize" "0.7.3" + "@emotion/unitless" "0.7.4" + "@emotion/utils" "0.11.2" + csstype "^2.5.7" + "@emotion/serialize@^0.11.6": version "0.11.6" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.6.tgz#78be8b9ee9ff49e0196233ba6ec1c1768ba1e1fc" @@ -1582,11 +1641,21 @@ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.2.tgz#74e5c6b5e489a1ba30ab246ab5eedd96916487c4" integrity sha512-pVBLzIbC/QCHDKJF2E82V2H/W/B004mDFQZiyo/MSR+VC4pV5JLG0TF/zgQDFvP3fZL/5RTPGEmXlYJBMUuJ+A== +"@emotion/sheet@0.9.3": + version "0.9.3" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.3.tgz#689f135ecf87d3c650ed0c4f5ddcbe579883564a" + integrity sha512-c3Q6V7Df7jfwSq5AzQWbXHa5soeE4F5cbqi40xn0CzXxWW9/6Mxq48WJEtqfWzbZtW9odZdnRAkwCQwN12ob4A== + "@emotion/stylis@0.8.3": version "0.8.3" resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.3.tgz#3ca7e9bcb31b3cb4afbaeb66156d86ee85e23246" integrity sha512-M3nMfJ6ndJMYloSIbYEBq6G3eqoYD41BpDOxreE8j0cb4fzz/5qvmqU9Mb2hzsXcCnIlGlWhS03PCzVGvTAe0Q== +"@emotion/stylis@0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.4.tgz#6c51afdf1dd0d73666ba09d2eb6c25c220d6fe4c" + integrity sha512-TLmkCVm8f8gH0oLv+HWKiu7e8xmBIaokhxcEKPh1m8pXiV/akCiq50FvYgOwY42rjejck8nsdQxZlXZ7pmyBUQ== + "@emotion/unitless@0.7.3", "@emotion/unitless@^0.7.0": version "0.7.3" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.3.tgz#6310a047f12d21a1036fb031317219892440416f" @@ -1612,6 +1681,11 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.2.tgz#63985d3d8b02530e0869962f4da09142ee8e200e" integrity sha512-n/VQ4mbfr81aqkx/XmVicOLjviMuy02eenSdJY33SVA7S2J42EU0P1H0mOogfYedb3wXA0d/LVtBrgTSm04WEA== +"@emotion/weak-memoize@0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.4.tgz#622a72bebd1e3f48d921563b4b60a762295a81fc" + integrity sha512-6PYY5DVdAY1ifaQW6XYTnOMihmBVT27elqSjEoodchsGjzYlEsTQMcEhSud99kVawatyTZRTiVkJ/c6lwbQ7nA== + "@insin/npm-install-webpack-plugin@5.0.0": version "5.0.0" resolved "https://registry.yarnpkg.com/@insin/npm-install-webpack-plugin/-/npm-install-webpack-plugin-5.0.0.tgz#514a027a259cb51392d845086033d534eac9083f" @@ -2221,6 +2295,13 @@ dependencies: "@types/lodash" "*" +"@types/lodash.pick@^4.4.6": + version "4.4.6" + resolved "https://registry.yarnpkg.com/@types/lodash.pick/-/lodash.pick-4.4.6.tgz#ae4e8f109e982786313bb6aac4b1a73aefa6e9be" + integrity sha512-u8bzA16qQ+8dY280z3aK7PoWb3fzX5ATJ0rJB6F+uqchOX2VYF02Aqa+8aYiHiHgPzQiITqCgeimlyKFy4OA6g== + dependencies: + "@types/lodash" "*" + "@types/lodash.startcase@^4.4.6": version "4.4.6" resolved "https://registry.yarnpkg.com/@types/lodash.startcase/-/lodash.startcase-4.4.6.tgz#0e91c90004c87f738ae495a24e7b858cdecf0e2f" @@ -12661,6 +12742,11 @@ lodash.once@^4.0.0, lodash.once@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= +lodash.pick@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"