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 15dcc39c9f..cee9d240e0 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,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-export * from './steps/ActivityRenderer';
export * from './steps/BeginDialog';
-export * from './steps/DefaultRenderer';
export * from './steps/ReplaceDialog';
export * from './steps/ChoiceInput';
export * from './steps/TextInput';
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/DefaultRenderer.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/steps/DefaultRenderer.tsx
deleted file mode 100644
index a40a063063..0000000000
--- a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/DefaultRenderer.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-import React, { FC } from 'react';
-
-import { NodeProps } from '../nodeProps';
-import { renderSDKType } from '../../../schema/uischemaRenderer';
-import { NodeMenu } from '../../menus/NodeMenu';
-import { NodeEventTypes } from '../../../constants/NodeEventTypes';
-
-export const DefaultRenderer: FC = ({ id, data, onEvent }) => {
- return renderSDKType(data, {
- menu: ,
- 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 ec5ef11b60..9403d61328 100644
--- a/Composer/packages/extensions/visual-designer/src/components/renderers/ElementRenderer.tsx
+++ b/Composer/packages/extensions/visual-designer/src/components/renderers/ElementRenderer.tsx
@@ -10,20 +10,12 @@ import { ObiTypes } from '../../constants/ObiTypes';
import { AttrNames } from '../../constants/ElementAttributes';
import { NodeRendererContext } from '../../store/NodeRendererContext';
import { SelectionContext } from '../../store/SelectionContext';
-import {
- DefaultRenderer,
- BeginDialog,
- ReplaceDialog,
- ActivityRenderer,
- ChoiceInput,
- BotAsks,
- UserInput,
- InvalidPromptBrick,
-} from '../nodes/index';
+import { BeginDialog, ReplaceDialog, 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';
import { NodeProps, defaultNodeProps } from '../nodes/nodeProps';
+import { UISchemaRenderer } from '../../schema/uischemaRenderer';
const rendererByObiType = {
[ObiTypes.BeginDialog]: BeginDialog,
@@ -31,13 +23,13 @@ const rendererByObiType = {
[ObiTypes.ForeachDetail]: ForeachDetail,
[ObiTypes.ForeachPageDetail]: ForeachPageDetail,
[ObiTypes.ReplaceDialog]: ReplaceDialog,
- [ObiTypes.SendActivity]: ActivityRenderer,
+ [ObiTypes.SendActivity]: UISchemaRenderer,
[ObiTypes.ChoiceInputDetail]: ChoiceInput,
[ObiTypes.BotAsks]: BotAsks,
[ObiTypes.UserAnswers]: UserInput,
[ObiTypes.InvalidPromptBrick]: InvalidPromptBrick,
};
-const DEFAULT_RENDERER = DefaultRenderer;
+const DEFAULT_RENDERER = UISchemaRenderer;
function chooseRendererByType($type): FC | ComponentClass {
const renderer = rendererByObiType[$type] || DEFAULT_RENDERER;
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/schema/uischema.types.ts b/Composer/packages/extensions/visual-designer/src/schema/uischema.types.ts
index 465d09b1a2..546980b1ab 100644
--- a/Composer/packages/extensions/visual-designer/src/schema/uischema.types.ts
+++ b/Composer/packages/extensions/visual-designer/src/schema/uischema.types.ts
@@ -4,6 +4,8 @@
import { FC, ComponentClass } from 'react';
import { BaseSchema, SDKTypes } from '@bfc/shared';
+import { NodeEventTypes } from '../constants/NodeEventTypes';
+
export enum UISchemaBuiltinKeys {
default = 'default',
}
@@ -23,8 +25,12 @@ export interface UIWidget {
export type WidgetComponent = FC | ComponentClass;
+export type WidgetEventHandler = (eventName: NodeEventTypes, eventData?: any) => void;
+
export interface WidgetContainerProps {
+ id: string;
data: BaseSchema;
+ onEvent: WidgetEventHandler;
[propKey: string]: any;
}
diff --git a/Composer/packages/extensions/visual-designer/src/schema/uischemaRenderer.tsx b/Composer/packages/extensions/visual-designer/src/schema/uischemaRenderer.tsx
index d7d5fa73f4..a088031c80 100644
--- a/Composer/packages/extensions/visual-designer/src/schema/uischemaRenderer.tsx
+++ b/Composer/packages/extensions/visual-designer/src/schema/uischemaRenderer.tsx
@@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import React from 'react';
+import React, { FC } from 'react';
import { BaseSchema } from '@bfc/shared';
import get from 'lodash/get';
import { uiSchema } from './uischema';
-import { UIWidget, UI_WIDGET_KEY, UIWidgetProp } from './uischema.types';
+import { UIWidget, UI_WIDGET_KEY, UIWidgetProp, WidgetEventHandler } from './uischema.types';
const buildWidgetProp = (data: BaseSchema, rawPropValue: UIWidgetProp) => {
if (typeof rawPropValue === 'function') {
@@ -35,14 +35,20 @@ const parseWidgetSchema = (data: BaseSchema, widgetSchema: UIWidget) => {
};
};
-const renderWidget = (inputData, schema: UIWidget, contextProps = {}): JSX.Element => {
- const { Widget, props } = parseWidgetSchema(inputData, schema);
- return ;
-};
+export interface UISchemaRendererProps {
+ /** The uniq id of current schema data. Usually a json path. */
+ id: string;
+
+ /** Declarative json with a $type field. */
+ data: BaseSchema;
-export const renderSDKType = (data: BaseSchema, context?: { menu: JSX.Element; onClick }): JSX.Element => {
+ /** Handle UI events */
+ onEvent: WidgetEventHandler;
+}
+
+export const UISchemaRenderer: FC = ({ id, data, onEvent, ...contextProps }): JSX.Element => {
const $type = get(data, '$type');
const schema = get(uiSchema, $type, uiSchema.default);
-
- return renderWidget(data, schema, context);
+ const { Widget, props } = parseWidgetSchema(data, schema);
+ return ;
};
diff --git a/Composer/packages/extensions/visual-designer/src/widgets/ActionCard.tsx b/Composer/packages/extensions/visual-designer/src/widgets/ActionCard.tsx
index a8200df902..fc01237ecd 100644
--- a/Composer/packages/extensions/visual-designer/src/widgets/ActionCard.tsx
+++ b/Composer/packages/extensions/visual-designer/src/widgets/ActionCard.tsx
@@ -7,17 +7,17 @@ import { generateSDKTitle } from '@bfc/shared';
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 ActionCardProps extends WidgetContainerProps {
title: string;
icon: string;
content: string | number | JSX.Element;
- menu: JSX.Element;
colors?: {
theme: string;
icon: string;
};
- onClick: () => any;
}
const DefaultCardColor = {
@@ -26,17 +26,24 @@ const DefaultCardColor = {
};
export const ActionCard: WidgetComponent = ({
+ id,
data,
+ onEvent,
title,
icon,
content,
- menu,
- onClick,
colors = DefaultCardColor,
}) => {
const header = generateSDKTitle(data, title);
const nodeColors = { themeColor: colors.theme, iconColor: colors.icon };
return (
-
+ }
+ icon={icon}
+ label={content}
+ nodeColors={nodeColors}
+ onClick={() => onEvent(NodeEventTypes.Focus, { id })}
+ />
);
};
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..59850494de
--- /dev/null
+++ b/Composer/packages/extensions/visual-designer/src/widgets/DialogRefCard.tsx
@@ -0,0 +1,63 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/** @jsx jsx */
+import { jsx } from '@emotion/core';
+import { generateSDKTitle } from '@bfc/shared';
+
+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';
+import get from 'lodash/get';
+
+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 })}
+ />
+ );
+};