Skip to content

Commit

Permalink
fix: do not preset name when creating a dialog (#1805)
Browse files Browse the repository at this point in the history
* do not preset name when creating a dialog

* do not share define conversation form between creating a bot and creating a dialog

* remove comment

* handle comments

* fix unit test

* handle comments

Co-authored-by: Andy Brown <asbrown002@gmail.com>
  • Loading branch information
liweitian and a-b-r-o-w-n committed Jan 7, 2020
1 parent cfb4b77 commit 0f1eda4
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 68 deletions.
6 changes: 3 additions & 3 deletions Composer/packages/client/__tests__/components/design.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { dialogs } from '../constants.json';

import { TriggerCreationModal } from './../../src/components/ProjectTree/TriggerCreationModal';
import { ProjectTree } from './../../src/components/ProjectTree';
import NewDialogModal from './../../src/pages/design/new-dialog-modal';
import { CreateDialogModal } from './../../src/pages/design/createDialogModal';
describe('<ProjectTree/>', () => {
it('should render the ProjectTree', async () => {
const dialogId = 'Main';
Expand All @@ -36,14 +36,14 @@ describe('<ProjectTree/>', () => {
expect(handleSelect).toHaveBeenCalledTimes(1);
});

it('should open NewDialogModal, close after clicking cancel', async () => {
it('should open CreateDialog Modal, close after clicking cancel', async () => {
let isOpen = true;
const handleDismiss = jest.fn(() => {
isOpen = false;
});
const handleSubmit = jest.fn(() => {});
const { getByText } = render(
<NewDialogModal isOpen={isOpen} onDismiss={handleDismiss} onSubmit={handleSubmit} onGetErrorMessage={() => {}} />
<CreateDialogModal isOpen={isOpen} onDismiss={handleDismiss} onSubmit={handleSubmit} />
);
const cancelButton = getByText('Cancel');
fireEvent.click(cancelButton);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ interface DefineConversationProps {
onDismiss: () => void;
onCurrentPathUpdate?: (newPath?: string, storageId?: string) => void;
onGetErrorMessage?: (text: string) => void;
enableLocationBrowse: boolean;
focusedStorageFolder?: StorageFolder;
currentPath?: string;
bots?: Bots[];
Expand All @@ -47,15 +46,7 @@ interface DefineConversationProps {
const initialFormDataError: FormDataError = {};

export const DefineConversation: React.FC<DefineConversationProps> = props => {
const {
onSubmit,
onDismiss,
onCurrentPathUpdate,
enableLocationBrowse,
focusedStorageFolder,
currentPath,
bots,
} = props;
const { onSubmit, onDismiss, onCurrentPathUpdate, focusedStorageFolder, currentPath, bots } = props;
const { state } = useContext(StoreContext);
const { templateId } = state;

Expand Down Expand Up @@ -130,7 +121,6 @@ export const DefineConversation: React.FC<DefineConversationProps> = props => {
const handleSubmit = e => {
e.preventDefault();
const errors = validateForm(formData);

if (Object.keys(errors).length) {
setFormDataErrors(errors);
return;
Expand All @@ -145,7 +135,7 @@ export const DefineConversation: React.FC<DefineConversationProps> = props => {
<Fragment>
<form onSubmit={handleSubmit}>
<input type="submit" style={{ display: 'none' }} />
<Stack horizontal={enableLocationBrowse} tokens={{ childrenGap: '2rem' }} styles={wizardStyles.stackinput}>
<Stack horizontal={true} tokens={{ childrenGap: '2rem' }} styles={wizardStyles.stackinput}>
<StackItem grow={0} styles={wizardStyles.halfstack}>
<TextField
label={formatMessage('Name')}
Expand All @@ -167,7 +157,7 @@ export const DefineConversation: React.FC<DefineConversationProps> = props => {
/>
</StackItem>
</Stack>
{enableLocationBrowse && focusedStorageFolder && onCurrentPathUpdate && currentPath && (
{focusedStorageFolder && onCurrentPathUpdate && currentPath && (
<LocationSelectContent
onCurrentPathUpdate={onCurrentPathUpdate}
focusedStorageFolder={focusedStorageFolder}
Expand Down
1 change: 0 additions & 1 deletion Composer/packages/client/src/CreationFlow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ export function CreationFlow(props) {
<DefineConversation
onSubmit={handleSubmit}
onDismiss={handleDismiss}
enableLocationBrowse={true}
onCurrentPathUpdate={updateCurrentPath}
focusedStorageFolder={focusedStorageFolder}
currentPath={currentPath}
Expand Down
113 changes: 113 additions & 0 deletions Composer/packages/client/src/pages/design/createDialogModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import React, { useState, useContext } from 'react';
import formatMessage from 'format-message';
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
import { Stack, StackItem } from 'office-ui-fabric-react/lib/Stack';
import { TextField } from 'office-ui-fabric-react/lib/TextField';

import { DialogCreationCopy } from '../../constants';
import { DialogWrapper } from '../../components/DialogWrapper/index';
import { StorageFolder } from '../../store/types';
import { StoreContext } from '../../store';

import { name, description, styles as wizardStyles } from './styles';

interface DialogFormData {
name: string;
description: string;
}

interface CreateDialogModalProps {
onSubmit: (dialogFormData: DialogFormData) => void;
onDismiss: () => void;
onCurrentPathUpdate?: (newPath?: string, storageId?: string) => void;
focusedStorageFolder?: StorageFolder;
currentPath?: string;
isOpen: boolean;
}

export const CreateDialogModal: React.FC<CreateDialogModalProps> = props => {
const { state } = useContext(StoreContext);
const { dialogs } = state;
const { onSubmit, onDismiss, isOpen } = props;
const initialFormData: DialogFormData = { name: '', description: '' };
const [formData, setFormData] = useState(initialFormData);
const [formDataErrors, setFormDataErrors] = useState<{ name?: string }>({});

const updateForm = field => (e, newValue) => {
setFormData({
...formData,
[field]: newValue,
});
};

const nameRegex = /^[a-zA-Z0-9-_.]+$/;
const validateForm = (data: DialogFormData) => {
const errors: { name?: string } = {};
const { name } = data;

if (name) {
if (!nameRegex.test(name)) {
errors.name = formatMessage(
'Spaces and special characters are not allowed. Use letters, numbers, -, or _., numbers, -, and _'
);
}
if (dialogs.some(dialog => dialog.id === name)) {
errors.name = formatMessage('Duplicaton of dialog name');
}
} else {
errors.name = formatMessage('Please input a name');
}
return errors;
};

const handleSubmit = e => {
e.preventDefault();
const errors = validateForm(formData);
if (Object.keys(errors).length) {
setFormDataErrors(errors);
return;
}

onSubmit({
...formData,
});
};

return (
<DialogWrapper isOpen={isOpen} onDismiss={onDismiss} {...DialogCreationCopy.DEFINE_CONVERSATION_OBJECTIVE}>
<form onSubmit={handleSubmit}>
<input type="submit" style={{ display: 'none' }} />
<Stack tokens={{ childrenGap: '2rem' }} styles={wizardStyles.stackinput}>
<StackItem grow={0} styles={wizardStyles.halfstack}>
<TextField
label={formatMessage('Name')}
value={formData.name}
styles={name}
onChange={updateForm('name')}
errorMessage={formDataErrors.name}
data-testid="NewDialogName"
/>
</StackItem>
<StackItem grow={0} styles={wizardStyles.halfstack}>
<TextField
styles={description}
value={formData.description}
label={formatMessage('Description')}
multiline
resizable={false}
onChange={updateForm('description')}
/>
</StackItem>
</Stack>

<DialogFooter>
<DefaultButton onClick={onDismiss} text={formatMessage('Cancel')} />
<PrimaryButton onClick={handleSubmit} text={formatMessage('Next')} />
</DialogFooter>
</form>
</DialogWrapper>
);
};
27 changes: 8 additions & 19 deletions Composer/packages/client/src/pages/design/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { Breadcrumb, IBreadcrumbItem } from 'office-ui-fabric-react/lib/Breadcru
import { Icon } from 'office-ui-fabric-react/lib/Icon';
import formatMessage from 'format-message';
import { globalHistory } from '@reach/router';
import toLower from 'lodash/toLower';
import get from 'lodash/get';
import { PromptTab } from '@bfc/shared';
import { getNewDesigner, seedNewDialog } from '@bfc/shared';
Expand All @@ -29,7 +28,7 @@ import { clearBreadcrumb } from '../../utils/navigation';
import undoHistory from '../../store/middlewares/undo/history';
import grayComposerIcon from '../../images/grayComposerIcon.svg';

import NewDialogModal from './new-dialog-modal';
import { CreateDialogModal } from './createDialogModal';
import {
breadcrumbClass,
contentWrapper,
Expand Down Expand Up @@ -190,17 +189,6 @@ function DesignPage(props) {
}
}

const getErrorMessage = text => {
if (
dialogs.findIndex(dialog => {
return toLower(dialog.id) === toLower(text);
}) >= 0
) {
return `${text} has been used, please choose another name`;
}
return '';
};

const onCreateDialogComplete = newDialog => {
if (newDialog) {
navTo(newDialog);
Expand Down Expand Up @@ -410,12 +398,13 @@ function DesignPage(props) {
</Conversation>
</div>
</div>
<NewDialogModal
isOpen={state.showCreateDialogModal}
onDismiss={() => actions.createDialogCancel()}
onSubmit={onSubmit}
onGetErrorMessage={getErrorMessage}
/>
{state.showCreateDialogModal && (
<CreateDialogModal
isOpen={state.showCreateDialogModal}
onDismiss={() => actions.createDialogCancel()}
onSubmit={onSubmit}
/>
)}
{triggerModalVisible && (
<TriggerCreationModal
dialogId={dialogId}
Expand Down
32 changes: 0 additions & 32 deletions Composer/packages/client/src/pages/design/new-dialog-modal.tsx

This file was deleted.

52 changes: 52 additions & 0 deletions Composer/packages/client/src/pages/design/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,55 @@ export const triggerButton = css`
font-size: 12px;
color: #0078d4;
`;

export const styles = {
dialog: {
title: {
fontWeight: FontWeights.bold,
fontSize: FontSizes.size20,
paddingTop: '14px',
paddingBottom: '11px',
},
subText: {
fontSize: FontSizes.size14,
},
},
modal: {
main: {
maxWidth: '80% !important',
width: '960px !important',
},
},
halfstack: {
root: [
{
flexBasis: '50%',
},
],
},
stackinput: {
root: [
{
marginBottom: '1rem',
},
],
},
};

export const textFieldlabel = {
label: {
root: [
{
fontWeight: FontWeights.semibold,
},
],
},
};

export const name = {
subComponentStyles: textFieldlabel,
};

export const description = {
subComponentStyles: textFieldlabel,
};

0 comments on commit 0f1eda4

Please sign in to comment.