Skip to content

Commit

Permalink
Merge branch 'master' into luError
Browse files Browse the repository at this point in the history
  • Loading branch information
cwhitten authored May 8, 2020
2 parents da85418 + cc66deb commit 53ef0f0
Show file tree
Hide file tree
Showing 93 changed files with 18,416 additions and 32,893 deletions.
5 changes: 2 additions & 3 deletions Composer/cypress/integration/NotificationPage.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ context('Notification Page', () => {
cy.findAllByText('__TestToDoBotWithLuisSample').should('exist');
});

it('can show dialog expression error ', () => {
it.skip('can show dialog expression error ', () => {
cy.visitPage('Design Flow');

cy.findByTestId('ProjectTree').within(() => {
Expand All @@ -67,8 +67,7 @@ context('Notification Page', () => {
.should('contain.text', 'expression');
cy.get('#root\\.condition')
.click()
.type('()')
.wait(1000);
.type('()');
});

cy.findByTestId('LeftNav-CommandBarButtonNotifications').click();
Expand Down
6 changes: 6 additions & 0 deletions Composer/packages/client/__tests__/mocks/worker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

export default class Worker {
static default = () => {};
}
4 changes: 4 additions & 0 deletions Composer/packages/client/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ module.exports = function(webpackEnv) {
],
include: paths.appSrc,
},
{
test: /\.worker\.ts$/,
use: { loader: 'worker-loader' },
},
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
Expand Down
1 change: 1 addition & 0 deletions Composer/packages/client/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = createConfig(
'react',
{
setupFilesAfterEnv: [path.resolve(__dirname, 'setupTests.ts')],
moduleNameMapper: { '\\.worker.ts': '<rootDir>/__tests__/mocks/worker.ts' },
},
{
presets: ['react-app', '@emotion/babel-preset-css-prop'],
Expand Down
3 changes: 2 additions & 1 deletion Composer/packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"webpack": "4.41.2",
"webpack-dev-server": "3.9.0",
"webpack-manifest-plugin": "2.1.0",
"workbox-webpack-plugin": "4.3.1"
"workbox-webpack-plugin": "4.3.1",
"worker-loader": "^2.0.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { PlaceHolderSectionName } from '@bfc/indexers/lib/utils/luUtil';
import get from 'lodash/get';
import { DialogInfo } from '@bfc/shared';
import { LuEditor, inlineModePlaceholder } from '@bfc/code-editor';
import { ComboBox, IComboBoxOption, IComboBox } from 'office-ui-fabric-react/lib/ComboBox';

import {
generateNewDialog,
Expand All @@ -26,10 +27,8 @@ import {
eventTypeKey,
intentTypeKey,
activityTypeKey,
messageTypeKey,
getEventTypes,
getActivityTypes,
getMessageTypes,
regexRecognizerKey,
} from '../../utils/dialogUtil';
import { addIntent } from '../../utils/luUtil';
Expand All @@ -44,18 +43,14 @@ const validateForm = (
regExIntents: [{ intent: string; pattern: string }]
): TriggerFormDataErrors => {
const errors: TriggerFormDataErrors = {};
const { $kind, specifiedType, intent, triggerPhrases, regexEx } = data;
const { $kind, event: eventName, intent, triggerPhrases, regexEx } = data;

if ($kind === eventTypeKey && !specifiedType) {
errors.specifiedType = formatMessage('Please select a event type');
if ($kind === eventTypeKey && !eventName) {
errors.event = formatMessage('Please select a event type');
}

if ($kind === activityTypeKey && !specifiedType) {
errors.specifiedType = formatMessage('Please select an activity type');
}

if ($kind === messageTypeKey && !specifiedType) {
errors.specifiedType = formatMessage('Please select a message type');
if ($kind === activityTypeKey && !eventName) {
errors.event = formatMessage('Please select an activity type');
}

if (!$kind) {
Expand Down Expand Up @@ -108,13 +103,14 @@ export const TriggerCreationModal: React.FC<TriggerCreationModalProps> = props =
const isNone = !get(dialogFile, 'content.recognizer');
const initialFormData: TriggerFormData = {
errors: {},
$kind: isNone ? '' : intentTypeKey,
specifiedType: '',
$kind: '',
event: '',
intent: '',
triggerPhrases: '',
regexEx: '',
};
const [formData, setFormData] = useState(initialFormData);
const [selectedType, setSelectedType] = useState(isNone ? '' : intentTypeKey);

const onClickSubmitButton = e => {
e.preventDefault();
Expand Down Expand Up @@ -144,12 +140,37 @@ export const TriggerCreationModal: React.FC<TriggerCreationModalProps> = props =
onDismiss();
};

const eventTypes: IComboBoxOption[] = getEventTypes();
const activityTypes: IDropdownOption[] = getActivityTypes();
let triggerTypeOptions: IDropdownOption[] = getTriggerTypes();

const onSelectTriggerType = (e, option) => {
setSelectedType(option.key || '');
setFormData({ ...initialFormData, $kind: option.key });
};

const onSelectSpecifiedTypeType = (e, option) => {
setFormData({ ...formData, specifiedType: option.key });
const handleEventChange = (
event: React.FormEvent<IComboBox>,
option?: IComboBoxOption,
index?: number,
value?: string
) => {
if (value) {
// if the custom event is an actual type, use that instead
if (eventTypes.find(o => o.key === value)) {
setFormData({ ...formData, $kind: value, event: '' });
} else {
setFormData({ ...formData, $kind: eventTypeKey, event: value });
}
} else if (option) {
setFormData({ ...formData, $kind: option.key as string, event: '' });
}
};

const onSelectSpecifiedType = (_e: any, option?: IDropdownOption) => {
if (option) {
setFormData({ ...formData, $kind: option.key as string });
}
};

const getLuDiagnostics = (intent: string, triggerPhrases: string) => {
Expand All @@ -174,19 +195,14 @@ export const TriggerCreationModal: React.FC<TriggerCreationModalProps> = props =
setFormData({ ...formData, triggerPhrases: body, errors });
};

const eventTypes: IDropdownOption[] = getEventTypes();
const activityTypes: IDropdownOption[] = getActivityTypes();
const messageTypes: IDropdownOption[] = getMessageTypes();
let triggerTypeOptions: IDropdownOption[] = getTriggerTypes();
if (isNone) {
triggerTypeOptions = triggerTypeOptions.filter(t => t.key !== intentTypeKey);
}
const showIntentName = formData.$kind === intentTypeKey;
const showRegExDropDown = formData.$kind === intentTypeKey && isRegEx;
const showTriggerPhrase = formData.$kind === intentTypeKey && !isRegEx;
const showEventDropDown = formData.$kind === eventTypeKey;
const showActivityDropDown = formData.$kind === activityTypeKey;
const showMessageDropDown = formData.$kind === messageTypeKey;
const showIntentName = selectedType === intentTypeKey;
const showRegExDropDown = selectedType === intentTypeKey && isRegEx;
const showTriggerPhrase = selectedType === intentTypeKey && !isRegEx;
const showEventDropDown = selectedType === eventTypeKey;
const showActivityDropDown = selectedType === activityTypeKey;

return (
<Dialog
Expand All @@ -211,17 +227,21 @@ export const TriggerCreationModal: React.FC<TriggerCreationModalProps> = props =
onChange={onSelectTriggerType}
errorMessage={formData.errors.$kind}
data-testid={'triggerTypeDropDown'}
defaultSelectedKey={formData.$kind}
defaultSelectedKey={selectedType}
/>
{showEventDropDown && (
<Dropdown
placeholder={formatMessage('Select a event type')}
<ComboBox
placeholder={formatMessage('Select an event type or enter a custom event name')}
label={formatMessage('Which event?')}
options={eventTypes}
styles={dropdownStyles}
onChange={onSelectSpecifiedTypeType}
errorMessage={formData.errors.specifiedType}
onChange={handleEventChange}
errorMessage={formData.errors.event}
data-testid={'eventTypeDropDown'}
allowFreeform
useComboBoxAsMenuWidth
autoComplete="off"
text={formData.event || eventTypes.find(e => e.key === formData.$kind)?.text}
/>
)}
{showActivityDropDown && (
Expand All @@ -230,22 +250,11 @@ export const TriggerCreationModal: React.FC<TriggerCreationModalProps> = props =
label={formatMessage('Which activity type')}
options={activityTypes}
styles={dropdownStyles}
onChange={onSelectSpecifiedTypeType}
errorMessage={formData.errors.specifiedType}
onChange={onSelectSpecifiedType}
errorMessage={formData.errors.event}
data-testid={'activityTypeDropDown'}
/>
)}
{showMessageDropDown && (
<Dropdown
placeholder={formatMessage('Select a message type')}
label={formatMessage('Which message type?')}
options={messageTypes}
styles={dropdownStyles}
onChange={onSelectSpecifiedTypeType}
errorMessage={formData.errors.specifiedType}
data-testid={'messageTypeDropDown'}
/>
)}
{showIntentName && (
<TextField
label={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ export const dropdownStyles = {
width: '400px',
},
root: {
paddingBottom: '20px',
marginBottom: '20px',
},
};

Expand Down
16 changes: 13 additions & 3 deletions Composer/packages/client/src/pages/design/PropertyEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
/** @jsx jsx */
import { jsx } from '@emotion/core';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import AdaptiveForm, { resolveBaseSchema, getUIOptions, mergePluginConfigs } from '@bfc/adaptive-form';
import Extension, { FormErrors } from '@bfc/extension';
import AdaptiveForm, { resolveRef, getUIOptions, mergePluginConfigs } from '@bfc/adaptive-form';
import Extension, { FormErrors, JSONSchema7 } from '@bfc/extension';
import formatMessage from 'format-message';
import isEqual from 'lodash/isEqual';
import debounce from 'lodash/debounce';
Expand All @@ -17,6 +17,16 @@ import plugins from '../../plugins';

import { formEditor } from './styles';

function resolveBaseSchema(schema: JSONSchema7, $kind: string): JSONSchema7 | undefined {
const defSchema = schema.definitions?.[$kind];
if (defSchema && typeof defSchema === 'object') {
return {
...resolveRef(defSchema, schema.definitions),
definitions: schema.definitions,
};
}
}

const PropertyEditor: React.FC = () => {
const { api: shellApi, data: shellData } = useShell('PropertyEditor');
const { currentDialog, data: formData = {}, focusPath, focusedSteps, schemas } = shellData;
Expand Down Expand Up @@ -48,7 +58,7 @@ const PropertyEditor: React.FC = () => {

const $schema = useMemo(() => {
if (schemas?.sdk?.content && localData) {
return resolveBaseSchema(schemas.sdk.content, localData);
return resolveBaseSchema(schemas.sdk.content, localData.$kind);
}
}, [schemas?.sdk?.content, localData.$kind]);

Expand Down
58 changes: 37 additions & 21 deletions Composer/packages/client/src/pages/design/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,11 @@ const DesignPage: React.FC<RouteComponentProps<{ dialogId: string; projectId: st
}, [] as IBreadcrumbItem[])
: [];
return (
<div style={{ display: 'flex', justifyContent: 'space-between', height: '65px' }}>
<div
role="region"
aria-label={formatMessage('Breadcrumb')}
style={{ display: 'flex', justifyContent: 'space-between', height: '65px' }}
>
<Breadcrumb
items={items}
ariaLabel={formatMessage('Navigation Path')}
Expand Down Expand Up @@ -395,28 +399,38 @@ const DesignPage: React.FC<RouteComponentProps<{ dialogId: string; projectId: st
return (
<React.Fragment>
<div css={pageRoot}>
<ProjectTree
dialogs={dialogs}
dialogId={dialogId}
selected={selected}
onSelect={handleSelect}
onDeleteDialog={handleDeleteDialog}
onDeleteTrigger={handleDeleteTrigger}
/>
<div role="main" css={contentWrapper}>
<ToolBar
toolbarItems={toolbarItems}
actions={actions}
projectId={projectId}
currentDialog={currentDialog}
openNewTriggerModal={openNewTriggerModal}
onCreateDialogComplete={onCreateDialogComplete}
onboardingAddCoachMarkRef={onboardingAddCoachMarkRef}
showSkillManifestModal={() => setExportSkillModalVisible(true)}
<div role="region" aria-label={formatMessage('Navigation pane')}>
<ProjectTree
dialogs={dialogs}
dialogId={dialogId}
selected={selected}
onSelect={handleSelect}
onDeleteDialog={handleDeleteDialog}
onDeleteTrigger={handleDeleteTrigger}
/>
</div>
<div role="main" css={contentWrapper}>
<div role="region" aria-label={formatMessage('toolbar')}>
<ToolBar
toolbarItems={toolbarItems}
actions={actions}
projectId={projectId}
currentDialog={currentDialog}
openNewTriggerModal={openNewTriggerModal}
onCreateDialogComplete={onCreateDialogComplete}
onboardingAddCoachMarkRef={onboardingAddCoachMarkRef}
showSkillManifestModal={() => setExportSkillModalVisible(true)}
/>
</div>
<Conversation css={editorContainer}>
<div css={editorWrapper}>
<div css={visualPanel} ref={visualPanelRef} tabIndex={0}>
<div
css={visualPanel}
ref={visualPanelRef}
tabIndex={0}
role="region"
aria-label={formatMessage('Authoring canvas')}
>
{breadcrumbItems}
{dialogJsonVisible ? (
<JsonEditor
Expand All @@ -432,7 +446,9 @@ const DesignPage: React.FC<RouteComponentProps<{ dialogId: string; projectId: st
<VisualEditor openNewTriggerModal={openNewTriggerModal} />
)}
</div>
<PropertyEditor key={focusPath} />
<div role="region" aria-label={formatMessage('Properties panel')}>
<PropertyEditor key={focusPath} />
</div>
</div>
</Conversation>
</div>
Expand Down
Loading

0 comments on commit 53ef0f0

Please sign in to comment.