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: support bot project's ui schema #3680

Merged
merged 21 commits into from
Jul 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
878c29a
remove inspect port when starting server
a-b-r-o-w-n Jul 8, 2020
706fc24
wip - use map for project files data structure
a-b-r-o-w-n Jul 8, 2020
b9a093c
Merge branch 'master' into abrown/feat/bot-project-ui-schema
a-b-r-o-w-n Jul 9, 2020
e115a61
complete refactor of files into a map
a-b-r-o-w-n Jul 9, 2020
9f79948
Merge branch 'main' into abrown/feat/bot-project-ui-schema
a-b-r-o-w-n Jul 13, 2020
de69bbc
support app.uischema naming convention
a-b-r-o-w-n Jul 13, 2020
c74ba8b
move expression field into adaptive form package
a-b-r-o-w-n Jul 13, 2020
68b040a
update ui plugins to new ui schema
a-b-r-o-w-n Jul 13, 2020
c887702
support new ui schema shape
a-b-r-o-w-n Jul 15, 2020
532ed0f
Merge branch 'main' into abrown/feat/bot-project-ui-schema
a-b-r-o-w-n Jul 20, 2020
3927f62
load user overrides to ui schema
a-b-r-o-w-n Jul 21, 2020
67e3ff5
fix typos
a-b-r-o-w-n Jul 21, 2020
2a96ed4
Merge branch 'main' into abrown/feat/bot-project-ui-schema
a-b-r-o-w-n Jul 22, 2020
9c164e1
update jest name
a-b-r-o-w-n Jul 22, 2020
6732b18
add some unit tests
a-b-r-o-w-n Jul 22, 2020
718f293
update menu type
a-b-r-o-w-n Jul 22, 2020
33d4043
Merge branch 'main' into abrown/feat/bot-project-ui-schema
a-b-r-o-w-n Jul 22, 2020
a6eb84b
fix merging of flow config
a-b-r-o-w-n Jul 23, 2020
ce36b6e
Merge branch 'main' into abrown/feat/bot-project-ui-schema
a-b-r-o-w-n Jul 23, 2020
22649ea
add fallback uischema
a-b-r-o-w-n Jul 23, 2020
a13fe91
load default ui schema if none found in bot project
a-b-r-o-w-n Jul 23, 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
1 change: 0 additions & 1 deletion Composer/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ module.exports = {
'<rootDir>/packages/server',
'<rootDir>/packages/electron-server',
'<rootDir>/packages/tools/language-servers/language-generation',
'<rootDir>/packages/ui-plugins/expressions',
'<rootDir>/packages/ui-plugins/lg',
'<rootDir>/packages/ui-plugins/luis',
'<rootDir>/packages/ui-plugins/prompts',
Expand Down
92 changes: 92 additions & 0 deletions Composer/packages/client/__tests__/plugins.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { mergePluginConfigs } from '../src/plugins';

describe('mergePluginConfigs', () => {
it('merges plugin configs from left to right', () => {
const config1 = {
uiSchema: {
'Microsoft.SendActivity': {
form: {
label: 'default label',
},
},
},
};
const config2 = {
uiSchema: {
'Microsoft.SendActivity': {
form: {
description: 'new description',
},
},
},
};
const config3 = {
uiSchema: {
'Microsoft.SendActivity': {
form: {
label: 'label override',
},
},
},
};

const result = mergePluginConfigs(config1, config2, config3);
expect(result).toEqual({
uiSchema: {
'Microsoft.SendActivity': {
form: {
label: 'label override',
description: 'new description',
},
},
},
recognizers: [],
flowWidgets: {},
});
});

it('adds recognizers', () => {
const config1 = {
recognizers: ['recognizer 1'],
};

const config2 = {
recognizers: ['recognizer 2'],
};

// @ts-expect-error
expect(mergePluginConfigs(config1, config2).recognizers).toEqual(['recognizer 1', 'recognizer 2']);
});

it('replaces other arrays', () => {
const config1 = {
uiSchema: {
'Microsoft.SendActivity': {
form: {
order: ['foo', 'bar'],
},
},
},
};
const config2 = {
uiSchema: {
'Microsoft.SendActivity': {
form: {
order: ['baz', '*'],
},
},
},
};

expect(mergePluginConfigs(config1, config2).uiSchema).toEqual({
'Microsoft.SendActivity': {
form: {
order: ['baz', '*'],
},
},
});
});
});
2 changes: 1 addition & 1 deletion Composer/packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@bfc/extension": "*",
"@bfc/indexers": "*",
"@bfc/shared": "*",
"@bfc/ui-plugin-expressions": "*",
"@bfc/ui-plugin-composer": "*",
"@bfc/ui-plugin-lg": "*",
"@bfc/ui-plugin-luis": "*",
"@bfc/ui-plugin-prompts": "*",
Expand Down
25 changes: 14 additions & 11 deletions Composer/packages/client/src/pages/design/PropertyEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
/** @jsx jsx */
import { jsx } from '@emotion/core';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import AdaptiveForm, { resolveRef, getUIOptions, mergePluginConfigs } from '@bfc/adaptive-form';
import Extension, { FormErrors, JSONSchema7 } from '@bfc/extension';
import AdaptiveForm, { resolveRef, getUIOptions } from '@bfc/adaptive-form';
import Extension, { FormErrors, JSONSchema7, PluginConfig } from '@bfc/extension';
import formatMessage from 'format-message';
import isEqual from 'lodash/isEqual';
import debounce from 'lodash/debounce';
import mapValues from 'lodash/mapValues';
import { Resizable, ResizeCallback } from 're-resizable';
import { MicrosoftAdaptiveDialog } from '@bfc/shared';

import { useShell } from '../../shell';
import plugins from '../../plugins';
import plugins, { mergePluginConfigs } from '../../plugins';

import { formEditor } from './styles';

Expand Down Expand Up @@ -62,12 +63,15 @@ const PropertyEditor: React.FC = () => {
}
}, [schemas?.sdk?.content, localData.$kind]);

