Skip to content

Commit

Permalink
Merge branch 'master' into open-project-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
cwhitten authored Apr 29, 2020
2 parents b5f54dd + fe192c6 commit 51d78a2
Show file tree
Hide file tree
Showing 22 changed files with 344 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,30 @@ import * as React from 'react';
import { render, fireEvent } from '@bfc/test-utils';

import { StoreContext } from '../../../../src/store';
import { StorageFolder } from '../../../../src/store/types';
import DefineConversation from '../../../../src/components/CreationFlow/DefineConversation';

describe('<DefineConversation/>', () => {
let onSubmitMock;
let onDismissMock;
const onCurrentPathUpdateMock = jest.fn();
let component, storeContext, saveTemplateMock, locationMock;

const focusedStorageFolder: StorageFolder = {
name: 'Desktop',
parent: '/test-folder',
writable: true,
type: 'folder',
path: '/test-folder/Desktop',
children: [
{
name: 'EchoBot-0',
type: 'bot',
path: 'Desktop/EchoBot-11299',
lastModified: 'Wed Apr 22 2020 17:51:07 GMT-0700 (Pacific Daylight Time)',
size: 1,
},
],
};
function renderComponent() {
return render(
<StoreContext.Provider value={storeContext}>
Expand All @@ -21,6 +37,7 @@ describe('<DefineConversation/>', () => {
onDismiss={onDismissMock}
onCurrentPathUpdate={onCurrentPathUpdateMock}
location={locationMock}
focusedStorageFolder={focusedStorageFolder}
/>
</StoreContext.Provider>
);
Expand Down Expand Up @@ -49,20 +66,6 @@ describe('<DefineConversation/>', () => {

it('should update formdata with data passed through location props', async () => {
storeContext.state.templateId = 'EchoBot';
storeContext.state.focusedStorageFolder = {
name: 'Desktop',
parent: '/test-folder',
writable: true,
children: [
{
name: 'EchoBot-0',
type: 'bot',
path: 'Desktop/EchoBot-11299',
lastModified: 'Wed Apr 22 2020 17:51:07 GMT-0700 (Pacific Daylight Time)',
size: '',
},
],
};
locationMock = {
search:
'schemaUrl%3Dhttps%3A%2F%2Fraw.luolix.top%2Fmicrosoft%2Fbotframework-sdk%2Fmaster%2Fschemas%2Fcomponent%2Fcomponent.schema%26name%3DEchoBot-11299%26description%3DTest%20Echo',
Expand All @@ -72,7 +75,6 @@ describe('<DefineConversation/>', () => {
fireEvent.click(node);
expect(onSubmitMock).toHaveBeenCalledWith({
description: 'Test Echo',
location: '',
name: 'EchoBot-11299',
schemaUrl:
'https://raw.githubusercontent.com/microsoft/botframework-sdk/master/schemas/component/component.schema',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ describe('<CreationFlow/>', () => {
it('should render the component', async () => {
const expectedTemplateId = 'EchoBot';
storeContext.state.templateId = 'EchoBot';
storeContext.actions.createProject = async templateId => {
storeContext.actions.createProject = async (templateId, name, description, location) => {
expect(templateId).toBe(expectedTemplateId);
expect(location === '\\test-folder\\Desktop' || location === '/test-folder/Desktop').toBeTruthy();
};
storeContext.state.focusedStorageFolder = {
name: 'Desktop',
Expand All @@ -77,7 +78,7 @@ describe('<CreationFlow/>', () => {
type: 'bot',
path: 'Desktop/EchoBot-11299',
lastModified: 'Wed Apr 22 2020 17:51:07 GMT-0700 (Pacific Daylight Time)',
size: '',
size: 1,
},
],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
import formatMessage from 'format-message';
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { Stack, StackItem } from 'office-ui-fabric-react/lib/Stack';
import React, { useState, Fragment, useEffect, useContext } from 'react';
import React, { useState, Fragment, useEffect } from 'react';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { RouteComponentProps } from '@reach/router';
import querystring from 'query-string';
Expand All @@ -18,21 +18,19 @@ import { DialogCreationCopy } from '../../../constants';
import { DialogWrapper } from '../../DialogWrapper';
import { DialogTypes } from '../../DialogWrapper/styles';
import { LocationSelectContent } from '../LocationBrowser/LocationSelectContent';
import { StoreContext } from '../../../store';
import { StorageFolder } from '../../../store/types';

import { name, description, halfstack, stackinput } from './styles';
const MAXTRYTIMES = 10000;

interface FormData {
name: string;
description: string;
location: string;
schemaUrl: string;
}

interface FormDataError {
name?: string;
location?: string;
}

interface DefineConversationProps
Expand All @@ -45,16 +43,14 @@ interface DefineConversationProps
onCurrentPathUpdate: (newPath?: string, storageId?: string) => void;
onGetErrorMessage?: (text: string) => void;
saveTemplateId?: (templateId: string) => void;
focusedStorageFolder: StorageFolder;
}

const initialFormDataError: FormDataError = {};

const DefineConversation: React.FC<DefineConversationProps> = props => {
const { onSubmit, onDismiss, onCurrentPathUpdate, saveTemplateId, templateId } = props;
const { state } = useContext(StoreContext);
const { focusedStorageFolder } = state;
const { onSubmit, onDismiss, onCurrentPathUpdate, saveTemplateId, templateId, focusedStorageFolder } = props;
const files = get(focusedStorageFolder, 'children', []);

const getDefaultName = () => {
let i = -1;
const bot = templateId;
Expand All @@ -72,7 +68,7 @@ const DefineConversation: React.FC<DefineConversationProps> = props => {
return defaultName;
};

const initalFormData: FormData = { name: '', description: '', location: '', schemaUrl: '' };
const initalFormData: FormData = { name: '', description: '', schemaUrl: '' };
const [formData, setFormData] = useState(initalFormData);
const [formDataErrors, setFormDataErrors] = useState(initialFormDataError);
const [disable, setDisable] = useState(false);
Expand Down Expand Up @@ -109,11 +105,6 @@ const DefineConversation: React.FC<DefineConversationProps> = props => {
return errors;
};

useEffect(() => {
const currentPath = Path.join(focusedStorageFolder.parent || '', focusedStorageFolder.name || '');
updateForm('location')(null, currentPath);
}, [focusedStorageFolder]);

useEffect(() => {
if (formData.name) {
const errors = validateForm(formData);
Expand All @@ -133,7 +124,7 @@ const DefineConversation: React.FC<DefineConversationProps> = props => {
});

useEffect(() => {
const formData: FormData = { name: getDefaultName(), description: '', location: '', schemaUrl: '' };
const formData: FormData = { name: getDefaultName(), description: '', schemaUrl: '' };
setFormData(formData);
if (props.location && props.location.search) {
const updatedFormData = {
Expand Down Expand Up @@ -171,7 +162,6 @@ const DefineConversation: React.FC<DefineConversationProps> = props => {
...formData,
});
};

return (
<Fragment>
<DialogWrapper
Expand Down Expand Up @@ -209,6 +199,7 @@ const DefineConversation: React.FC<DefineConversationProps> = props => {
<LocationSelectContent
operationMode={{ read: true, write: true }}
onCurrentPathUpdate={onCurrentPathUpdate}
focusedStorageFolder={focusedStorageFolder}
/>

<DialogFooter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CreationFlowStatus } from '../../../constants';
import { File } from '../../../store/types';
import { StoreContext } from '../../../store';
import { FileTypes } from '../../../constants';
import { StorageFolder } from '../../../store/types';

import { FileSelector } from './FileSelector';
import { loading, fileSelectorContainer } from './styles';
Expand All @@ -20,14 +21,15 @@ interface LocationSelectContentProps {
read: boolean;
write: boolean;
};
focusedStorageFolder: StorageFolder;
onOpen?: (path: string, storage: string) => void;
onCurrentPathUpdate: (newPath?: string, storageId?: string) => void;
}

export const LocationSelectContent: React.FC<LocationSelectContentProps> = props => {
const { onOpen, onCurrentPathUpdate, operationMode } = props;
const { onOpen, onCurrentPathUpdate, operationMode, focusedStorageFolder } = props;
const { state } = useContext(StoreContext);
const { storages, storageFileLoadingStatus, creationFlowStatus, focusedStorageFolder } = state;
const { storages, storageFileLoadingStatus, creationFlowStatus } = state;
const currentStorageIndex = useRef(0);
const onFileChosen = (item: File) => {
if (item) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ import { DialogCreationCopy } from '../../../constants';
import { DialogWrapper } from '../../DialogWrapper';
import { DialogTypes } from '../../DialogWrapper/styles';
import { LocationSelectContent } from '../LocationBrowser/LocationSelectContent';

import { StorageFolder } from '../../../store/types';
interface OpenProjectProps extends RouteComponentProps<{}> {
focusedStorageFolder: StorageFolder;
onOpen: (path: string, storage: string) => void;
onCurrentPathUpdate: (newPath?: string, storageId?: string) => void;
onDismiss: () => void;
}

export const OpenProject: React.FC<OpenProjectProps> = props => {
const { onOpen, onDismiss, onCurrentPathUpdate } = props;
const { onOpen, onDismiss, onCurrentPathUpdate, focusedStorageFolder } = props;

return (
<DialogWrapper
Expand All @@ -38,6 +39,7 @@ export const OpenProject: React.FC<OpenProjectProps> = props => {
}}
onOpen={onOpen}
onCurrentPathUpdate={onCurrentPathUpdate}
focusedStorageFolder={focusedStorageFolder}
/>
<DialogFooter>
<DefaultButton onClick={onDismiss} text={formatMessage('Cancel')} />
Expand Down
29 changes: 24 additions & 5 deletions Composer/packages/client/src/components/CreationFlow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const CreationFlow: React.FC<CreationFlowProps> = () => {
fetchFolderItemsByPath,
setCreationFlowStatus,
} = actions;
const { templateId, templateProjects, storages } = state;
const { templateId, templateProjects, storages, focusedStorageFolder } = state;
const currentStorageIndex = useRef(0);
const storage = storages[currentStorageIndex.current];
const currentStorageId = storage ? storage.id : 'default';
Expand Down Expand Up @@ -70,11 +70,22 @@ const CreationFlow: React.FC<CreationFlowProps> = () => {
};

const handleCreateNew = async formData => {
await createProject(templateId || '', formData.name, formData.description, formData.location, formData.schemaUrl);
await createProject(
templateId || '',
formData.name,
formData.description,
Path.join(focusedStorageFolder.parent || '', focusedStorageFolder.name || ''),
formData.schemaUrl
);
};

const handleSaveAs = async formData => {
await saveProjectAs(state.projectId, formData.name, formData.description, formData.location);
await saveProjectAs(
state.projectId,
formData.name,
formData.description,
Path.join(focusedStorageFolder.parent || '', focusedStorageFolder.name || '')
);
};

const handleSubmit = formData => {
Expand Down Expand Up @@ -106,6 +117,7 @@ const CreationFlow: React.FC<CreationFlowProps> = () => {
onSubmit={handleSubmit}
onDismiss={handleDismiss}
onCurrentPathUpdate={updateCurrentPath}
focusedStorageFolder={focusedStorageFolder}
path="create/:templateId"
saveTemplateId={saveTemplateId}
/>
Expand All @@ -114,9 +126,16 @@ const CreationFlow: React.FC<CreationFlowProps> = () => {
onSubmit={handleSubmit}
onDismiss={handleDismiss}
onCurrentPathUpdate={updateCurrentPath}
path=":projectId/save"
focusedStorageFolder={focusedStorageFolder}
path=":projectId/:templateId/save"
/>
<OpenProject
onOpen={openBot}
onDismiss={handleDismiss}
onCurrentPathUpdate={updateCurrentPath}
focusedStorageFolder={focusedStorageFolder}
path="open"
/>
<OpenProject onOpen={openBot} onDismiss={handleDismiss} onCurrentPathUpdate={updateCurrentPath} path="open" />
</Router>
</Fragment>
);
Expand Down
1 change: 0 additions & 1 deletion Composer/packages/client/src/components/NavItem/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export const link = (active: boolean, disabled: boolean) => css`
: `&:hover {
background-color: ${NeutralColors.gray50};
}
&:focus {
outline: none;
.ms-Fabric--isFocusVisible &::after {
Expand Down
26 changes: 23 additions & 3 deletions Composer/packages/client/src/components/ProjectTree/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import cloneDeep from 'lodash/cloneDeep';
import formatMessage from 'format-message';
import { DialogInfo, ITrigger } from '@bfc/shared';
import { Resizable, ResizeCallback } from 're-resizable';
import debounce from 'lodash/debounce';

import { StoreContext } from '../../store';
import { createSelectedPath, getFriendlyName } from '../../utils';
Expand Down Expand Up @@ -96,7 +97,7 @@ export const ProjectTree: React.FC<IProjectTreeProps> = props => {
const groupRef: React.RefObject<IGroupedList> = useRef(null);
const { dialogs, dialogId, selected, onSelect, onDeleteTrigger, onDeleteDialog } = props;
const [filter, setFilter] = useState('');

const delayedSetFilter = debounce(newValue => setFilter(newValue), 1000);
const addMainDialogRef = useCallback(mainDialog => onboardingAddCoachMarkRef({ mainDialog }), []);

const sortedDialogs = useMemo(() => {
Expand Down Expand Up @@ -141,14 +142,16 @@ export const ProjectTree: React.FC<IProjectTreeProps> = props => {

const onFilter = (_e?: any, newValue?: string): void => {
if (typeof newValue === 'string') {
setFilter(newValue);
delayedSetFilter(newValue);
}
};

const handleResize: ResizeCallback = (_e, _dir, _ref, d) => {
updateUserSettings({ dialogNavWidth: currentWidth + d.width });
};

const res: { items: any[]; groups: IGroup[] } = createGroup(sortedDialogs, dialogId, filter);

return (
<Resizable
size={{ width: currentWidth, height: 'auto' }}
Expand All @@ -167,8 +170,25 @@ export const ProjectTree: React.FC<IProjectTreeProps> = props => {
onChange={onFilter}
iconProps={{ iconName: 'Filter' }}
/>
<div
aria-live={'polite'}
aria-label={formatMessage(
`{
dialogNum, plural,
=0 {No dialogs}
=1 {One dialog}
other {# dialogs}
} have been found.
{
dialogNum, select,
0 {}
other {Press down arrow key to navigate the search results}
}`,
{ dialogNum: res.groups.length }
)}
/>
<GroupedList
{...createGroup(sortedDialogs, dialogId, filter)}
{...res}
onRenderCell={onRenderCell}
componentRef={groupRef}
groupProps={
Expand Down
Loading

0 comments on commit 51d78a2

Please sign in to comment.