Skip to content

Commit

Permalink
feat: Schema-driven visual editor - migrates 15 simple types (#1811)
Browse files Browse the repository at this point in the history
* uischema def

* uischema v0 def (basic types)

* consume uischema

* fix demo

* add renderSDK demo

* fix a title getter bug

* better demo page

* add contextProps

* support DeleteProperties

* fix demo page

* add specific renderer for ConditonNode

* retire ConditionNode from DefaultRenderer

* register ForeachDetail & ForeachpageDetail in upper level

* move label calculation to new renderer

* migrate DefaultRenderer to uischema renderer

* fix lint warning

* apply `formatMessage` to node lib

* let formatMessage receive string literal

* move title logic into ActionCard

* move `generateSDKTitle` into 'shared'

* apply `generateSDKTitle` to all nodes

* retire `getFriendlyName`

* change title priority

* uncheck 'SampleBots' folder
  • Loading branch information
yeze322 authored and a-b-r-o-w-n committed Jan 6, 2020
1 parent cb57161 commit 9167702
Show file tree
Hide file tree
Showing 19 changed files with 465 additions and 206 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { EditorConfig } from '../../src/editors/editorConfig';
import { VisualEditorDemo } from './stories/VisualEditorDemo';
import { StepEditorDemo } from './stories/StepEditorDemo';
import { EventsEditorDemo } from './stories/EventsEditorDemo';
import { VisualSDKDemo } from './stories/VisualSDKDemo';
import './index.css';

initializeIcons(undefined, { disableWarnings: true });
Expand All @@ -27,6 +28,10 @@ const DemoMaps = {
key: 'EventsEditorDemo',
component: EventsEditorDemo,
},
VisualSDKDemo: {
key: 'VisualSDKDemo',
component: VisualSDKDemo,
},
};

class Demo extends Component {
Expand Down Expand Up @@ -61,6 +66,10 @@ class Demo extends Component {
key: DemoMaps.EventsEditorDemo.key,
name: 'Event Editor',
},
{
key: DemoMaps.VisualSDKDemo.key,
name: 'Visual SDK',
},
],
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { Component } from 'react';
import { seedNewDialog, SDKTypes } from '@bfc/shared';

import { renderSDKType } from '../../../src/schema/uischemaRenderer';
import { EdgeMenu } from '../../../src/components/menus/EdgeMenu';
import { JsonBlock } from '../components/json-block';

import './story.css';

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

seedInitialActions() {
const initialTypes = [
SDKTypes.EditArray,
SDKTypes.InitProperty,
SDKTypes.SetProperties,
SDKTypes.SetProperty,
SDKTypes.DeleteProperties,
SDKTypes.DeleteProperty,
SDKTypes.EndDialog,
SDKTypes.CancelAllDialogs,
SDKTypes.EmitEvent,
];
const initalActions = initialTypes.map(t => seedNewDialog(t));
return initalActions;
}

appendActionPreview($type) {
this.setState({
actions: [...this.state.actions, seedNewDialog($type)],
});
}

renderActionPreview(action, index) {
return (
<div
className="action-preview"
key={`action-preview-${index}`}
style={{ display: 'flex', flexDirection: 'row', margin: 10 }}
>
<div className="action-preview--raw">
<JsonBlock
styles={{
width: '200px',
height: '80px',
fontSize: '8px',
}}
defaultValue={action}
onSubmit={newAction => {
const newActions = [...this.state.actions];
newActions[index] = newAction;
this.setState({
actions: newActions,
});
}}
/>
</div>
<div className="action-preview--visual">{renderSDKType(action)}</div>
</div>
);
}

renderActionFactory() {
return (
<div style={{ height: 100, margin: 20 }}>
<h3>Create action by $type</h3>
<EdgeMenu id="visual-sdk-demo" onClick={$type => this.appendActionPreview($type)} />
</div>
);
}

render() {
return (
<div className="story-container">
<h1 className="story-title">Visual SDK Demo</h1>
<div className="story-content" style={{ display: 'flex', flexFlow: 'wrap' }}>
{this.state.actions.map((action, index) => this.renderActionPreview(action, index))}
{this.renderActionFactory()}
</div>
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.story-container {
height: 100%;
}

.story-title {
height: 50px;
margin: 0;
}

.story-content {
display: flex;
flex-direction: row;
height: calc(100% - 60px);
}

.block {
border: 1px solid grey;
margin: 10px;
width: 50%;
overflow: auto;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ module.exports = {
port: 3001,
stats: 'errors-only',
},
node: {
fs: 'empty',
},
module: {
rules: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,29 @@
// 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 { getFriendlyName } from '../utils';
import { useLgTemplate } from '../../../utils/hooks';

export const ActivityRenderer: React.FC<NodeProps> = 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 (
<FormCard
nodeColors={nodeColors}
header={getFriendlyName(data) || 'Activity'}
corner={<NodeMenu id={id} onEvent={onEvent} />}
icon={ElementIcon.MessageBot}
header={generateSDKTitle(data, header)}
label={templateText}
icon={ElementIcon.MessageBot}
corner={<NodeMenu id={id} onEvent={onEvent} />}
nodeColors={nodeColors}
onClick={() => {
onEvent(NodeEventTypes.Focus, { id });
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
/** @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';
import { getFriendlyName } from '../utils';

export class BeginDialog extends React.Component<NodeProps, object> {
static defaultProps = defaultNodeProps;
Expand Down Expand Up @@ -38,12 +39,13 @@ export class BeginDialog extends React.Component<NodeProps, object> {
render() {
const { id, data, onEvent } = this.props;
const nodeColors = getElementColor(data.$type);
const header = formatMessage('BeginDialog');
return (
<FormCard
nodeColors={nodeColors}
header={getFriendlyName(data) || 'BeginDialog'}
corner={<NodeMenu id={id} onEvent={onEvent} />}
header={generateSDKTitle(data, header)}
label={this.renderCallDialogLink()}
corner={<NodeMenu id={id} onEvent={onEvent} />}
nodeColors={nodeColors}
onClick={() => {
onEvent(NodeEventTypes.Focus, { id });
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// 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<NodeProps> = ({ id, data, onEvent }) => {
const { $type } = data;

return (
<FormCard
header={formatMessage('Branch')}
label={get(data, 'condition', '')}
icon={getElementIcon($type)}
corner={<NodeMenu id={id} onEvent={onEvent} />}
nodeColors={getElementColor($type)}
onClick={() => {
onEvent(NodeEventTypes.Focus, { id });
}}
/>
);
};
Loading

0 comments on commit 9167702

Please sign in to comment.