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 })}
+ />
+ );
+};