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: show error message in form editor. #1737

Merged
merged 12 commits into from
Dec 10, 2019
1 change: 1 addition & 0 deletions Composer/packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@reach/router": "^1.2.1",
"axios": "^0.18.0",
"botbuilder-lg": "4.7.0-preview.93464",
"botframework-expressions": "4.7.0-preview.93464",
"format-message": "^6.2.3",
"immer": "^2.1.4",
"jwt-decode": "^2.2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const LGPage: React.FC<RouteComponentProps> = props => {

useEffect(() => {
// dialog lg templates is part of commong.lg. By restricting edit in root view, user would aware that the changes they made may affect other dialogs.
if (!isRoot) {
if (!isRoot && fileValid) {
setEditMode(false);
}

Expand Down
2 changes: 1 addition & 1 deletion Composer/packages/client/src/utils/dialogUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ConceptLabels, DialogGroup, SDKTypes, dialogGroups, seedNewDialog } fro
import get from 'lodash/get';
import set from 'lodash/set';
import cloneDeep from 'lodash/cloneDeep';
import { ExpressionEngine } from 'botbuilder-expression-parser';
import { ExpressionEngine } from 'botframework-expressions';
import { IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { DialogInfo } from '@bfc/indexers';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { PrimaryButton, DefaultButton, DirectionalHint } from 'office-ui-fabric-
import debounce from 'lodash/debounce';
import nanoid from 'nanoid';
import { initializeIcons } from '@uifabric/icons';
import { ExpressionEngine } from 'botbuilder-expression-parser';
import { ExpressionEngine } from 'botframework-expressions';
import { seedNewDialog, ShellApi } from '@bfc/shared';
import { LuFile, DialogInfo } from '@bfc/indexers';

Expand Down
5 changes: 2 additions & 3 deletions Composer/packages/extensions/obiformeditor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"name": "@bfc/obiformeditor",
"license": "MIT",
"version": "1.0.0",
"description": "obieditortest React component",
"engines": {
Expand Down Expand Up @@ -62,7 +61,7 @@
"@types/react": "16.9.0",
"@types/react-dom": "16.9.0",
"autoprefixer": "^9.5.1",
"botbuilder-expression-parser": "^4.5.11",
"botframework-expressions": "4.7.0-preview.93464",
"codemirror": "^5.44.0",
"copyfiles": "^2.1.0",
"css-loader": "^2.1.1",
Expand Down Expand Up @@ -92,4 +91,4 @@
"keywords": [
"react-component"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface FormContext
dialogOptions: { value: string; label: string }[];
dialogId?: string;
isRoot: boolean;
formErrors: any;
}

interface EnumOption {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { TextField, ITextFieldProps, ITextFieldStyles } from 'office-ui-fabric-r
import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
import { JSONSchema6 } from 'json-schema';
import formatMessage from 'format-message';
import get from 'lodash/get';

import { FormContext } from '../types';
import { EditableField } from '../fields/EditableField';
Expand All @@ -25,8 +26,9 @@ interface ExpresionWidgetProps extends ITextFieldProps {
options?: any;
}

const getDefaultErrorMessage = () => {
return formatMessage.rich('Invalid expression syntax. Refer to the syntax documentation<a>here</a>', {
const getDefaultErrorMessage = errMessage => {
return formatMessage.rich('{errMessage}. Refer to the syntax documentation<a>here</a>', {
errMessage,
a: ({ children }) => (
<a
key="a"
Expand All @@ -41,39 +43,13 @@ const getDefaultErrorMessage = () => {
};

export const ExpressionWidget: React.FC<ExpresionWidgetProps> = props => {
const {
rawErrors,
formContext,
schema,
id,
label,
editable,
hiddenErrMessage,
onValidate,
options = {},
...rest
} = props;
const { shellApi } = formContext;
const { formContext, schema, id, label, editable, hiddenErrMessage, onValidate, options = {}, ...rest } = props;
const { description } = schema;
const { hideLabel } = options;
const name = props.id?.split('_')[props.id?.split('_').length - 1];

const onGetErrorMessage = async (value: string): Promise<JSX.Element | string> => {
if (!value) {
if (hiddenErrMessage) {
onValidate && onValidate();
}
return '';
}

const isValid = await shellApi.validateExpression(value);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
let errMessage: string | any[] = '';
if (!isValid) {
errMessage = getDefaultErrorMessage();
} else if (rawErrors && rawErrors.length > 0) {
errMessage = rawErrors[0];
}
const onGetErrorMessage = (): JSX.Element | string => {
const errMessage = name && get(formContext, ['formErrors', name], '');

const messageBar = errMessage ? (
<MessageBar
Expand All @@ -83,7 +59,7 @@ export const ExpressionWidget: React.FC<ExpresionWidgetProps> = props => {
truncated
overflowButtonAriaLabel={formatMessage('See more')}
>
{errMessage}
{getDefaultErrorMessage(`${label} ${errMessage}`)}
</MessageBar>
) : (
''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,14 @@ interface LgEditorWidgetProps {

export const LgEditorWidget: React.FC<LgEditorWidgetProps> = props => {
const { formContext, name, value, height = 250 } = props;
const [errorMsg, setErrorMsg] = useState('');
const lgName = new LgMetaData(name, formContext.dialogId || '').toString();
const lgFileId = formContext.currentDialog.lgFile || 'common';
const lgFile = formContext.lgFiles && formContext.lgFiles.find(file => file.id === lgFileId);

const updateLgTemplate = useMemo(
() =>
debounce((body: string) => {
formContext.shellApi
.updateLgTemplate(lgFileId, lgName, body)
.then(() => setErrorMsg(''))
.catch(error => setErrorMsg(error));
formContext.shellApi.updateLgTemplate(lgFileId, lgName, body).catch(() => {});
}, 500),
[lgName, lgFileId]
);
Expand All @@ -70,6 +66,18 @@ export const LgEditorWidget: React.FC<LgEditorWidgetProps> = props => {
body: getInitialTemplate(name, value),
};

const lgStartLine = (lgFile && lgFile.content.split('\n').findIndex(item => item.trim() === `# ${lgName}()`)) || -1;
zhixzhan marked this conversation as resolved.
Show resolved Hide resolved
const templateBodyLines = template.body.split('\n').length;

const diagnostic =
lgFile &&
lgFile.diagnostics &&
lgFile.diagnostics.find(d => {
return d.range && lgStartLine + 1 < d.range.start.line && lgStartLine + 1 + templateBodyLines >= d.range.end.line;
});
const errorMsg = diagnostic
? diagnostic.message.split('error message: ')[diagnostic.message.split('error message: ').length - 1]
alanlong9278 marked this conversation as resolved.
Show resolved Hide resolved
: '';
const [localValue, setLocalValue] = useState(template.body);
const lgOption = {
inline: true,
Expand Down
23 changes: 22 additions & 1 deletion Composer/packages/extensions/obiformeditor/src/FormEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

/** @jsx jsx */
import { Global, jsx } from '@emotion/core';
import React, { useState } from 'react';
import React, { useState, useMemo } from 'react';
import { Dropdown } from 'office-ui-fabric-react/lib/Dropdown';
import { JSONSchema6Definition, JSONSchema6 } from 'json-schema';
import merge from 'lodash/merge';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import { appschema, ShellData, ShellApi } from '@bfc/shared';
import { Diagnostic } from '@bfc/indexers';

import Form from './Form';
import { uiSchema } from './schema/uischema';
Expand All @@ -33,6 +34,25 @@ export const FormEditor: React.FunctionComponent<FormEditorProps> = props => {
const [localData, setLocalData] = useState(data);
const type = getType(localData);

const formErrors = useMemo(() => {
if (props.currentDialog && props.currentDialog.diagnostics) {
const currentPath = props.focusPath.replace('#', '');
const diagnostics = get(props.currentDialog, 'diagnostics', [] as Diagnostic[]);

return diagnostics.reduce((errors, d) => {
const [dPath, dType, dProp] = d.path?.split('#') || [];

if (dPath === currentPath && dType === type && dProp) {
errors[dProp] = d.message;
}

return errors;
}, {});
}

return {};
}, [props.currentDialog]);

if (!type) {
return (
<div>
Expand Down Expand Up @@ -112,6 +132,7 @@ export const FormEditor: React.FunctionComponent<FormEditorProps> = props => {
focusedEvent: props.focusedEvent,
focusedSteps: props.focusedSteps,
focusedTab: props.focusedTab,
formErrors,
}}
idPrefix={props.focusPath}
>
Expand Down
18 changes: 8 additions & 10 deletions Composer/packages/lib/code-editor/src/RichEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,14 @@ export function RichEditor(props: RichEditorProps) {
}
}, [editor]);

const errorHelp = formatMessage.rich(
'This text has errors in the syntax. Refer to the syntax documentation<a>here</a>.',
{
a: ({ children }) => (
<a key="a" href={helpURL} target="_blank" rel="noopener noreferrer">
{children}
</a>
),
}
);
const errorHelp = formatMessage.rich('{errorMsg}. Refer to the syntax documentation<a>here</a>.', {
errorMsg,
a: ({ children }) => (
<a key="a" href={helpURL} target="_blank" rel="noopener noreferrer">
{children}
</a>
),
});

const getHeight = () => {
if (height === null || height === undefined) {
Expand Down
2 changes: 1 addition & 1 deletion Composer/packages/lib/indexers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
"ts-jest": "^24.1.0"
},
"dependencies": {
"botbuilder-expression-parser": "^4.5.11",
"botbuilder-lg": "4.7.0-preview.93464",
"botframework-expressions": "4.7.0-preview.93464",
"lodash": "^4.17.15",
"ludown": "^1.3.4"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.

import get from 'lodash/get';
import { ExpressionEngine } from 'botbuilder-expression-parser';
import { ExpressionEngine } from 'botframework-expressions';
import formatMessage from 'format-message';

import { Diagnostic } from '../diagnostic';
Expand All @@ -26,7 +26,7 @@ export const IsExpression: CheckerFunc = (
try {
ExpressionParser.parse(exp);
} catch (error) {
message = formatMessage(`must be an expression`);
message = `${formatMessage('must be an expression:')} ${error})`;
}
}
if (message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Licensed under the MIT License.
*/

import { ReturnType } from 'botbuilder-expression';
import { ReturnType } from 'botframework-expressions';
export class FunctionEntity {
public constructor(params: string[], returntype: ReturnType, introduction: string) {
this.Params = params;
Expand Down
32 changes: 0 additions & 32 deletions Composer/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4388,28 +4388,6 @@ botbuilder-core@4.7.0-preview.93464:
assert "^1.4.1"
botframework-schema "4.7.0-preview.93464"

botbuilder-expression-parser@^4.5.11:
version "4.5.11"
resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/botbuilder-expression-parser/-/botbuilder-expression-parser-4.5.11.tgz#fcce377a2b2c1a2c2345b2c77d9cf4289e171f9f"
integrity sha1-/M43eissGiwjRbLHfZz0KJ4XH58=
dependencies:
antlr4ts "0.5.0-alpha.1"
botbuilder-expression "https://botbuilder.myget.org/F/botbuilder-declarative/npm/botbuilder-expression/-/4.5.11.tgz"

"botbuilder-expression@https://botbuilder.myget.org/F/botbuilder-declarative/npm/botbuilder-expression/-/4.5.11.tgz":
version "4.5.11"
resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/botbuilder-expression/-/4.5.11.tgz#d15384417be9c0e17d46bf729fe707b81b66ef68"
dependencies:
"@microsoft/recognizers-text-data-types-timex-expression" "^1.1.4"
antlr4ts "0.5.0-alpha.1"
jspath "^0.4.0"
lru-cache "^5.1.1"
moment "2.24.0"
moment-timezone "^0.5.25"
xml2js "^0.4.19"
xmldom "^0.1.27"
xpath "0.0.27"

botbuilder-lg@4.7.0-preview.93464:
version "4.7.0-preview.93464"
resolved "https://botbuilder.myget.org/F/botbuilder-v4-js-daily/npm/botbuilder-lg/-/botbuilder-lg-4.7.0-preview.93464.tgz#504c647aca501998a0bcf89da33612c808334825"
Expand Down Expand Up @@ -17138,21 +17116,11 @@ xmlbuilder@^9.0.7, xmlbuilder@~9.0.1:
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=

xmldom@^0.1.27:
version "0.1.27"
resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk=

xmlhttprequest@1:
version "1.8.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=

xpath@0.0.27:
version "0.0.27"
resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92"
integrity sha1-3TQh+9zFZGrDLEhTG01+nQws+pI=

xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
Expand Down