Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Visual Editor as an extension #2586

Merged
merged 31 commits into from
Apr 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ba3ee88
rename 'ui:widget' field to 'widget'
yeze322 Apr 9, 2020
8117050
change default widget to ActionHeader
yeze322 Apr 9, 2020
8517e09
fix visual editor demo
yeze322 Apr 9, 2020
768b618
simplify visual schema
yeze322 Apr 9, 2020
2a02a3e
support loading widgets via reflection
yeze322 Apr 9, 2020
dd6f6ec
uischema -> visualSchema
yeze322 Apr 9, 2020
f950d7e
drive TypesWithoutWrapper as 'nowrap' in schema
yeze322 Apr 9, 2020
3efc81f
remove outdated files
yeze322 Apr 9, 2020
3abb2bf
hoists visualSchema.types to @bfc/extension
yeze322 Apr 9, 2020
ae29b53
rename visualSchema to defaultVisualSchema
yeze322 Apr 9, 2020
8ac9a5d
fix demo
yeze322 Apr 10, 2020
87ae90b
consume Extension context in Visual
yeze322 Apr 10, 2020
c0753a5
declare schema as Visual Props
yeze322 Apr 10, 2020
e7b65ec
let visual editor consume plugin schema
yeze322 Apr 10, 2020
f817e4b
split visual config to widgets & schema
yeze322 Apr 10, 2020
2603641
implement visual plugin merge strategy
yeze322 Apr 10, 2020
0442ddd
migrate SendActivity to Lg plugin
yeze322 Apr 10, 2020
21198af
move styled components to external lib
yeze322 Apr 10, 2020
5bba968
move prompts visual schema to 'prompts' plugin
yeze322 Apr 10, 2020
5935ef6
rename @visual-designer-elements to @ui-shared
yeze322 Apr 10, 2020
3f3f1a9
Merge branch 'master' into visual/extension
yeze322 Apr 10, 2020
331a842
Merge branch 'master' into visual/extension
yeze322 Apr 13, 2020
4f23e2f
use ui-shared in LG
yeze322 Apr 13, 2020
02e5e87
fix visual widget type declaration
yeze322 Apr 13, 2020
f192fd3
add missing workspace dependency
yeze322 Apr 13, 2020
c310b76
remove ActivityRenderer (replaced by LgWidget)
yeze322 Apr 13, 2020
af9aebe
remove unref vars
yeze322 Apr 13, 2020
6c417b1
Merge branch 'master' into visual/extension
yeze322 Apr 14, 2020
d1dc1c0
rename: visualSchema -> flowSchema
yeze322 Apr 14, 2020
10db578
update config key to `visualSchema`
yeze322 Apr 14, 2020
ce8442e
chore: rename 'uiSchema' in PluginConfig to 'formSchema' (#2634)
yeze322 Apr 14, 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
Expand Up @@ -79,12 +79,7 @@ const VisualEditor: React.FC<VisualEditorProps> = props => {
data-testid="VisualEditor"
>
<Extension shell={shellApi} shellData={shellData} plugins={plugins}>
<VisualDesigner
{...shellData}
onChange={shellApi.saveData}
shellApi={shellApi as any}
schema={schemas.sdk?.content}
/>
<VisualDesigner schema={schemas.sdk?.content} />
</Extension>
</div>
{!selected && onRenderBlankVisual(triggerButtonVisible, openNewTriggerModal)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import React from 'react';
import { PluginConfig } from '@bfc/extension';

const PluginContext = React.createContext<Required<PluginConfig>>({
uiSchema: {},
formSchema: {},
visualSchema: {},
roleSchema: {},
// kindSchema: {},
recognizers: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export const AdaptiveForm: React.FC<AdaptiveFormProps> = function AdaptiveForm(p
}, []);

const $uiSchema = useMemo(() => {
return getUISchema($schema, pluginConfig.uiSchema);
return getUISchema($schema, pluginConfig.formSchema);
}, [$schema, pluginConfig]);

const errors = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const SchemaField: React.FC<FieldProps> = props => {
const pluginConfig = usePluginConfig();
const schema = resolveRef(baseSchema, definitions);
const uiOptions = {
...getUISchema(schema, pluginConfig.uiSchema),
...getUISchema(schema, pluginConfig.formSchema),
...baseUIOptions,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import DefaultRecognizers from '../../defaultRecognizers';
describe('mergePluginConfigs', () => {
it('returns default ui schema when no overrides', () => {
expect(mergePluginConfigs()).toEqual({
uiSchema: DefaultUISchema,
formSchema: DefaultUISchema,
roleSchema: DefaultRoleSchema,
recognizers: DefaultRecognizers,
});
});

it('merges overrides into the defaults', () => {
const overrides = {
uiSchema: {
formSchema: {
[SDKKinds.AdaptiveDialog]: {
hidden: ['recognizer'],
properties: {
Expand All @@ -38,27 +38,7 @@ describe('mergePluginConfigs', () => {

expect(mergePluginConfigs(overrides)).toMatchInlineSnapshot(`
Object {
"recognizers": Array [
Object {
"displayName": [Function],
"handleRecognizerChange": [Function],
"id": "none",
"isSelected": [Function],
},
Object {
"displayName": [Function],
"editor": [Function],
"handleRecognizerChange": [Function],
"id": "Microsoft.RegexRecognizer",
"isSelected": [Function],
},
],
"roleSchema": Object {
"expression": Object {
"label": "expression label",
},
},
"uiSchema": Object {
"formSchema": Object {
"Microsoft.AdaptiveDialog": Object {
"description": [Function],
"helpLink": "https://aka.ms/botframework",
Expand Down Expand Up @@ -506,6 +486,26 @@ Object {
"label": [Function],
},
},
"recognizers": Array [
Object {
"displayName": [Function],
"handleRecognizerChange": [Function],
"id": "none",
"isSelected": [Function],
},
Object {
"displayName": [Function],
"editor": [Function],
"handleRecognizerChange": [Function],
"id": "Microsoft.RegexRecognizer",
"isSelected": [Function],
},
],
"roleSchema": Object {
"expression": Object {
"label": "expression label",
},
},
}
`);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('resolveFieldWidget', () => {
field: DefaultFields.StringField,
},
},
uiSchema: {},
formSchema: {},
recognizers: [],
};

Expand All @@ -51,7 +51,7 @@ describe('resolveFieldWidget', () => {

const globalSchema = {
roleSchema: {},
uiSchema: {
formSchema: {
'Microsoft.Recognizer': {
field: DefaultFields.RecognizerField,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import DefaultRoleSchema from '../defaultRoleSchema';
import DefaultRecognizers from '../defaultRecognizers';

const defaults: PluginConfig = {
uiSchema: DefaultUISchema,
formSchema: DefaultUISchema,
roleSchema: DefaultRoleSchema,
recognizers: DefaultRecognizers,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function resolveFieldWidget(
return RoleOverride;
}

const KindOverride = schema.$kind && globalConfig?.uiSchema[schema.$kind]?.field;
const KindOverride = schema.$kind && globalConfig?.formSchema[schema.$kind]?.field;

if (KindOverride) {
return KindOverride;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { UISchema, RoleSchema, RecognizerSchema } from './uiSchema';
import { UISchema, RoleSchema, RecognizerSchema } from './formSchema';
import { FlowEditorConfig } from './flowSchema';

export interface PluginConfig {
uiSchema?: UISchema;
formSchema?: UISchema;
roleSchema?: RoleSchema;
recognizers?: RecognizerSchema[];
visualSchema?: FlowEditorConfig;
}
45 changes: 45 additions & 0 deletions Composer/packages/extensions/extension/src/types/flowSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { FC, ComponentClass } from 'react';
import { BaseSchema, SDKKinds } from '@bfc/shared';

export interface FlowEditorConfig {
widgets?: FlowEditorWidgetMap;
schema?: FlowSchema;
}

export type FlowEditorWidgetMap = { [widgetName: string]: WidgetComponent<any> };
export enum FlowSchemaBuiltinKeys {
default = 'default',
}

/** schema */
export type FlowSchema = {
[key in SDKKinds | FlowSchemaBuiltinKeys]?: FlowWidget;
};

export interface FlowWidget {
/** Widget implementation (React Class) or Widget name (string) */
widget: string | WidgetComponent<any>;

/** If set to true, output widget will be borderless (usually applied to IfCondition, SwitchCondition) */
nowrap?: boolean;

[propKey: string]: FlowWidgetProp;
}

export type WidgetComponent<T extends WidgetContainerProps> = FC<T> | ComponentClass<T, any>;

export type WidgetEventHandler = (eventName: string, eventData?: any) => void;

export interface WidgetContainerProps {
id: string;
data: BaseSchema;
onEvent: WidgetEventHandler;
[propKey: string]: any;
}

export type FlowWidgetProp = Value | PropGenerator | FlowWidget;
type Value = string | number | boolean | undefined | { [key: string]: any };
type PropGenerator = (data: any) => string | number | object | JSX.Element;
2 changes: 1 addition & 1 deletion Composer/packages/extensions/extension/src/types/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
import React from 'react';

import { UIOptions } from './uiSchema';
import { UIOptions } from './formSchema';

declare module 'json-schema' {
interface JSONSchema7 {
Expand Down
4 changes: 3 additions & 1 deletion Composer/packages/extensions/extension/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export * from './extension';
export * from './form';
export * from './uiSchema';
export * from './formSchema';
export * from './flowSchema';
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import { DialogFactory, dialogGroups, DialogGroup } from '@bfc/shared';

import { EdgeMenu } from '../../../src/components/menus/EdgeMenu';
import { JsonBlock } from '../components/json-block';
import { renderUIWidget } from '../../../src/schema/uischemaRenderer';
import { UISchemaProvider } from '../../../src/schema/uischemaProvider';
import { uiSchema } from '../../../src/schema/uischema';
import { renderUIWidget } from '../../../src/schema/flowSchemaRenderer';
import { FlowSchemaProvider } from '../../../src/schema/flowSchemaProvider';
import { defaultFlowSchema } from '../../../src/schema/defaultFlowSchema';

import './story.css';

const uiSchemaPrivider = new UISchemaProvider(uiSchema);
const uiSchemaPrivider = new FlowSchemaProvider(defaultFlowSchema);
const actionFactory = new DialogFactory({});

export class VisualSDKDemo extends Component {
state = {
actions: this.seedInitialActions(),
};
factory = new DialogFactory({});

seedInitialActions() {
const initialTypes = [
Expand All @@ -27,7 +27,7 @@ export class VisualSDKDemo extends Component {
...dialogGroups[DialogGroup.CODE].types,
...dialogGroups[DialogGroup.LOG].types,
];
const initalActions = initialTypes.map(t => this.factory.create(t));
const initalActions = initialTypes.map(t => actionFactory.create(t));
return initalActions;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ module.exports = {
use: [
{
loader: 'style-loader',
options: {
hmr: true,
sourceMap: true,
},
},
{ loader: 'css-loader', options: { importLoaders: 1 } },
{
Expand All @@ -73,10 +69,6 @@ module.exports = {
use: [
{
loader: 'style-loader',
options: {
hmr: true,
sourceMap: true,
},
},
{ loader: 'css-loader', options: { importLoaders: 1 } },
{
Expand Down
5 changes: 4 additions & 1 deletion Composer/packages/extensions/visual-designer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"lint:fix": "yarn lint --fix"
},
"dependencies": {
"@bfc/extension": "*",
"@bfc/shared": "*",
"@bfc/ui-shared": "*",
"@emotion/core": "^10.0.27",
"@emotion/styled": "^10.0.27",
"classnames": "^2.2.6",
Expand Down Expand Up @@ -59,7 +61,8 @@
"react-dom": "16.13.0",
"react-testing-library": "^6.0.2",
"ts-jest": "^24.1.0",
"ts-loader": "^6.0.3"
"ts-loader": "^6.0.3",
"tsconfig-paths-webpack-plugin": "^3.2.0"
},
"author": "",
"homepage": "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import { FC, ReactNode } from 'react';
import { TextDiv } from '@bfc/ui-shared';

import { StandardNodeWidth, HeaderHeight, StandardSectionHeight } from '../../../constants/ElementSizes';
import { ObiColors } from '../../../constants/ElementColors';
import { ArrowLine } from '../../lib/ArrowLine';
import { TextDiv } from '../../elements/styledComponents';

const containerCSS = css`
font-size: 12px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,23 @@
/** @jsx jsx */
import { jsx } from '@emotion/core';
import { FC, useContext } from 'react';
import { SDKKinds } from '@bfc/shared';
import get from 'lodash/get';

import { NodeProps, defaultNodeProps } from '../nodes/nodeProps';
import { renderUIWidget } from '../../schema/uischemaRenderer';
import { UISchemaContext } from '../../store/UISchemaContext';
import { renderUIWidget } from '../../schema/flowSchemaRenderer';
import { FlowSchemaContext } from '../../store/FlowSchemaContext';

import { ElementWrapper } from './ElementWrapper';
import { ElementMeasurer } from './ElementMeasurer';

/** TODO: (zeye) integrate this array into UISchema */
const TypesWithoutWrapper = [
SDKKinds.IfCondition,
SDKKinds.SwitchCondition,
SDKKinds.Foreach,
SDKKinds.ForeachPage,
SDKKinds.AttachmentInput,
SDKKinds.ConfirmInput,
SDKKinds.DateTimeInput,
SDKKinds.NumberInput,
SDKKinds.TextInput,
SDKKinds.ChoiceInput,
];

export const StepRenderer: FC<NodeProps> = ({ id, data, onEvent, onResize }): JSX.Element => {
const schemaProvider = useContext(UISchemaContext);
const { widgets, schemaProvider } = useContext(FlowSchemaContext);

const $kind = get(data, '$kind', '');
const widgetSchema = schemaProvider.get($kind);

const content = renderUIWidget(widgetSchema, { id, data, onEvent, onResize });
if (TypesWithoutWrapper.some(x => $kind === x)) {
const content = renderUIWidget(widgetSchema, widgets, { id, data, onEvent, onResize });
if (widgetSchema.nowrap) {
return content;
}
return (
Expand Down
Loading