Skip to content

Commit

Permalink
fix: the luis settings sometimes are lost when publishing luis (#3635)
Browse files Browse the repository at this point in the history
* fix: the luis settings sometimes are lost when publishing luis

* fix lint

* fix test
  • Loading branch information
lei9444 authored Jul 15, 2020
1 parent a124273 commit 53178da
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 322 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import * as React from 'react';
import { fireEvent } from '@bfc/test-utils';

import { PublishLuis } from '../../../src/pages/language-understanding/publish-luis-modal';
import { PublishLuisDialog } from '../../../src/components/TestController/publishDialog';
import { renderWithStore } from '../../testUtils';

describe('<PublishLuis />', () => {
it('should render the <PublishLuis />', () => {
describe('<PublishLuisDialog />', () => {
it('should render the <PublishLuisDialog />', () => {
const onDismiss = jest.fn(() => {});
const onPublish = jest.fn(() => {});
const state = {
Expand All @@ -26,36 +26,30 @@ describe('<PublishLuis />', () => {
},
},
};
const actions = {
setSettings: jest.fn((projectId, settings) => {
state.settings = settings;
}),
};
const { getByText } = renderWithStore(
<PublishLuis workState={0} onDismiss={onDismiss} onPublish={onPublish} />,
state,
actions
<PublishLuisDialog
isOpen
botName={'sampleBot0'}
config={state.settings.luis}
onDismiss={onDismiss}
onPublish={onPublish}
/>,
state
);
expect(getByText('What is the name of your bot?')).not.toBeNull();
const publishButton = getByText('OK');
expect(publishButton).not.toBeNull();
fireEvent.click(publishButton);
expect(actions.setSettings).toBeCalled();
expect(state).toEqual({
projectId: '12345',
botName: 'sampleBot0',
settings: {
luis: {
name: 'sampleBot0',
authoringKey: '12345',
authoringEndpoint: 'testAuthoringEndpoint',
endpointKey: '12345',
endpoint: 'testEndpoint',
authoringRegion: 'westus',
defaultLanguage: 'en-us',
environment: 'composer',
},
},
expect(onPublish).toBeCalled();
expect(onPublish).toBeCalledWith({
name: 'sampleBot0',
authoringKey: '12345',
authoringEndpoint: 'testAuthoringEndpoint',
endpointKey: '12345',
endpoint: 'testEndpoint',
authoringRegion: 'westus',
defaultLanguage: 'en-us',
environment: 'composer',
});
});
});
19 changes: 18 additions & 1 deletion Composer/packages/client/__tests__/components/skill.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,26 @@ const items: Skill[] = [
},
];

const state = {
projectId: '12345',
botName: 'sampleBot0',
settings: {
luis: {
name: '',
authoringKey: '12345',
authoringEndpoint: 'testAuthoringEndpoint',
endpointKey: '12345',
endpoint: 'testEndpoint',
authoringRegion: 'westus',
defaultLanguage: 'en-us',
environment: 'composer',
},
},
};

describe('Skill page', () => {
it('can add a new skill', () => {
const { getByText } = renderWithStore(<Skills />);
const { getByText } = renderWithStore(<Skills />, state);

const button = getByText('Connect to a new skill');
fireEvent.click(button);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,14 @@ export const TestController: React.FC = () => {
const botActionRef = useRef(null);
const notifications = useNotifications();
const { botEndpoints, botName, botStatus, dialogs, luFiles, settings, projectId, botLoadErrorMsg } = state;
const { publishToTarget, onboardingAddCoachMarkRef, publishLuis, getPublishStatus, setBotStatus } = actions;
const {
publishToTarget,
onboardingAddCoachMarkRef,
publishLuis,
getPublishStatus,
setBotStatus,
setSettings,
} = actions;
const connected = botStatus === BotStatus.connected;
const publishing = botStatus === BotStatus.publishing;
const reloading = botStatus === BotStatus.reloading;
Expand Down Expand Up @@ -86,11 +93,11 @@ export const TestController: React.FC = () => {
setCalloutVisible(true);
}

async function handlePublishLuis() {
async function handlePublishLuis(luisConfig) {
setBotStatus(BotStatus.publishing);
dismissDialog();
const luisConfig = settingsStorage.get(projectId) ? settingsStorage.get(projectId).luis : null;
await publishLuis(luisConfig.authoringKey, state.projectId);
await setSettings(projectId, { ...settings, luis: luisConfig });
await publishLuis(luisConfig, projectId);
}

async function handleLoadBot() {
Expand Down Expand Up @@ -118,7 +125,7 @@ export const TestController: React.FC = () => {
if (botStatus === BotStatus.failed || botStatus === BotStatus.pending || !isLuisConfigComplete(config)) {
openDialog();
} else {
await handlePublishLuis();
await handlePublishLuis(config);
}
} else {
await handleLoadBot();
Expand Down Expand Up @@ -172,7 +179,13 @@ export const TestController: React.FC = () => {
onDismiss={dismissCallout}
onTry={handleStart}
/>
<PublishLuisDialog botName={botName} isOpen={modalOpen} onDismiss={dismissDialog} onPublish={handlePublishLuis} />
<PublishLuisDialog
botName={botName}
config={settings.luis}
isOpen={modalOpen}
onDismiss={dismissDialog}
onPublish={handlePublishLuis}
/>
</Fragment>
);
};
Original file line number Diff line number Diff line change
@@ -1,22 +1,140 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React from 'react';
/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import React, { useCallback } from 'react';
import { Dialog, DialogType } from 'office-ui-fabric-react/lib/Dialog';
import { FontWeights, FontSizes } from 'office-ui-fabric-react/lib/Styling';
import { DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { Link } from 'office-ui-fabric-react/lib/Link';
import { IconButton } from 'office-ui-fabric-react/lib/Button';
import { Stack } from 'office-ui-fabric-react/lib/Stack';
import { TooltipHost } from 'office-ui-fabric-react/lib/Tooltip';
import formatMessage from 'format-message';

import { dialog, dialogModal } from '../../pages/language-understanding/styles';
import { PublishLuis } from '../../pages/language-understanding/publish-luis-modal';
import { Text, Tips, Links, nameRegex } from '../../constants';
import { FieldConfig, useForm } from '../../hooks/useForm';
import { ILuisConfig } from '../../store/types';

// -------------------- Styles -------------------- //
const textFieldLabel = css`
font-weight: ${FontWeights.semibold};
`;

const dialogSubTitle = css`
font-size: ${FontSizes.medium};
font-weight: ${FontWeights.semibold};
`;

const dialogContent = css`
margin-top: 20px;
margin-bottom: 50px;
`;

const dialog = {
title: {
fontWeight: FontWeights.bold,
},
};

const dialogModal = {
main: {
maxWidth: '450px !important',
},
};

interface LuisFormData {
name: string;
authoringKey: string;
endpointKey: string;
authoringRegion: string;
defaultLanguage: string;
environment: string;
endpoint: string;
authoringEndpoint: string;
}

const validate = (value: string) => {
if (!nameRegex.test(value)) {
return formatMessage('Spaces and special characters are not allowed. Use letters, numbers, -, or _.');
}
};

// eslint-disable-next-line react/display-name
const onRenderLabel = (info) => (props) => (
<Stack horizontal verticalAlign="center">
<span css={textFieldLabel}>{props.label}</span>
<TooltipHost calloutProps={{ gapSpace: 0 }} content={info}>
<IconButton iconProps={{ iconName: 'Info' }} styles={{ root: { marginBottom: -3 } }} />
</TooltipHost>
</Stack>
);

interface IPublishLuisDialogProps {
botName: string;
isOpen: boolean;
config: ILuisConfig;
onDismiss: () => void;
onPublish: () => void;
onPublish: (data: LuisFormData) => void;
}

export const PublishLuisDialog: React.FC<IPublishLuisDialogProps> = (props) => {
const { isOpen, onDismiss, onPublish, botName } = props;
const { isOpen, onDismiss, onPublish, botName, config } = props;

const luisFormConfig: FieldConfig<LuisFormData> = {
name: {
required: true,
validate: validate,
defaultValue: config.name || botName,
},
authoringKey: {
required: true,
validate: validate,
defaultValue: config.authoringKey,
},
endpointKey: {
required: false,
defaultValue: config.endpointKey,
},
authoringRegion: {
required: true,
defaultValue: config.authoringRegion || 'westus',
},
defaultLanguage: {
required: true,
defaultValue: config.defaultLanguage || 'en-us',
},
environment: {
required: true,
validate: validate,
defaultValue: config.environment,
},
endpoint: {
required: false,
defaultValue: config.endpoint,
},
authoringEndpoint: {
required: false,
defaultValue: config.authoringEndpoint,
},
};

const { formData, formErrors, hasErrors, updateField } = useForm(luisFormConfig, { validateOnMount: true });

const handlePublish = useCallback(
(e) => {
e.preventDefault();
if (hasErrors) {
return;
}

onPublish(formData);
},
[hasErrors, formData]
);

return (
<Dialog
Expand All @@ -33,7 +151,58 @@ export const PublishLuisDialog: React.FC<IPublishLuisDialogProps> = (props) => {
}}
onDismiss={onDismiss}
>
<PublishLuis botName={botName} onDismiss={onDismiss} onPublish={onPublish} />
<div css={dialogSubTitle}>
{Text.LUISDEPLOY}{' '}
<Link href={Links.LUIS} target="_blank">
{formatMessage('Learn more.')}
</Link>
</div>
<form css={dialogContent} onSubmit={handlePublish}>
<Stack gap={20}>
<TextField
data-testid="ProjectNameInput"
errorMessage={formErrors.name}
label={formatMessage('What is the name of your bot?')}
value={formData.name}
onChange={(_e, val) => updateField('name', val)}
onRenderLabel={onRenderLabel(Tips.PROJECT_NAME)}
/>
<TextField
data-testid="EnvironmentInput"
errorMessage={formErrors.environment}
label={formatMessage('Environment')}
value={formData.environment}
onChange={(_e, val) => updateField('environment', val)}
onRenderLabel={onRenderLabel(Tips.ENVIRONMENT)}
/>
<TextField
data-testid="AuthoringKeyInput"
errorMessage={formErrors.authoringKey}
label={formatMessage('LUIS Authoring key:')}
value={formData.authoringKey}
onChange={(_e, val) => updateField('authoringKey', val)}
onRenderLabel={onRenderLabel(Tips.AUTHORING_KEY)}
/>
<TextField
disabled
errorMessage={formErrors.authoringRegion}
label={formatMessage('Authoring Region')}
value={formData.authoringRegion}
onRenderLabel={onRenderLabel(Tips.AUTHORING_REGION)}
/>
<TextField
disabled
errorMessage={formErrors.defaultLanguage}
label={formatMessage('Default Language')}
value={formData.defaultLanguage}
onRenderLabel={onRenderLabel(Tips.DEFAULT_LANGUAGE)}
/>
</Stack>
</form>
<DialogFooter>
<PrimaryButton disabled={hasErrors} text={formatMessage('OK')} onClick={handlePublish} />
<DefaultButton data-testid={'publish-LUIS-models-cancel'} text={formatMessage('Cancel')} onClick={onDismiss} />
</DialogFooter>
</Dialog>
);
};
Loading

0 comments on commit 53178da

Please sign in to comment.