Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
7b8d5a6
draft: uischema flow part
yeze322 Aug 19, 2020
f4b55f8
draft: try define flow schema
yeze322 Aug 19, 2020
190d9fc
lint: blank line at EOF
yeze322 Aug 20, 2020
3858959
schema: add rest actions
yeze322 Aug 21, 2020
c24f2fa
schema: unify the schema of yml files
yeze322 Aug 21, 2020
b4d8944
schema: migrate schema to LG
yeze322 Aug 24, 2020
dab863b
feat: evaluate LG in widgetRenderer
yeze322 Aug 26, 2020
9337c71
Merge branch 'main' into visual/flow-schema
yeze322 Aug 26, 2020
8c65564
fix: capture LG eval error
yeze322 Aug 26, 2020
850052f
schema: migrate schema to LG; TODO: migrate to Exp
yeze322 Aug 26, 2020
0e516fc
feat: mixed evaluation with LG + Exp
yeze322 Aug 28, 2020
ede60b9
refactor: rename variables
yeze322 Aug 28, 2020
a298223
schema: migrate some actions to pure exp
yeze322 Aug 28, 2020
b91c8fd
Merge branch 'main' into visual/flow-schema
yeze322 Aug 31, 2020
b4c0cf5
fix: wrong result key in BeginDialog
yeze322 Aug 31, 2020
2f5d264
feat: add 'hideFooter' option to widgets/ActionCard
yeze322 Aug 31, 2020
97ff552
feat: new widget 'PropertyDescription'
yeze322 Aug 31, 2020
1f453e3
schema: migrate to PropertyDescription
yeze322 Aug 31, 2020
bb4d024
schema: migrate prev change to expression
yeze322 Aug 31, 2020
b073a7b
schema: migrat 3 kinds to PropertyDescription in exp
yeze322 Aug 31, 2020
6fa506a
schema: migrate DeleteActivity
yeze322 Aug 31, 2020
52ac6b5
feat: new widget 'ResourceOperation'
yeze322 Aug 31, 2020
7be2a2a
schema: migrate to 'ResourceOperation' widget
yeze322 Aug 31, 2020
70e7ee0
refactor: adjust schema reorder
yeze322 Aug 31, 2020
cf2a9a5
fix: more restrict regex for value access
yeze322 Aug 31, 2020
c5f2c7a
schema: migrate SetProperty to lg
yeze322 Aug 31, 2020
88cb093
refactor: rename ListOverview prop 'itemInterval'
yeze322 Aug 31, 2020
d83ecbd
refactor: optimize ListOverview interface desgin
yeze322 Aug 31, 2020
ea2fba4
schema: migrate SetProps, DelProps to Exp engine
yeze322 Aug 31, 2020
3d554a6
refactor: suffix builtin config files with '.ts'
yeze322 Aug 31, 2020
b3a115b
clean: remove yml drafts
yeze322 Aug 31, 2020
2db12a4
remove debug code
yeze322 Aug 31, 2020
dbf8c84
schema: expand *Input kinds definitions
yeze322 Aug 31, 2020
15e2893
refactor: move evaluator to Expression domain
yeze322 Sep 1, 2020
0835268
test: UT for widgetExpEvaluator
yeze322 Sep 1, 2020
e17d9c8
refactor: write inline color value in flow schema
yeze322 Sep 1, 2020
2906032
refactor: hoists Flow widget types to @bfc/extension
yeze322 Sep 1, 2020
0714d77
schema: move flow schema to extension pkg
yeze322 Sep 1, 2020
0216ded
feat: merge 'flow' part to uischema
yeze322 Sep 1, 2020
bad7d0f
fix: render ActionCard safely
yeze322 Sep 1, 2020
80f6c72
fix: move looping schema as Flow's builtin schema
yeze322 Sep 1, 2020
b35585b
feat: use pure expression way in Flow schema
yeze322 Sep 1, 2020
897745b
fix: handle evaluator corner case
yeze322 Sep 1, 2020
9d06807
schema: migrate whole schema to expression format
yeze322 Sep 1, 2020
891a69a
typo: space in schema
yeze322 Sep 1, 2020
77d279e
fix: respect null undfined value in ActionCard
yeze322 Sep 1, 2020
983b862
refactor: more robust safeRender
yeze322 Sep 1, 2020
3faf7dc
add a comment
yeze322 Sep 1, 2020
58e623d
schema: Oauth wording
yeze322 Sep 1, 2020
46a8699
fix: escape those constant strings begin with '='
yeze322 Sep 1, 2020
4206b40
Merge branch 'main' into visual/flow-schema
yeze322 Sep 1, 2020
67f306a
Merge branch 'main' into visual/flow-schema
yeze322 Sep 1, 2020
c230a03
Merge branch 'main' into visual/flow-schema
yeze322 Sep 1, 2020
abc7410
Merge branch 'main' into visual/flow-schema
yeze322 Sep 2, 2020
bac820a
feat: only evaluate Action with specific key
yeze322 Sep 8, 2020
7d4e9ce
schema: update '= Result' usages
yeze322 Sep 8, 2020
2053cdc
Merge branch 'main' into visual/flow-schema
yeze322 Sep 8, 2020
956600b
feat: be compatible with string interpolation pattern
yeze322 Sep 9, 2020
5200fa4
Merge branch 'main' into visual/flow-schema
yeze322 Sep 9, 2020
5c83928
Merge branch 'main' into visual/flow-schema
yeze322 Sep 10, 2020
9c46690
Merge branch 'main' into visual/flow-schema
yeze322 Sep 17, 2020
0f76a9b
manually fix some '@bfc/extension-client' imports
yeze322 Sep 17, 2020
593c674
fix ForeachPage prop binding
yeze322 Sep 17, 2020
307170a
Merge branch 'main' into visual/flow-schema
yeze322 Sep 17, 2020
d5f0d2f
Merge branch 'main' into visual/flow-schema
yeze322 Sep 21, 2020
1d5f215
Merge branch 'main' into visual/flow-schema
yeze322 Sep 24, 2020
a3f0dd7
Merge branch 'main' into visual/flow-schema
yeze322 Sep 24, 2020
589e4d2
Merge branch 'main' into visual/flow-schema
cwhitten Sep 28, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import {
evaluateWidgetProp,
ActionContextKey,
} from '../../../src/adaptive-flow-renderer/utils/expression/widgetExpressionEvaluator';