const pluginConfig = useMemo(() => {
return mergePluginConfigs(...plugins);
}, []);
const pluginConfig: PluginConfig = useMemo(() => {
const sdkUISchema = schemas?.ui?.content ?? {};
const userUISchema = schemas?.uiOverrides?.content ?? {};

const $uiSchema = useMemo(() => {
return getUIOptions($schema, pluginConfig.formSchema, pluginConfig.roleSchema);
return mergePluginConfigs({ uiSchema: sdkUISchema }, plugins, { uiSchema: userUISchema });
}, [schemas?.ui?.content, schemas?.uiOverrides?.content]);

const $uiOptions = useMemo(() => {
return getUIOptions($schema, mapValues(pluginConfig.uiSchema, 'form'));
}, [$schema, pluginConfig]);

const errors = useMemo(() => {
Expand Down Expand Up @@ -129,13 +133,12 @@ const PropertyEditor: React.FC = () => {
onResizeStop={handleResize}
>
<div aria-label={formatMessage('form editor')} css={formEditor} data-testid="PropertyEditor" role="region">
<Extension plugins={plugins} shell={shellApi} shellData={shellData}>
<Extension plugins={pluginConfig} shell={shellApi} shellData={shellData}>
<AdaptiveForm
errors={errors}
formData={localData}
pluginConfig={pluginConfig}
schema={$schema}
uiOptions={$uiSchema}
uiOptions={$uiOptions}
onChange={handleDataChange}
/>
</Extension>
Expand Down
32 changes: 30 additions & 2 deletions Composer/packages/client/src/plugins.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import expressions from '@bfc/ui-plugin-expressions';
import mergeWith from 'lodash/mergeWith';
import isArray from 'lodash/isArray';
// this is just a type import
// eslint-disable-next-line lodash/import-scope
import type { MergeWithCustomizer } from 'lodash';
import type { PluginConfig } from '@bfc/extension';
import composer from '@bfc/ui-plugin-composer';
import prompts from '@bfc/ui-plugin-prompts';
import selectDialog from '@bfc/ui-plugin-select-dialog';
import selectSkillDialog from '@bfc/ui-plugin-select-skill-dialog';
import lg from '@bfc/ui-plugin-lg';
import lu from '@bfc/ui-plugin-luis';

export default [prompts, selectDialog, selectSkillDialog, lg, lu, expressions];
const mergeArrays: MergeWithCustomizer = (objValue, srcValue, key) => {
if (isArray(objValue)) {
// merge recognizers into defaults
if (key === 'recognizers') {
return objValue.concat(srcValue);
}

// otherwise override other arrays
return srcValue;
}
};

const defaultPlugin: Required<PluginConfig> = {
uiSchema: {},
recognizers: [],
flowWidgets: {},
};

export function mergePluginConfigs(...plugins: PluginConfig[]): Required<PluginConfig> {
return mergeWith({}, defaultPlugin, ...plugins, mergeArrays);
}

export default mergePluginConfigs(composer, prompts, selectDialog, selectSkillDialog, lg, lu);

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { AdaptiveDialog } from '../adaptive-flow-renderer/adaptive/AdaptiveDialo

import { NodeRendererContext, NodeRendererContextValue } from './contexts/NodeRendererContext';
import { SelfHostContext } from './contexts/SelfHostContext';
import { mergePluginConfig } from './utils/mergePluginConfig';
import { getCustomSchema } from './utils/getCustomSchema';
import { SelectionContext } from './contexts/SelectionContext';
import { enableKeyboardCommandAttributes, KeyboardCommandHandler } from './components/KeyboardZone';
Expand All @@ -30,6 +29,7 @@ import {
VisualEditorNodeWrapper,
VisualEditorElementWrapper,
} from './renderers';
import { useFlowUIOptions } from './hooks/useFlowUIOptions';

formatMessage.setup({
missingTranslation: 'ignore',
Expand Down Expand Up @@ -61,7 +61,8 @@ export interface VisualDesignerProps {
schema?: JSONSchema7;
}
const VisualDesigner: React.FC<VisualDesignerProps> = ({ schema }): JSX.Element => {
const { shellApi, plugins, ...shellData } = useShellApi();
const { shellApi, ...shellData } = useShellApi();
const { schema: schemaFromPlugins, widgets: widgetsFromPlugins } = useFlowUIOptions();
const {
dialogId,
focusedEvent,
Expand Down Expand Up @@ -102,7 +103,6 @@ const VisualDesigner: React.FC<VisualDesignerProps> = ({ schema }): JSX.Element
customSchemas: customSchema ? [customSchema] : [],
};

const { schema: schemaFromPlugins, widgets: widgetsFromPlugins } = mergePluginConfig(...plugins);
const customFlowSchema: FlowSchema = nodeContext.customSchemas.reduce((result, s) => {
const definitionKeys: string[] = Object.keys(s.definitions);
definitionKeys.forEach(($kind) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { useShellApi, useFlowConfig } from '@bfc/extension';

export function useFlowUIOptions() {
const { plugins } = useShellApi();
const schema = useFlowConfig();

return { widgets: plugins.flowWidgets ?? {}, schema };
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

import get from 'lodash/get';
import merge from 'lodash/merge';

import { FlowWidget, FlowSchema } from '../../types/flowRenderer.types';

Expand All @@ -17,7 +18,7 @@ export class WidgetSchemaProvider {

private mergeSchemas(orderedSchemas: FlowSchema[]): FlowSchema {
if (!Array.isArray(orderedSchemas) || !orderedSchemas.length) return {};
return Object.assign({}, ...orderedSchemas);
return merge({}, ...orderedSchemas);
}

get = ($kind: string): FlowWidget => {
Expand Down
15 changes: 0 additions & 15 deletions Composer/packages/extensions/adaptive-form/src/PluginContext.ts

This file was deleted.

Loading