From 9c6b654ab05466429d5aa952e30ec67c31cb9a33 Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Fri, 24 Jan 2020 20:06:53 +0800 Subject: [PATCH 1/6] migrate Foreach / IfCondition / SwitchCondition --- .../visual-designer/src/schema/uischema.tsx | 15 +++ .../src/widgets/ForeachWidget.tsx | 114 ++++++++++++++++++ .../src/widgets/IfConditionWidget.tsx | 112 +++++++++++++++++ .../src/widgets/SwitchConditionWidget.tsx | 109 +++++++++++++++++ 4 files changed, 350 insertions(+) create mode 100644 Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx create mode 100644 Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx create mode 100644 Composer/packages/extensions/visual-designer/src/widgets/SwitchConditionWidget.tsx diff --git a/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx b/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx index 5f0f49dccd..3a34b3d992 100644 --- a/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx +++ b/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx @@ -8,6 +8,9 @@ import { ActionCard } from '../widgets/ActionCard'; import { ActivityRenderer } from '../widgets/ActivityRenderer'; import { DialogRefCard } from '../widgets/DialogRefCard'; import { PromptWidget } from '../widgets/PromptWidget'; +import { IfConditionWidget } from '../widgets/IfConditionWidget'; +import { SwitchConditionWidget } from '../widgets/SwitchConditionWidget'; +import { ForeachWidget } from '../widgets/ForeachWidget'; import { ElementIcon } from '../utils/obiPropertyResolver'; import { ObiColors } from '../constants/ElementColors'; @@ -44,6 +47,18 @@ export const uiSchema: UISchema = { default: { 'ui:widget': ActionCard, }, + [SDKTypes.IfCondition]: { + 'ui:widget': IfConditionWidget, + }, + [SDKTypes.SwitchCondition]: { + 'ui:widget': SwitchConditionWidget, + }, + [SDKTypes.Foreach]: { + 'ui:widget': ForeachWidget, + }, + [SDKTypes.ForeachPage]: { + 'ui:widget': ForeachWidget, + }, [SDKTypes.SendActivity]: { 'ui:widget': ActivityRenderer, field: 'activity', diff --git a/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx b/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx new file mode 100644 index 0000000000..a25bb1e4e4 --- /dev/null +++ b/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import { useMemo, useEffect, useState, FunctionComponent } from 'react'; + +import { transformForeach } from '../transformers/transformForeach'; +import { foreachLayouter } from '../layouters/foreachLayouter'; +import { areBoundariesEqual, Boundary } from '../models/Boundary'; +import { GraphNode } from '../models/GraphNode'; +import { NodeEventTypes } from '../constants/NodeEventTypes'; +import { OffsetContainer } from '../components/lib/OffsetContainer'; +import { Edge } from '../components/lib/EdgeComponents'; +import { LoopIndicator } from '../components/decorations/LoopIndicator'; +import { StepGroup } from '../components/groups'; +import { ForeachDetail } from '../components/nodes/steps/ForeachDetail'; +import { ElementWrapper } from '../components/renderers/ElementWrapper'; +import { ObiTypes } from '../constants/ObiTypes'; +import { ForeachPageDetail } from '../components/nodes/steps/ForeachPageDetail'; +import { NodeMap, BoundaryMap } from '../components/nodes/layout-steps/types'; +import { WidgetContainerProps } from '../schema/uischema.types'; + +const calculateNodeMap = (jsonpath, data): NodeMap => { + const result = transformForeach(data, jsonpath); + if (!result) return {}; + + const { foreachDetail, stepGroup, loopBegin, loopEnd } = result; + return { + foreachNode: GraphNode.fromIndexedJson(foreachDetail), + stepGroupNode: GraphNode.fromIndexedJson(stepGroup), + loopBeginNode: GraphNode.fromIndexedJson(loopBegin), + loopEndNode: GraphNode.fromIndexedJson(loopEnd), + }; +}; + +const calculateLayout = (nodeMap: NodeMap, boundaryMap: BoundaryMap) => { + Object.values(nodeMap) + .filter(x => !!x) + .forEach((x: GraphNode) => { + x.boundary = boundaryMap[x.id] || x.boundary; + }); + + return foreachLayouter(nodeMap.foreachNode, nodeMap.stepGroupNode, nodeMap.loopBeginNode, nodeMap.loopEndNode); +}; + +export type ForeachWidgetProps = WidgetContainerProps; + +export const ForeachWidget: FunctionComponent = ({ id, data, onEvent, onResize }) => { + const [boundaryMap, setBoundaryMap] = useState({}); + const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); + const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); + const accumulatedPatches = {}; + + const patchBoundary = (id, boundary?: Boundary) => { + if (!boundaryMap[id] || !areBoundariesEqual(boundaryMap[id], boundary)) { + accumulatedPatches[id] = boundary; + setBoundaryMap({ + ...boundaryMap, + ...accumulatedPatches, + }); + } + }; + + useEffect(() => { + onResize(layout.boundary); + }, [layout]); + + const { boundary, nodeMap, edges } = layout; + if (!nodeMap) { + return null; + } + + const { foreachNode, stepsNode, loopBeginNode, loopEndNode } = nodeMap; + const ForeachHeader = data.$type === ObiTypes.Foreach ? ForeachDetail : ForeachPageDetail; + return ( +
+ + + + + + + { + patchBoundary(stepsNode.id, size); + }} + /> + + {[loopBeginNode, loopEndNode] + .filter(x => !!x) + .map((x, index) => ( + + onEvent(NodeEventTypes.Focus, { id })} /> + + ))} + {edges ? edges.map(x => ) : null} +
+ ); +}; + +ForeachWidget.defaultProps = { + onResize: () => null, +}; diff --git a/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx b/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx new file mode 100644 index 0000000000..b69c703a8e --- /dev/null +++ b/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import { FunctionComponent, useEffect, useState, useMemo } from 'react'; + +import { transformIfCondtion } from '../transformers/transformIfCondition'; +import { ifElseLayouter } from '../layouters/ifelseLayouter'; +import { NodeEventTypes } from '../constants/NodeEventTypes'; +import { GraphNode } from '../models/GraphNode'; +import { areBoundariesEqual, Boundary } from '../models/Boundary'; +import { OffsetContainer } from '../components/lib/OffsetContainer'; +import { Edge } from '../components/lib/EdgeComponents'; +import { StepGroup } from '../components/groups'; +import { Diamond } from '../components/nodes/templates/Diamond'; +import { ElementWrapper } from '../components/renderers/ElementWrapper'; +import { ConditionNode } from '../components/nodes/steps/ConditionNode'; +import { NodeMap, BoundaryMap } from '../components/nodes/layout-steps/types'; +import { WidgetContainerProps } from '../schema/uischema.types'; + +const calculateNodeMap = (path, data): NodeMap => { + const result = transformIfCondtion(data, path); + if (!result) return {}; + + const { condition, choice, ifGroup, elseGroup } = result; + return { + conditionNode: GraphNode.fromIndexedJson(condition), + choiceNode: GraphNode.fromIndexedJson(choice), + ifGroupNode: GraphNode.fromIndexedJson(ifGroup), + elseGroupNode: GraphNode.fromIndexedJson(elseGroup), + }; +}; + +const calculateLayout = (nodeMap: NodeMap, boundaryMap: BoundaryMap) => { + Object.values(nodeMap) + .filter(x => !!x) + .forEach((x: GraphNode) => (x.boundary = boundaryMap[x.id] || x.boundary)); + + return ifElseLayouter(nodeMap.conditionNode, nodeMap.choiceNode, nodeMap.ifGroupNode, nodeMap.elseGroupNode); +}; + +export type IfConditionWidgetProps = WidgetContainerProps; +export const IfConditionWidget: FunctionComponent = ({ id, data, onEvent, onResize }) => { + const [boundaryMap, setBoundaryMap] = useState({}); + const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); + const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); + const accumulatedPatches = {}; + + const patchBoundary = (id, boundary?: Boundary) => { + if (!boundaryMap[id] || !areBoundariesEqual(boundaryMap[id], boundary)) { + accumulatedPatches[id] = boundary; + setBoundaryMap({ + ...boundaryMap, + ...accumulatedPatches, + }); + } + }; + + useEffect(() => { + onResize(layout.boundary); + }, [layout]); + + const { boundary, nodeMap, edges } = layout; + const condition = nodeMap.condition || new GraphNode(); + const choice = nodeMap.choice || new GraphNode(); + + return ( +
+ + + + + + + { + onEvent(NodeEventTypes.Focus, { id }); + }} + /> + + {nodeMap + ? [nodeMap.if, nodeMap.else] + .filter(x => !!x) + .map(x => ( + + { + patchBoundary(x.id, size); + }} + /> + + )) + : null} + {edges ? edges.map(x => ) : null} +
+ ); +}; + +IfConditionWidget.defaultProps = { + onResize: () => null, +}; diff --git a/Composer/packages/extensions/visual-designer/src/widgets/SwitchConditionWidget.tsx b/Composer/packages/extensions/visual-designer/src/widgets/SwitchConditionWidget.tsx new file mode 100644 index 0000000000..cd5597e265 --- /dev/null +++ b/Composer/packages/extensions/visual-designer/src/widgets/SwitchConditionWidget.tsx @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** @jsx jsx */ +import { jsx } from '@emotion/core'; +import { FunctionComponent, useEffect, useState, useMemo } from 'react'; + +import { NodeEventTypes } from '../constants/NodeEventTypes'; +import { transformSwitchCondition } from '../transformers/transformSwitchCondition'; +import { switchCaseLayouter } from '../layouters/switchCaseLayouter'; +import { GraphNode } from '../models/GraphNode'; +import { areBoundariesEqual } from '../models/Boundary'; +import { OffsetContainer } from '../components/lib/OffsetContainer'; +import { Edge } from '../components/lib/EdgeComponents'; +import { StepGroup } from '../components/groups'; +import { Diamond } from '../components/nodes/templates/Diamond'; +import { ElementWrapper } from '../components/renderers/ElementWrapper'; +import { ConditionNode } from '../components/nodes/steps/ConditionNode'; +import { WidgetContainerProps } from '../schema/uischema.types'; + +const calculateNodeMap = (path, data) => { + const result = transformSwitchCondition(data, path); + if (!result) return {}; + + const { condition, choice, branches } = result; + return { + conditionNode: GraphNode.fromIndexedJson(condition), + choiceNode: GraphNode.fromIndexedJson(choice), + branchNodes: branches.map(x => GraphNode.fromIndexedJson(x)), + }; +}; + +const calculateLayout = (nodeMap, boundaryMap) => { + [nodeMap.conditionNode, nodeMap.choiceNode, ...nodeMap.branchNodes] + .filter(x => !!x) + .forEach(x => (x.boundary = boundaryMap[x.id] || x.boundary)); + + return switchCaseLayouter(nodeMap.conditionNode, nodeMap.choiceNode, nodeMap.branchNodes); +}; + +export type SwitchConditionWidgetProps = WidgetContainerProps; + +export const SwitchConditionWidget: FunctionComponent = ({ id, data, onEvent, onResize }) => { + const [boundaryMap, setBoundaryMap] = useState({}); + const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); + const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); + const accumulatedPatches = {}; + + const patchBoundary = (id, boundary) => { + if (!boundaryMap[id] || !areBoundariesEqual(boundaryMap[id], boundary)) { + accumulatedPatches[id] = boundary; + setBoundaryMap({ + ...boundaryMap, + ...accumulatedPatches, + }); + } + }; + + useEffect(() => { + onResize(layout.boundary); + }, [layout]); + + const { boundary, nodeMap, edges } = layout; + const conditionNode = nodeMap.conditionNode; + const choiceNode = nodeMap.choiceNode; + const branchNodes = nodeMap.branchNodes || []; + + return ( +
+ + + + + + + { + onEvent(NodeEventTypes.Focus, { id }); + }} + /> + + {(branchNodes as any).map(x => ( + + { + patchBoundary(x.id, size); + }} + /> + + ))} + {edges ? edges.map(x => ) : null} +
+ ); +}; + +SwitchConditionWidget.defaultProps = { + onResize: () => null, +}; From 3f14dce982292603a1679d5dacd941d1dbed9cb6 Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Fri, 24 Jan 2020 20:10:07 +0800 Subject: [PATCH 2/6] apply UISchemaRenderer to all types --- .../src/components/renderers/StepRenderer.tsx | 32 +++---------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/Composer/packages/extensions/visual-designer/src/components/renderers/StepRenderer.tsx b/Composer/packages/extensions/visual-designer/src/components/renderers/StepRenderer.tsx index db3ca5ef57..db53f2efdb 100644 --- a/Composer/packages/extensions/visual-designer/src/components/renderers/StepRenderer.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/renderers/StepRenderer.tsx @@ -3,30 +3,15 @@ /** @jsx jsx */ import { jsx } from '@emotion/core'; -import { FC, ComponentClass } from 'react'; +import { FC } from 'react'; import { SDKTypes } from '@bfc/shared'; import get from 'lodash/get'; -import { ObiTypes } from '../../constants/ObiTypes'; -import { IfCondition, SwitchCondition, Foreach } from '../nodes/index'; import { NodeProps, defaultNodeProps } from '../nodes/nodeProps'; import { UISchemaRenderer } from '../../schema/uischemaRenderer'; import { ElementWrapper } from './ElementWrapper'; -const rendererByObiType = { - [ObiTypes.IfCondition]: IfCondition, - [ObiTypes.SwitchCondition]: SwitchCondition, - [ObiTypes.Foreach]: Foreach, - [ObiTypes.ForeachPage]: Foreach, -}; -const DEFAULT_RENDERER = UISchemaRenderer; - -function chooseRendererByType($type): FC | ComponentClass { - const renderer = rendererByObiType[$type] || DEFAULT_RENDERER; - return renderer; -} - /** TODO: (zeye) integrate this array into UISchema */ const TypesWithoutWrapper = [ SDKTypes.IfCondition, @@ -40,20 +25,11 @@ const TypesWithoutWrapper = [ SDKTypes.TextInput, SDKTypes.ChoiceInput, ]; -export const StepRenderer: FC = ({ id, data, onEvent, onResize }): JSX.Element => { + +export const StepRenderer: FC = ({ id, data, onEvent }): JSX.Element => { const $type = get(data, '$type', ''); - const ChosenRenderer = chooseRendererByType($type); - const content = ( - { - onResize(size, 'node'); - }} - /> - ); + const content = ; if (TypesWithoutWrapper.some(x => $type === x)) { return content; From 6ca7122fc36799454cbce8873cb1f7be146e70da Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Fri, 24 Jan 2020 20:20:20 +0800 Subject: [PATCH 3/6] remove old widgets --- .../src/components/nodes/index.tsx | 4 - .../components/nodes/layout-steps/Foreach.tsx | 111 ------------------ .../nodes/layout-steps/IfCondition.tsx | 110 ----------------- .../nodes/layout-steps/SwitchCondition.tsx | 105 ----------------- .../nodes/{layout-steps => }/types.ts | 4 +- .../src/widgets/ForeachWidget.tsx | 2 +- .../src/widgets/IfConditionWidget.tsx | 2 +- 7 files changed, 4 insertions(+), 334 deletions(-) delete mode 100644 Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/Foreach.tsx delete mode 100644 Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/IfCondition.tsx delete mode 100644 Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/SwitchCondition.tsx rename Composer/packages/extensions/visual-designer/src/components/nodes/{layout-steps => }/types.ts (62%) 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 64c16234e9..f0d34a8d62 100644 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/index.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/nodes/index.tsx @@ -7,10 +7,6 @@ export * from './steps/BotAsks'; export * from './steps/UserInput'; export * from './steps/InvalidPromptBrick'; -export * from './layout-steps/Foreach'; -export * from './layout-steps/IfCondition'; -export * from './layout-steps/SwitchCondition'; - export * from './events/EventRule'; export * from './events/IntentRule'; export * from './events/UnknownIntentRule'; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/Foreach.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/Foreach.tsx deleted file mode 100644 index 58019c4ac6..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/Foreach.tsx +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** @jsx jsx */ -import { jsx } from '@emotion/core'; -import { useMemo, useEffect, useState, FunctionComponent } from 'react'; - -import { transformForeach } from '../../../transformers/transformForeach'; -import { foreachLayouter } from '../../../layouters/foreachLayouter'; -import { areBoundariesEqual, Boundary } from '../../../models/Boundary'; -import { GraphNode } from '../../../models/GraphNode'; -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; -import { OffsetContainer } from '../../lib/OffsetContainer'; -import { Edge } from '../../lib/EdgeComponents'; -import { LoopIndicator } from '../../decorations/LoopIndicator'; -import { StepGroup } from '../../groups'; -import { NodeProps, defaultNodeProps } from '../nodeProps'; -import { ForeachDetail } from '../steps/ForeachDetail'; -import { ElementWrapper } from '../../renderers/ElementWrapper'; -import { ObiTypes } from '../../../constants/ObiTypes'; -import { ForeachPageDetail } from '../steps/ForeachPageDetail'; - -import { NodeMap, BoundaryMap } from './types'; - -const calculateNodeMap = (jsonpath, data): NodeMap => { - const result = transformForeach(data, jsonpath); - if (!result) return {}; - - const { foreachDetail, stepGroup, loopBegin, loopEnd } = result; - return { - foreachNode: GraphNode.fromIndexedJson(foreachDetail), - stepGroupNode: GraphNode.fromIndexedJson(stepGroup), - loopBeginNode: GraphNode.fromIndexedJson(loopBegin), - loopEndNode: GraphNode.fromIndexedJson(loopEnd), - }; -}; - -const calculateLayout = (nodeMap: NodeMap, boundaryMap: BoundaryMap) => { - Object.values(nodeMap) - .filter(x => !!x) - .forEach((x: GraphNode) => { - x.boundary = boundaryMap[x.id] || x.boundary; - }); - - return foreachLayouter(nodeMap.foreachNode, nodeMap.stepGroupNode, nodeMap.loopBeginNode, nodeMap.loopEndNode); -}; - -export const Foreach: FunctionComponent = ({ id, data, onEvent, onResize }) => { - const [boundaryMap, setBoundaryMap] = useState({}); - const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); - const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); - const accumulatedPatches = {}; - - const patchBoundary = (id, boundary?: Boundary) => { - if (!boundaryMap[id] || !areBoundariesEqual(boundaryMap[id], boundary)) { - accumulatedPatches[id] = boundary; - setBoundaryMap({ - ...boundaryMap, - ...accumulatedPatches, - }); - } - }; - - useEffect(() => { - onResize(layout.boundary); - }, [layout]); - - const { boundary, nodeMap, edges } = layout; - if (!nodeMap) { - return null; - } - - const { foreachNode, stepsNode, loopBeginNode, loopEndNode } = nodeMap; - const ForeachHeader = data.$type === ObiTypes.Foreach ? ForeachDetail : ForeachPageDetail; - return ( -
- - - - - - - { - patchBoundary(stepsNode.id, size); - }} - /> - - {[loopBeginNode, loopEndNode] - .filter(x => !!x) - .map((x, index) => ( - - onEvent(NodeEventTypes.Focus, { id })} /> - - ))} - {edges ? edges.map(x => ) : null} -
- ); -}; - -Foreach.defaultProps = defaultNodeProps; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/IfCondition.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/IfCondition.tsx deleted file mode 100644 index 5f9159d561..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/IfCondition.tsx +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** @jsx jsx */ -import { jsx } from '@emotion/core'; -import { FunctionComponent, useEffect, useState, useMemo } from 'react'; - -import { transformIfCondtion } from '../../../transformers/transformIfCondition'; -import { ifElseLayouter } from '../../../layouters/ifelseLayouter'; -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; -import { GraphNode } from '../../../models/GraphNode'; -import { areBoundariesEqual, Boundary } from '../../../models/Boundary'; -import { OffsetContainer } from '../../lib/OffsetContainer'; -import { Edge } from '../../lib/EdgeComponents'; -import { StepGroup } from '../../groups'; -import { Diamond } from '../templates/Diamond'; -import { ElementWrapper } from '../../renderers/ElementWrapper'; -import { NodeProps, defaultNodeProps } from '../nodeProps'; -import { ConditionNode } from '../steps/ConditionNode'; - -import { NodeMap, BoundaryMap } from './types'; - -const calculateNodeMap = (path, data): NodeMap => { - const result = transformIfCondtion(data, path); - if (!result) return {}; - - const { condition, choice, ifGroup, elseGroup } = result; - return { - conditionNode: GraphNode.fromIndexedJson(condition), - choiceNode: GraphNode.fromIndexedJson(choice), - ifGroupNode: GraphNode.fromIndexedJson(ifGroup), - elseGroupNode: GraphNode.fromIndexedJson(elseGroup), - }; -}; - -const calculateLayout = (nodeMap: NodeMap, boundaryMap: BoundaryMap) => { - Object.values(nodeMap) - .filter(x => !!x) - .forEach((x: GraphNode) => (x.boundary = boundaryMap[x.id] || x.boundary)); - - return ifElseLayouter(nodeMap.conditionNode, nodeMap.choiceNode, nodeMap.ifGroupNode, nodeMap.elseGroupNode); -}; - -export const IfCondition: FunctionComponent = ({ id, data, onEvent, onResize }) => { - const [boundaryMap, setBoundaryMap] = useState({}); - const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); - const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); - const accumulatedPatches = {}; - - const patchBoundary = (id, boundary?: Boundary) => { - if (!boundaryMap[id] || !areBoundariesEqual(boundaryMap[id], boundary)) { - accumulatedPatches[id] = boundary; - setBoundaryMap({ - ...boundaryMap, - ...accumulatedPatches, - }); - } - }; - - useEffect(() => { - onResize(layout.boundary); - }, [layout]); - - const { boundary, nodeMap, edges } = layout; - const condition = nodeMap.condition || new GraphNode(); - const choice = nodeMap.choice || new GraphNode(); - - return ( -
- - - - - - - { - onEvent(NodeEventTypes.Focus, { id }); - }} - /> - - {nodeMap - ? [nodeMap.if, nodeMap.else] - .filter(x => !!x) - .map(x => ( - - { - patchBoundary(x.id, size); - }} - /> - - )) - : null} - {edges ? edges.map(x => ) : null} -
- ); -}; - -IfCondition.defaultProps = defaultNodeProps; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/SwitchCondition.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/SwitchCondition.tsx deleted file mode 100644 index 31a97af96b..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/SwitchCondition.tsx +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -/** @jsx jsx */ -import { jsx } from '@emotion/core'; -import { FunctionComponent, useEffect, useState, useMemo } from 'react'; - -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; -import { transformSwitchCondition } from '../../../transformers/transformSwitchCondition'; -import { switchCaseLayouter } from '../../../layouters/switchCaseLayouter'; -import { GraphNode } from '../../../models/GraphNode'; -import { areBoundariesEqual } from '../../../models/Boundary'; -import { OffsetContainer } from '../../lib/OffsetContainer'; -import { Edge } from '../../lib/EdgeComponents'; -import { StepGroup } from '../../groups'; -import { Diamond } from '../templates/Diamond'; -import { NodeProps, defaultNodeProps } from '../nodeProps'; -import { ElementWrapper } from '../../renderers/ElementWrapper'; -import { ConditionNode } from '../steps/ConditionNode'; - -const calculateNodeMap = (path, data) => { - const result = transformSwitchCondition(data, path); - if (!result) return {}; - - const { condition, choice, branches } = result; - return { - conditionNode: GraphNode.fromIndexedJson(condition), - choiceNode: GraphNode.fromIndexedJson(choice), - branchNodes: branches.map(x => GraphNode.fromIndexedJson(x)), - }; -}; - -const calculateLayout = (nodeMap, boundaryMap) => { - [nodeMap.conditionNode, nodeMap.choiceNode, ...nodeMap.branchNodes] - .filter(x => !!x) - .forEach(x => (x.boundary = boundaryMap[x.id] || x.boundary)); - - return switchCaseLayouter(nodeMap.conditionNode, nodeMap.choiceNode, nodeMap.branchNodes); -}; - -export const SwitchCondition: FunctionComponent = ({ id, data, onEvent, onResize }) => { - const [boundaryMap, setBoundaryMap] = useState({}); - const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); - const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); - const accumulatedPatches = {}; - - const patchBoundary = (id, boundary) => { - if (!boundaryMap[id] || !areBoundariesEqual(boundaryMap[id], boundary)) { - accumulatedPatches[id] = boundary; - setBoundaryMap({ - ...boundaryMap, - ...accumulatedPatches, - }); - } - }; - - useEffect(() => { - onResize(layout.boundary); - }, [layout]); - - const { boundary, nodeMap, edges } = layout; - const conditionNode = nodeMap.conditionNode; - const choiceNode = nodeMap.choiceNode; - const branchNodes = nodeMap.branchNodes || []; - - return ( -
- - - - - - - { - onEvent(NodeEventTypes.Focus, { id }); - }} - /> - - {(branchNodes as any).map(x => ( - - { - patchBoundary(x.id, size); - }} - /> - - ))} - {edges ? edges.map(x => ) : null} -
- ); -}; - -SwitchCondition.defaultProps = defaultNodeProps; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/types.ts b/Composer/packages/extensions/visual-designer/src/components/nodes/types.ts similarity index 62% rename from Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/types.ts rename to Composer/packages/extensions/visual-designer/src/components/nodes/types.ts index 4ab3d4b7e0..f77977d23a 100644 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/layout-steps/types.ts +++ b/Composer/packages/extensions/visual-designer/src/components/nodes/types.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { GraphNode } from '../../../models/GraphNode'; -import { Boundary } from '../../../models/Boundary'; +import { GraphNode } from '../../models/GraphNode'; +import { Boundary } from '../../models/Boundary'; export type NodeMap = { [id: string]: GraphNode }; export type BoundaryMap = { [id: string]: Boundary }; diff --git a/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx b/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx index a25bb1e4e4..42a05fe555 100644 --- a/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx +++ b/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx @@ -18,7 +18,7 @@ import { ForeachDetail } from '../components/nodes/steps/ForeachDetail'; import { ElementWrapper } from '../components/renderers/ElementWrapper'; import { ObiTypes } from '../constants/ObiTypes'; import { ForeachPageDetail } from '../components/nodes/steps/ForeachPageDetail'; -import { NodeMap, BoundaryMap } from '../components/nodes/layout-steps/types'; +import { NodeMap, BoundaryMap } from '../components/nodes/types'; import { WidgetContainerProps } from '../schema/uischema.types'; const calculateNodeMap = (jsonpath, data): NodeMap => { diff --git a/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx b/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx index b69c703a8e..5769eda9a1 100644 --- a/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx +++ b/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx @@ -16,7 +16,7 @@ import { StepGroup } from '../components/groups'; import { Diamond } from '../components/nodes/templates/Diamond'; import { ElementWrapper } from '../components/renderers/ElementWrapper'; import { ConditionNode } from '../components/nodes/steps/ConditionNode'; -import { NodeMap, BoundaryMap } from '../components/nodes/layout-steps/types'; +import { NodeMap, BoundaryMap } from '../components/nodes/types'; import { WidgetContainerProps } from '../schema/uischema.types'; const calculateNodeMap = (path, data): NodeMap => { From aabffddb8a3699e9db42314c6c040ff8c869754e Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Fri, 24 Jan 2020 21:00:56 +0800 Subject: [PATCH 4/6] update header part of 4 types --- .../visual-designer/src/schema/uischema.tsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx b/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx index 3a34b3d992..03cd05bfd3 100644 --- a/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx +++ b/Composer/packages/extensions/visual-designer/src/schema/uischema.tsx @@ -2,7 +2,9 @@ // Licensed under the MIT License. import { SDKTypes, getInputType } from '@bfc/shared'; +import formatMessage from 'format-message'; import React from 'react'; +import get from 'lodash/get'; import { ActionCard } from '../widgets/ActionCard'; import { ActivityRenderer } from '../widgets/ActivityRenderer'; @@ -49,15 +51,39 @@ export const uiSchema: UISchema = { }, [SDKTypes.IfCondition]: { 'ui:widget': IfConditionWidget, + judgement: { + 'ui:widget': ActionCard, + title: formatMessage('Branch'), + content: data => data.condition, + }, }, [SDKTypes.SwitchCondition]: { 'ui:widget': SwitchConditionWidget, + judgement: { + 'ui:widget': ActionCard, + title: formatMessage('Branch'), + content: data => data.condition, + }, }, [SDKTypes.Foreach]: { 'ui:widget': ForeachWidget, + loop: { + 'ui:widget': ActionCard, + title: formatMessage('Loop: For Each'), + content: data => `${formatMessage('Each value in')} {${data.itemsProperty || '?'}}`, + }, }, [SDKTypes.ForeachPage]: { 'ui:widget': ForeachWidget, + loop: { + 'ui:widget': ActionCard, + title: formatMessage('Loop: For Each Page'), + content: data => { + const pageSizeString = get(data, 'pageSize', '?'); + const propString = get(data, 'itemsProperty', '?'); + return `${formatMessage('Each page of')} ${pageSizeString} ${formatMessage('in')} {${propString}}`; + }, + }, }, [SDKTypes.SendActivity]: { 'ui:widget': ActivityRenderer, From d643c58e05f1c3a1f5f15fccf1abbf73bb1cb250 Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Fri, 24 Jan 2020 21:16:27 +0800 Subject: [PATCH 5/6] apply customization parts to widget --- .../src/widgets/ForeachWidget.tsx | 18 +++++---------- .../src/widgets/IfConditionWidget.tsx | 22 ++++++++++--------- .../src/widgets/SwitchConditionWidget.tsx | 21 +++++++++--------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx b/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx index 42a05fe555..4e06561323 100644 --- a/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx +++ b/Composer/packages/extensions/visual-designer/src/widgets/ForeachWidget.tsx @@ -14,10 +14,7 @@ import { OffsetContainer } from '../components/lib/OffsetContainer'; import { Edge } from '../components/lib/EdgeComponents'; import { LoopIndicator } from '../components/decorations/LoopIndicator'; import { StepGroup } from '../components/groups'; -import { ForeachDetail } from '../components/nodes/steps/ForeachDetail'; import { ElementWrapper } from '../components/renderers/ElementWrapper'; -import { ObiTypes } from '../constants/ObiTypes'; -import { ForeachPageDetail } from '../components/nodes/steps/ForeachPageDetail'; import { NodeMap, BoundaryMap } from '../components/nodes/types'; import { WidgetContainerProps } from '../schema/uischema.types'; @@ -44,9 +41,11 @@ const calculateLayout = (nodeMap: NodeMap, boundaryMap: BoundaryMap) => { return foreachLayouter(nodeMap.foreachNode, nodeMap.stepGroupNode, nodeMap.loopBeginNode, nodeMap.loopEndNode); }; -export type ForeachWidgetProps = WidgetContainerProps; +export interface ForeachWidgetProps extends WidgetContainerProps { + loop: JSX.Element; +} -export const ForeachWidget: FunctionComponent = ({ id, data, onEvent, onResize }) => { +export const ForeachWidget: FunctionComponent = ({ id, data, onEvent, onResize, loop }) => { const [boundaryMap, setBoundaryMap] = useState({}); const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); @@ -72,18 +71,11 @@ export const ForeachWidget: FunctionComponent = ({ id, dat } const { foreachNode, stepsNode, loopBeginNode, loopEndNode } = nodeMap; - const ForeachHeader = data.$type === ObiTypes.Foreach ? ForeachDetail : ForeachPageDetail; return (
- + {loop} diff --git a/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx b/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx index 5769eda9a1..2d7ce14cba 100644 --- a/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx +++ b/Composer/packages/extensions/visual-designer/src/widgets/IfConditionWidget.tsx @@ -15,7 +15,6 @@ import { Edge } from '../components/lib/EdgeComponents'; import { StepGroup } from '../components/groups'; import { Diamond } from '../components/nodes/templates/Diamond'; import { ElementWrapper } from '../components/renderers/ElementWrapper'; -import { ConditionNode } from '../components/nodes/steps/ConditionNode'; import { NodeMap, BoundaryMap } from '../components/nodes/types'; import { WidgetContainerProps } from '../schema/uischema.types'; @@ -40,8 +39,17 @@ const calculateLayout = (nodeMap: NodeMap, boundaryMap: BoundaryMap) => { return ifElseLayouter(nodeMap.conditionNode, nodeMap.choiceNode, nodeMap.ifGroupNode, nodeMap.elseGroupNode); }; -export type IfConditionWidgetProps = WidgetContainerProps; -export const IfConditionWidget: FunctionComponent = ({ id, data, onEvent, onResize }) => { +export interface IfConditionWidgetProps extends WidgetContainerProps { + judgement: JSX.Element; +} + +export const IfConditionWidget: FunctionComponent = ({ + id, + data, + onEvent, + onResize, + judgement, +}) => { const [boundaryMap, setBoundaryMap] = useState({}); const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); @@ -69,13 +77,7 @@ export const IfConditionWidget: FunctionComponent = ({ i
- + {judgement} diff --git a/Composer/packages/extensions/visual-designer/src/widgets/SwitchConditionWidget.tsx b/Composer/packages/extensions/visual-designer/src/widgets/SwitchConditionWidget.tsx index cd5597e265..eca024e423 100644 --- a/Composer/packages/extensions/visual-designer/src/widgets/SwitchConditionWidget.tsx +++ b/Composer/packages/extensions/visual-designer/src/widgets/SwitchConditionWidget.tsx @@ -15,7 +15,6 @@ import { Edge } from '../components/lib/EdgeComponents'; import { StepGroup } from '../components/groups'; import { Diamond } from '../components/nodes/templates/Diamond'; import { ElementWrapper } from '../components/renderers/ElementWrapper'; -import { ConditionNode } from '../components/nodes/steps/ConditionNode'; import { WidgetContainerProps } from '../schema/uischema.types'; const calculateNodeMap = (path, data) => { @@ -38,9 +37,17 @@ const calculateLayout = (nodeMap, boundaryMap) => { return switchCaseLayouter(nodeMap.conditionNode, nodeMap.choiceNode, nodeMap.branchNodes); }; -export type SwitchConditionWidgetProps = WidgetContainerProps; +export interface SwitchConditionWidgetProps extends WidgetContainerProps { + judgement: JSX.Element; +} -export const SwitchConditionWidget: FunctionComponent = ({ id, data, onEvent, onResize }) => { +export const SwitchConditionWidget: FunctionComponent = ({ + id, + data, + onEvent, + onResize, + judgement, +}) => { const [boundaryMap, setBoundaryMap] = useState({}); const initialNodeMap = useMemo(() => calculateNodeMap(id, data), [id, data]); const layout = useMemo(() => calculateLayout(initialNodeMap, boundaryMap), [initialNodeMap, boundaryMap]); @@ -69,13 +76,7 @@ export const SwitchConditionWidget: FunctionComponent = ({
- + {judgement} From 87306b55bfd7af61e89fdb2b3ef9e54b8efa175a Mon Sep 17 00:00:00 2001 From: Ze Ye Date: Fri, 24 Jan 2020 21:18:41 +0800 Subject: [PATCH 6/6] remove unused component --- .../components/nodes/steps/ConditionNode.tsx | 29 --------------- .../components/nodes/steps/ForeachDetail.tsx | 33 ----------------- .../nodes/steps/ForeachPageDetail.tsx | 37 ------------------- 3 files changed, 99 deletions(-) delete mode 100644 Composer/packages/extensions/visual-designer/src/components/nodes/steps/ConditionNode.tsx delete mode 100644 Composer/packages/extensions/visual-designer/src/components/nodes/steps/ForeachDetail.tsx delete mode 100644 Composer/packages/extensions/visual-designer/src/components/nodes/steps/ForeachPageDetail.tsx diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ConditionNode.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ConditionNode.tsx deleted file mode 100644 index 8cb21370e7..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ConditionNode.tsx +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import React, { FC } from 'react'; -import get from 'lodash/get'; -import formatMessage from 'format-message'; - -import { FormCard } from '../templates/FormCard'; -import { NodeProps } from '../nodeProps'; -import { getElementIcon, getElementColor } from '../../../utils/obiPropertyResolver'; -import { NodeMenu } from '../../menus/NodeMenu'; -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; - -export const ConditionNode: FC = ({ id, data, onEvent }) => { - const { $type } = data; - - return ( - } - nodeColors={getElementColor($type)} - onClick={() => { - onEvent(NodeEventTypes.Focus, { id }); - }} - /> - ); -}; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ForeachDetail.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ForeachDetail.tsx deleted file mode 100644 index 68bba40d92..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ForeachDetail.tsx +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import React, { FC } from 'react'; -import formatMessage from 'format-message'; -import { generateSDKTitle } from '@bfc/shared'; - -import { FormCard } from '../templates/FormCard'; -import { NodeProps } from '../nodeProps'; -import { getElementIcon, getElementColor } from '../../../utils/obiPropertyResolver'; -import { NodeMenu } from '../../menus/NodeMenu'; -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; - -export const ForeachDetail: FC = ({ id, data, onEvent }) => { - const { $type } = data; - const header = formatMessage('Loop: For Each'); - const label = `${formatMessage('Each value in')} {${data.itemsProperty || '?'}}`; - - return ( - } - nodeColors={getElementColor($type)} - onClick={() => { - onEvent(NodeEventTypes.Focus, { id }); - }} - /> - ); -}; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ForeachPageDetail.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ForeachPageDetail.tsx deleted file mode 100644 index ddd17ef1e3..0000000000 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/steps/ForeachPageDetail.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -import React, { FC } from 'react'; -import formatMessage from 'format-message'; -import get from 'lodash/get'; -import { generateSDKTitle } from '@bfc/shared'; - -import { FormCard } from '../templates/FormCard'; -import { NodeProps } from '../nodeProps'; -import { getElementIcon, getElementColor } from '../../../utils/obiPropertyResolver'; -import { NodeMenu } from '../../menus/NodeMenu'; -import { NodeEventTypes } from '../../../constants/NodeEventTypes'; - -export const ForeachPageDetail: FC = ({ id, data, onEvent }) => { - const { $type } = data; - - const header = formatMessage('Loop: For Each Page'); - const pageSizeString = get(data, 'pageSize', '?'); - const propString = get(data, 'itemsProperty', '?'); - const label = `${formatMessage('Each page of')} ${pageSizeString} ${formatMessage('in')} {${propString}}`; - - return ( - } - nodeColors={getElementColor($type)} - onClick={() => { - onEvent(NodeEventTypes.Focus, { id }); - }} - /> - ); -};