const evaluate = evaluateWidgetProp;
describe('evaluateWidgetProp()', () => {
it('can evaluate string interpolation pattern.', () => {
expect(evaluate('${a}, ${b}', { a: 1, b: 2 })).toEqual('1, 2');
});

it('return origin input when input non-expression string.', () => {
['hello', 'action.x', '= Result Value', '= ActivityId'].forEach((x) => {
expect(evaluate(x, {}, ActionContextKey)).toEqual(x);
});
});

it('can evaluate basic value access pattern.', () => {
expect(evaluate('=action.x', { action: { x: 1 } })).toEqual(1);

// Notes: Expression engine behavior. 'null' will be read as 'undefined'
expect(evaluate('=action.x', { action: { x: null } })).toEqual(undefined);
expect(evaluate('=action.x', { action: {} })).toEqual(undefined);
expect(evaluate('=action.x', { action: { x: undefined } })).toEqual(undefined);
expect(evaluate('=action.x', { action: { x: false } })).toEqual(false);

// Convert to string
expect(evaluate('=string(action.x)', { action: { x: null } })).toEqual(undefined);
expect(evaluate('=string(action.x)', { action: { x: undefined } })).toEqual(undefined);
expect(evaluate('=string(action.x)', { action: { x: false } })).toEqual('false');

// Case-insensitive
expect(evaluate('=action.x', { action: { x: 'x' } })).toEqual('x');
expect(evaluate('=action.x', { action: { X: 'x' } })).toEqual('x');
});

it('can evaluate expressions with foreach', () => {
expect(evaluate('=foreach(a.items, x=>x)', { a: { items: [] } })).toEqual([]);
expect(evaluate('=foreach(a.items, x=>x)', { a: { items: [1, 2] } })).toEqual([1, 2]);
expect(evaluate('=foreach(a.items, x=>x+1)', { a: { items: [1, 2] } })).toEqual([2, 3]);
expect(evaluate('=foreach(a.items, x=>x)', { a: { items: ['1'] } })).toEqual(['1']);
expect(evaluate('=foreach(a.items, x=>x+1)', { a: { items: ['1'] } })).toEqual(['11']);
expect(evaluate('=foreach(a.items, x=>x+"1")', { a: { items: ['1'] } })).toEqual(['11']);
});

it('can evaluate expressions with if', () => {
expect(evaluate('=if(a.x, "1", "2")', { a: { x: true } })).toEqual('1');
expect(evaluate('=if(a.x, "1", "2")', { a: { X: true } })).toEqual('1');
expect(evaluate('=if(a.x, "1", "2")', { a: { x: '' } })).toEqual('1');
expect(evaluate('=if(a.x, "1", "2")', { a: { x: 0 } })).toEqual('1');
expect(evaluate('=if(a.x<1, "1", "2")', { a: { x: 0 } })).toEqual('1');

expect(evaluate('=if(a.x, "1", "2")', { a: { x: false } })).toEqual('2');
expect(evaluate('=if(a.x, "1", "2")', { a: {} })).toEqual('2');
expect(evaluate('=if(a.x, "1", "2")', { a: { x: null } })).toEqual('2');
expect(evaluate('=if(a.x, "1", "2")', { a: { x: undefined } })).toEqual('2');
});

it('can evaluate string template pattern.', () => {
expect(evaluate('=concat(a.x, " and ", a.y)', { a: { x: 'x', y: 'y' } })).toEqual('x and y');
expect(evaluate('=concat(a.x, " and ", a.y)', { a: { X: 'X', Y: 'Y' } })).toEqual('X and Y');
expect(evaluate('=concat(a.x, " and ", a.y)', { a: { x: 1 } })).toEqual('1 and ');
expect(evaluate('=concat(string(a.x), " and ", string(a.y))', { a: { x: { val: 1 }, y: [1] } })).toEqual(
'{"val":1} and [1]'
);
});

describe('can evaluate real Flow use case', () => {
it('in Foreach.', () => {
expect(
evaluate('=concat("Each value in ", coalesce(action.itemsProperty, "?"))', {
action: { itemsProperty: 'user.names' },
})
).toEqual('Each value in user.names');
expect(evaluate('=concat("Each value in ", coalesce(action.itemsProperty, "?"))', { action: {} })).toEqual(
'Each value in ?'
);
});

it('in SetProperties.', () => {
expect(
evaluate('=foreach(action.assignments, x => concat(x.property, " : " ,x.value))', {
action: {
assignments: [
{ property: 'a', value: 1 },
{ property: 'b', value: '2' },
],
},
})
).toEqual(['a : 1', 'b : 2']);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@

import React from 'react';
import { render } from '@bfc/test-utils';
import { WidgetComponent, FlowEditorWidgetMap } from '@bfc/extension-client';
import { WidgetComponent, FlowEditorWidgetMap, FlowWidget } from '@bfc/extension-client';

import { renderUIWidget, UIWidgetContext } from '../../../src/adaptive-flow-renderer/utils/visual/widgetRenderer';
import { FlowWidget } from '../../../src/adaptive-flow-renderer/types/flowRenderer.types';

const renderWidget = (schema: FlowWidget, widgetsMap: FlowEditorWidgetMap, context: UIWidgetContext) => {
const TestResult = () => renderUIWidget(schema, widgetsMap, context);
Expand Down
2 changes: 2 additions & 0 deletions Composer/packages/adaptive-flow/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
"@bfc/ui-shared": "*",
"@emotion/core": "^10.0.27",
"@emotion/styled": "^10.0.27",
"adaptive-expressions": "4.10.0-preview-147186",
"botbuilder-lg": "^4.10.0-preview-150886",
"create-react-class": "^15.6.3",
"d3": "^5.9.1",
"dagre": "^0.8.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import React, { useRef, useMemo, useEffect } from 'react';
import isEqual from 'lodash/isEqual';
import formatMessage from 'format-message';
import { DialogFactory } from '@bfc/shared';
import { useShellApi, JSONSchema7 } from '@bfc/extension-client';
import { useShellApi, JSONSchema7, FlowUISchema, FlowWidget } from '@bfc/extension-client';
import { MarqueeSelection } from 'office-ui-fabric-react/lib/MarqueeSelection';

import { FlowSchema, FlowWidget } from '../adaptive-flow-renderer/types/flowRenderer.types';
import { NodeEventTypes } from '../adaptive-flow-renderer/constants/NodeEventTypes';
import { AdaptiveDialog } from '../adaptive-flow-renderer/adaptive/AdaptiveDialog';

Expand Down Expand Up @@ -105,7 +104,7 @@ const VisualDesigner: React.FC<VisualDesignerProps> = ({ onFocus, onBlur, schema
customSchemas: customActionSchema ? [customActionSchema] : [],
};

const customFlowSchema: FlowSchema = nodeContext.customSchemas.reduce((result, s) => {
const customFlowSchema: FlowUISchema = nodeContext.customSchemas.reduce((result, s) => {
const definitionKeys: string[] = Object.keys(s.definitions);
definitionKeys.forEach(($kind) => {
result[$kind] = {
Expand All @@ -114,7 +113,7 @@ const VisualDesigner: React.FC<VisualDesignerProps> = ({ onFocus, onBlur, schema
} as FlowWidget;
});
return result;
}, {} as FlowSchema);
}, {} as FlowUISchema);

const divRef = useRef<HTMLDivElement>(null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import { jsx } from '@emotion/core';
import { FC, Fragment } from 'react';
import get from 'lodash/get';
import { FlowEditorWidgetMap as NodeWidgetMap } from '@bfc/extension-client';
import { FlowEditorWidgetMap, FlowUISchema } from '@bfc/extension-client';

import { FlowSchema } from '../types/flowRenderer.types';
import { EditorEventHandler } from '../constants/NodeEventTypes';
import { RendererContext, DefaultRenderers, RendererContextData } from '../contexts/RendererContext';
import builtinSchema from '../configs/builtinSchema';
Expand All @@ -31,10 +30,10 @@ export interface AdaptiveDialogProps {
onEvent: EditorEventHandler;

/** UI schema to define how to render a sdk $kind */
schema: FlowSchema;
schema: FlowUISchema;

/** All available widgets to render a node */
widgets: NodeWidgetMap;
widgets: FlowEditorWidgetMap;
renderers?: Partial<RendererContextData>;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { SDKKinds } from '@bfc/shared';
import { FlowUISchema } from '@bfc/extension-client';

const builtinVisualSDKSchema: FlowUISchema = {
default: {
widget: 'ActionHeader',
},
custom: {
widget: 'ActionHeader',
colors: { theme: '#69797E', color: '#FFFFFF' },
},
[SDKKinds.IfCondition]: {
widget: 'IfConditionWidget',
nowrap: true,
judgement: {
widget: 'ActionCard',
body: '=coalesce(action.condition, "<condition>")',
},
},
[SDKKinds.SwitchCondition]: {
widget: 'SwitchConditionWidget',
nowrap: true,
judgement: {
widget: 'ActionCard',
body: '=coalesce(action.condition, "<condition>")',
},
},
[SDKKinds.Foreach]: {
widget: 'ForeachWidget',
nowrap: true,
loop: {
widget: 'ActionCard',
body: '=concat("Each value in ", coalesce(action.itemsProperty, "?"))',
},
},
[SDKKinds.ForeachPage]: {
widget: 'ForeachWidget',
nowrap: true,
loop: {
widget: 'ActionCard',
body: '=concat("Each page of ", coalesce(action.pageSize, "?"), " in ", coalesce(action.page, "?"))',
},
},
};

export default builtinVisualSDKSchema;
Loading