diff --git a/Composer/packages/extensions/visual-designer/demo/src/index.js b/Composer/packages/extensions/visual-designer/demo/src/index.js index 34e853d250..c9f24d18fe 100644 --- a/Composer/packages/extensions/visual-designer/demo/src/index.js +++ b/Composer/packages/extensions/visual-designer/demo/src/index.js @@ -36,7 +36,7 @@ const DemoMaps = { class Demo extends Component { state = { - selectedItem: DemoMaps.VisualEditorDemo.key, + selectedItem: DemoMaps.VisualSDKDemo.key, }; renderNav() { diff --git a/Composer/packages/extensions/visual-designer/demo/src/stories/VisualSDKDemo.js b/Composer/packages/extensions/visual-designer/demo/src/stories/VisualSDKDemo.js index af63d7d274..b3bab73ad5 100644 --- a/Composer/packages/extensions/visual-designer/demo/src/stories/VisualSDKDemo.js +++ b/Composer/packages/extensions/visual-designer/demo/src/stories/VisualSDKDemo.js @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import { seedNewDialog, SDKTypes } from '@bfc/shared'; -import { renderSDKType } from '../../../src/schema/uischemaRenderer'; +import { UISchemaRenderer } from '../../../src/schema/uischemaRenderer'; import { EdgeMenu } from '../../../src/components/menus/EdgeMenu'; import { JsonBlock } from '../components/json-block'; @@ -14,13 +14,17 @@ export class VisualSDKDemo extends Component { seedInitialActions() { const initialTypes = [ + SDKTypes.SendActivity, SDKTypes.EditArray, SDKTypes.InitProperty, SDKTypes.SetProperties, SDKTypes.SetProperty, SDKTypes.DeleteProperties, SDKTypes.DeleteProperty, + SDKTypes.BeginDialog, SDKTypes.EndDialog, + SDKTypes.RepeatDialog, + SDKTypes.ReplaceDialog, SDKTypes.CancelAllDialogs, SDKTypes.EmitEvent, ]; @@ -58,7 +62,9 @@ export class VisualSDKDemo extends Component { }} /> -
{renderSDKType(action)}
+
+ null} /> +
); } diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/index.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/index.tsx index 14c303c116..375569a664 100644 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/index.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/nodes/index.tsx @@ -1,9 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export * from './steps/ActivityRenderer'; -export * from './steps/BeginDialog'; -export * from './steps/ReplaceDialog'; export * from './steps/ChoiceInput'; export * from './steps/TextInput'; export * from './steps/BotAsks'; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ActivityRenderer.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ActivityRenderer.tsx deleted file mode 100644 index 1bcb8248b6..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ActivityRenderer.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import React from 'react'; -import formatMessage from 'format-message'; -import { generateSDKTitle } from '@bfc/shared'; - -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; -import { getElementColor, ElementIcon } from '../../../utils/obiPropertyResolver'; -import { NodeMenu } from '../../menus/NodeMenu'; -import { FormCard } from '../templates/FormCard'; -import { NodeProps, defaultNodeProps } from '../nodeProps'; -import { useLgTemplate } from '../../../utils/hooks'; - -export const ActivityRenderer: React.FC = props => { - const { id, data, onEvent } = props; - const templateText = useLgTemplate(data.activity, data.$designer && data.$designer.id); - - const nodeColors = getElementColor(data.$type); - const header = formatMessage('Activity'); - return ( - } - nodeColors={nodeColors} - onClick={() => { - onEvent(NodeEventTypes.Focus, { id }); - }} - /> - ); -}; - -ActivityRenderer.defaultProps = defaultNodeProps; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/BeginDialog.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/steps/BeginDialog.tsx deleted file mode 100644 index 1283f75fa3..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/BeginDialog.tsx +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** @jsx jsx */ -import { jsx } from '@emotion/core'; -import React from 'react'; -import formatMessage from 'format-message'; -import { generateSDKTitle } from '@bfc/shared'; - -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; -import { getElementColor } from '../../../utils/obiPropertyResolver'; -import { NodeMenu } from '../../menus/NodeMenu'; -import { FormCard } from '../templates/FormCard'; -import { NodeProps, defaultNodeProps } from '../nodeProps'; - -export class BeginDialog extends React.Component { - static defaultProps = defaultNodeProps; - renderCallDialogLink() { - const { id, data, onEvent } = this.props; - if (!data || !data.dialog) return null; - - const calleeDialog = typeof data.dialog === 'object' ? data.dialog.$ref : data.dialog; - return ( - { - e.stopPropagation(); - onEvent(NodeEventTypes.OpenDialog, { caller: id, callee: calleeDialog }); - }} - > - {calleeDialog} - - ); - } - - render() { - const { id, data, onEvent } = this.props; - const nodeColors = getElementColor(data.$type); - const header = formatMessage('BeginDialog'); - return ( - } - nodeColors={nodeColors} - onClick={() => { - onEvent(NodeEventTypes.Focus, { id }); - }} - /> - ); - } -} diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ReplaceDialog.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ReplaceDialog.tsx deleted file mode 100644 index 01c7d44c41..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ReplaceDialog.tsx +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** @jsx jsx */ -import { jsx } from '@emotion/core'; -import React from 'react'; -import formatMessage from 'format-message'; -import { generateSDKTitle } from '@bfc/shared'; - -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; -import { getElementColor } from '../../../utils/obiPropertyResolver'; -import { NodeMenu } from '../../menus/NodeMenu'; -import { FormCard } from '../templates/FormCard'; -import { NodeProps, defaultNodeProps } from '../nodeProps'; - -export class ReplaceDialog extends React.Component { - static defaultProps = defaultNodeProps; - renderCallDialogLink() { - const { id, data, onEvent } = this.props; - if (!data || !data.dialog) return null; - - const calleeDialog = typeof data.dialog === 'object' ? data.dialog.$ref : data.dialog; - return ( - - {formatMessage('Switch to ')} - { - e.stopPropagation(); - onEvent(NodeEventTypes.OpenDialog, { caller: id, callee: calleeDialog }); - }} - > - {calleeDialog} - - - ); - } - - render() { - const { id, data, onEvent } = this.props; - const nodeColors = getElementColor(data.$type); - const header = formatMessage('ReplaceDialog'); - return ( - } - nodeColors={nodeColors} - onClick={() => { - onEvent(NodeEventTypes.Focus, { id }); - }} - /> - ); - } -} diff --git a/Composer/packages/extensions/visual-designer/src/components/renderers/ElementRenderer.tsx b/Composer/packages/extensions/visual-designer/src/components/renderers/ElementRenderer.tsx index 7612a8f448..083c5e92bd 100644 --- a/Composer/packages/extensions/visual-designer/src/components/renderers/ElementRenderer.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/renderers/ElementRenderer.tsx @@ -10,15 +10,7 @@ import { ObiTypes } from '../../constants/ObiTypes'; import { AttrNames } from '../../constants/ElementAttributes'; import { NodeRendererContext } from '../../store/NodeRendererContext'; import { SelectionContext } from '../../store/SelectionContext'; -import { - BeginDialog, - ReplaceDialog, - ActivityRenderer, - ChoiceInput, - BotAsks, - UserInput, - InvalidPromptBrick, -} from '../nodes/index'; +import { ChoiceInput, BotAsks, UserInput, InvalidPromptBrick } from '../nodes/index'; import { ConditionNode } from '../nodes/steps/ConditionNode'; import { ForeachDetail } from '../nodes/steps/ForeachDetail'; import { ForeachPageDetail } from '../nodes/steps/ForeachPageDetail'; @@ -26,12 +18,12 @@ import { NodeProps, defaultNodeProps } from '../nodes/nodeProps'; import { UISchemaRenderer } from '../../schema/uischemaRenderer'; const rendererByObiType = { - [ObiTypes.BeginDialog]: BeginDialog, [ObiTypes.ConditionNode]: ConditionNode, [ObiTypes.ForeachDetail]: ForeachDetail, [ObiTypes.ForeachPageDetail]: ForeachPageDetail, - [ObiTypes.ReplaceDialog]: ReplaceDialog, - [ObiTypes.SendActivity]: ActivityRenderer, + [ObiTypes.BeginDialog]: UISchemaRenderer, + [ObiTypes.ReplaceDialog]: UISchemaRenderer, + [ObiTypes.SendActivity]: UISchemaRenderer, [ObiTypes.ChoiceInputDetail]: ChoiceInput, [ObiTypes.BotAsks]: BotAsks, [ObiTypes.UserAnswers]: UserInput, diff --git a/Composer/packages/extensions/visual-designer/src/schema/uischema.ts b/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx similarity index 73% rename from Composer/packages/extensions/visual-designer/src/schema/uischema.ts rename to Composer/packages/extensions/visual-designer/src/schema/uischema.tsx index 620105afaf..667af73b7d 100644 --- a/Composer/packages/extensions/visual-designer/src/schema/uischema.ts +++ b/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx @@ -2,8 +2,13 @@ // Licensed under the MIT License. import { SDKTypes } from '@bfc/shared'; +import React from 'react'; import { ActionCard } from '../widgets/ActionCard'; +import { ActivityRenderer } from '../widgets/ActivityRenderer'; +import { DialogRefCard } from '../widgets/DialogRefCard'; +import { ElementIcon } from '../utils/obiPropertyResolver'; +import { ObiColors } from '../constants/ElementColors'; import { UISchema } from './uischema.types'; @@ -11,6 +16,24 @@ export const uiSchema: UISchema = { default: { 'ui:widget': ActionCard, }, + [SDKTypes.SendActivity]: { + 'ui:widget': ActivityRenderer, + field: 'activity', + icon: ElementIcon.MessageBot, + colors: { + theme: ObiColors.BlueMagenta20, + icon: ObiColors.BlueMagenta30, + }, + }, + [SDKTypes.BeginDialog]: { + 'ui:widget': DialogRefCard, + dialog: data => data.dialog, + }, + [SDKTypes.ReplaceDialog]: { + 'ui:widget': DialogRefCard, + dialog: data => data.dialog, + getRefContent: data => dialogRef => <>Switch to {dialogRef}, + }, [SDKTypes.EditArray]: { 'ui:widget': ActionCard, content: data => `${data.changeType} {${data.itemsProperty || '?'}}`, diff --git a/Composer/packages/extensions/visual-designer/src/widgets/ActivityRenderer.tsx b/Composer/packages/extensions/visual-designer/src/widgets/ActivityRenderer.tsx new file mode 100644 index 0000000000..9fd5dd66f9 --- /dev/null +++ b/Composer/packages/extensions/visual-designer/src/widgets/ActivityRenderer.tsx @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import React from 'react'; +import { generateSDKTitle } from '@bfc/shared'; +import get from 'lodash/get'; + +import { NodeEventTypes } from '../constants/NodeEventTypes'; +import { ElementIcon } from '../utils/obiPropertyResolver'; +import { NodeMenu } from '../components/menus/NodeMenu'; +import { FormCard } from '../components/nodes/templates/FormCard'; +import { useLgTemplate } from '../utils/hooks'; +import { WidgetContainerProps } from '../schema/uischema.types'; +import { ObiColors } from '../constants/ElementColors'; + +export interface ActivityRenderer extends WidgetContainerProps { + /** indicates which field contains lg activity. ('activity', 'prompt', 'invalidPropmt'...) */ + field: string; + icon: ElementIcon; + colors?: { + theme: string; + icon: string; + }; +} + +const DefaultThemeColor = { + theme: ObiColors.BlueMagenta20, + icon: ObiColors.BlueMagenta30, +}; + +export const ActivityRenderer: React.FC = ({ + id, + data, + onEvent, + field, + icon = ElementIcon.MessageBot, + colors = DefaultThemeColor, +}) => { + const designerId = get(data, '$designer.id'); + const activityTemplate = get(data, field, ''); + + const templateText = useLgTemplate(activityTemplate, designerId); + const nodeColors = { themeColor: colors.theme, iconColor: colors.icon }; + + return ( + } + nodeColors={nodeColors} + onClick={() => { + onEvent(NodeEventTypes.Focus, { id }); + }} + /> + ); +}; diff --git a/Composer/packages/extensions/visual-designer/src/widgets/DialogRefCard.tsx b/Composer/packages/extensions/visual-designer/src/widgets/DialogRefCard.tsx new file mode 100644 index 0000000000..1d93f49e5d --- /dev/null +++ b/Composer/packages/extensions/visual-designer/src/widgets/DialogRefCard.tsx @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import { generateSDKTitle } from '@bfc/shared'; +import get from 'lodash/get'; +import { Link } from 'office-ui-fabric-react/lib/Link'; + +import { FormCard } from '../components/nodes/templates/FormCard'; +import { WidgetContainerProps, WidgetComponent } from '../schema/uischema.types'; +import { ObiColors } from '../constants/ElementColors'; +import { NodeEventTypes } from '../constants/NodeEventTypes'; +import { NodeMenu } from '../components/menus/NodeMenu'; + +export interface DialogRefCardProps extends WidgetContainerProps { + dialog: string | object; + getRefContent?: (dialogRef: JSX.Element) => JSX.Element; + colors?: { + theme: string; + icon: string; + }; +} + +const DefaultCardColor = { + theme: ObiColors.AzureGray3, + icon: ObiColors.AzureGray2, +}; + +export const DialogRefCard: WidgetComponent = ({ + id, + data, + onEvent, + dialog, + getRefContent, + colors = DefaultCardColor, +}) => { + const header = generateSDKTitle(data); + const nodeColors = { themeColor: colors.theme, iconColor: colors.icon }; + const calleeDialog = typeof dialog === 'object' ? get(dialog, '$ref') : dialog; + const dialogRef = ( + { + e.stopPropagation(); + onEvent(NodeEventTypes.OpenDialog, { caller: id, callee: calleeDialog }); + }} + > + {calleeDialog} + + ); + return ( + } + label={typeof getRefContent === 'function' ? getRefContent(dialogRef) : dialogRef} + nodeColors={nodeColors} + onClick={() => onEvent(NodeEventTypes.Focus, { id })} + /> + ); +};