Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import React, { useState, useContext, Fragment, useEffect } from 'react';
import React, { useState, Fragment } 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 get from 'lodash/get';

import { LocationSelectContent } from '../LocationBrowser/LocationSelectContent';
import { styles as wizardStyles } from '../StepWizard/styles';
import { FileTypes } from '../../constants';

import { StoreContext } from './../../store';
import { name, description } from './styles';

const nameRegex = /^[a-zA-Z0-9-_.]+$/;
Expand All @@ -22,7 +19,7 @@ const validateForm = data => {
const errors = {};
const { name } = data;

if (name && !nameRegex.test(name)) {
if (!name || !nameRegex.test(name)) {
errors.name = formatMessage(
'Spaces and special characters are not allowed. Use letters, numbers, -, or _., numbers, -, and _'
);
Expand All @@ -32,35 +29,11 @@ const validateForm = data => {
};

export function DefineConversation(props) {
const { state } = useContext(StoreContext);
const { onSubmit, onGetErrorMessage, onDismiss, enableLocationBrowse } = props;
const { templateId, focusedStorageFolder } = state;

const [formData, setFormData] = useState({ errors: {} });
const [location, setLocation] = useState('');
const [disable, setDisable] = useState(false);

useEffect(() => {
const allFilesInFolder = get(focusedStorageFolder, 'children', []);

const botsInCurrentFolder = allFilesInFolder.filter(file => {
if (file.type === FileTypes.BOT) {
return file;
}
});
let i = 0;
let defaultName = `${templateId}-${i}`;

while (
botsInCurrentFolder.findIndex(bot => {
return bot.name === defaultName;
}) > -1
) {
i = i + 1;
defaultName = `${templateId}-${i}`;
}
updateForm('defaultName')(null, defaultName);
}, [templateId, focusedStorageFolder]);

const updateForm = field => (e, newValue) => {
setFormData({
...formData,
Expand All @@ -81,12 +54,9 @@ export function DefineConversation(props) {
return;
}

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

//disable the next button if the text has errors.
Expand All @@ -107,6 +77,11 @@ export function DefineConversation(props) {
}
};

// // update the path in the form and toggle the location picker.
const updateLocation = path => {
updateForm('location')(null, path);
};

return (
<Fragment>
<form onSubmit={handleSubmit}>
Expand All @@ -115,7 +90,7 @@ export function DefineConversation(props) {
<StackItem grow={0} styles={wizardStyles.halfstack}>
<TextField
label={formatMessage('Name')}
value={formData.name || formData.defaultName}
value={formData.name}
styles={name}
onChange={updateForm('name')}
errorMessage={formData.errors.name}
Expand All @@ -134,7 +109,7 @@ export function DefineConversation(props) {
/>
</StackItem>
</Stack>
{enableLocationBrowse && <LocationSelectContent onChange={setLocation} allowOpeningBot={false} />}
{enableLocationBrowse && <LocationSelectContent onChange={updateLocation} allowOpeningBot={false} />}

<DialogFooter>
<DefaultButton onClick={onDismiss} text={formatMessage('Cancel')} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,22 @@ import path from 'path';
import { jsx } from '@emotion/core';
import { Fragment, useEffect, useState, useContext, useRef } from 'react';

import storage from '../../utils/storage';

import { FileSelector } from './FileSelector';
import { StoreContext } from './../../store';
import { FileTypes } from './../../constants';

const NEW_BOT_LOCATION_KEY = 'newBotLocation';

export function LocationSelectContent(props) {
const { state, actions } = useContext(StoreContext);
const { storages, focusedStorageFolder, storageFileLoadingStatus } = state;
const { onOpen, onChange, allowOpeningBot = true } = props;

const { fetchFolderItemsByPath } = actions;
const currentStorageIndex = useRef(0);
const [currentPath, setCurrentPath] = useState('');
const [currentPath, setCurrentPath] = useState(storage.get(NEW_BOT_LOCATION_KEY, ''));
const currentStorageId = storages[currentStorageIndex.current] ? storages[currentStorageIndex.current].id : 'default';

useEffect(() => {
Expand All @@ -35,7 +39,6 @@ export function LocationSelectContent(props) {
// const formatedPath = path.normalize(newPath.replace(/\\/g, '/'));
const formatedPath = path.normalize(newPath);
await fetchFolderItemsByPath(storageId, formatedPath);
await actions.updateCurrentPath(formatedPath);
setCurrentPath(formatedPath);
}
};
Expand All @@ -45,7 +48,7 @@ export function LocationSelectContent(props) {
let path = currentPath;
let id = '';
if (storages[index]) {
path = storages[index].path;
path = path || storages[index].path;
id = storages[index].id;
}
updateCurrentPath(path, id);
Expand All @@ -55,6 +58,7 @@ export function LocationSelectContent(props) {
if (onChange) {
onChange(currentPath);
}
storage.set(NEW_BOT_LOCATION_KEY, currentPath);
}, [currentPath]);

const onSelectionChanged = item => {
Expand Down
27 changes: 11 additions & 16 deletions Composer/packages/client/src/CreationFlow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@ export function CreationFlow(props) {
const { templateId, templateProjects, focusedStorageFolder } = state;

useEffect(() => {
const botsInCurrentFolder = getBotsInFocusedStorageFolder();
const allFilesInFolder = get(focusedStorageFolder, 'children', []);

const botsInCurrentFolder = allFilesInFolder.filter(file => {
if (file.type === FileTypes.BOT) {
return file;
}
});

setBots(botsInCurrentFolder);
}, [focusedStorageFolder]);
Expand Down Expand Up @@ -60,17 +66,6 @@ export function CreationFlow(props) {
}
};

const getBotsInFocusedStorageFolder = () => {
const allFilesInFolder = get(focusedStorageFolder, 'children', []);

const botsInCurrentFolder = allFilesInFolder.filter(file => {
if (file.type === FileTypes.BOT) {
return file;
}
});
return botsInCurrentFolder;
};

const openBot = async botFolder => {
await openBotProject(botFolder);
navigateTo('/dialogs/Main');
Expand All @@ -81,20 +76,20 @@ export function CreationFlow(props) {
setCreationFlowStatus(CreationFlowStatus.CLOSE);
};

const handleCreateNew = async (formData, location) => {
await createProject(templateId || '', formData.name || formData.defaultName, formData.description, location);
const handleCreateNew = async formData => {
await createProject(templateId || '', formData.name, formData.description, formData.location);
};

const handleSaveAs = async formData => {
await saveProjectAs(formData.name, formData.description);
};

const handleSubmit = (formData, location) => {
const handleSubmit = formData => {
switch (creationFlowStatus) {
case CreationFlowStatus.NEW_FROM_SCRATCH:
case CreationFlowStatus.NEW_FROM_TEMPLATE:
case CreationFlowStatus.NEW:
handleCreateNew(formData, location);
handleCreateNew(formData);
navigateTo('/dialogs/Main');
break;
case CreationFlowStatus.SAVEAS:
Expand Down
4 changes: 0 additions & 4 deletions Composer/packages/client/src/store/action/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,3 @@ export const fetchFolderItemsByPath: ActionCreator = async ({ dispatch }, id, pa
});
}
};

export const updateCurrentPath: ActionCreator = async ({ dispatch }, path) => {
await httpClient.put(`/storages/currentPath`, { path: path });
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ jest.mock('../../src/store/store', () => {
name: 'This PC',
type: 'LocalDisk',
path: '.',
defaultPath: '.',
},
],
recentBotProjects: [] as any[],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ jest.mock('../../src/store/store', () => {
name: 'This PC',
type: 'LocalDisk',
path: '.',
defaultPath: '.',
},
];
return {
Expand Down
6 changes: 0 additions & 6 deletions Composer/packages/server/src/controllers/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,6 @@ function createStorageConnection(req: Request, res: Response) {
res.status(200).json(StorageService.getStorageConnections());
}

function updateCurrentPath(req: Request, res: Response) {
StorageService.updateCurrentPath(req.body.path);
res.status(200).json('success');
}

async function getBlob(req: Request, res: Response) {
const storageId = req.params.storageId;
const reqpath = decodeURI(req.params.path);
Expand All @@ -39,5 +34,4 @@ export const StorageController = {
getStorageConnections,
createStorageConnection,
getBlob,
updateCurrentPath,
};
1 change: 0 additions & 1 deletion Composer/packages/server/src/router/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ router.post('/projects/opened/project/saveAs', ProjectController.saveProjectAs);
router.get('/projects/recent', ProjectController.getRecentProjects);

// storages
router.put('/storages/currentPath', StorageController.updateCurrentPath);
router.get('/storages', StorageController.getStorageConnections);
router.post('/storages', StorageController.createStorageConnection);
router.get('/storages/:storageId/blobs/:path(*)', StorageController.getBlob);
Expand Down
30 changes: 2 additions & 28 deletions Composer/packages/server/src/services/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class StorageService {

constructor() {
this.storageConnections = Store.get(this.STORE_KEY);
this.ensureDefaultBotFoldersExist();
}

public getStorageClient = (storageId: string): IFileStorage => {
Expand All @@ -40,18 +39,11 @@ class StorageService {
};

public getStorageConnections = (): StorageConnection[] => {
const connections = this.storageConnections.map(s => {
return this.storageConnections.map(s => {
const temp = Object.assign({}, s);
// if the last accessed path exist
if (fs.existsSync(s.path)) {
temp.path = Path.resolve(s.path); // resolve path if path is relative, and change it to unix pattern
} else {
temp.path = Path.resolve(s.defaultPath);
}
temp.path = Path.resolve(s.path); // resolve path if path is relative, and change it to unix pattern
return temp;
});
this.ensureDefaultBotFoldersExist();
return connections;
};

public checkBlob = async (storageId: string, filePath: string): Promise<boolean> => {
Expand Down Expand Up @@ -93,17 +85,6 @@ class StorageService {
}
};

public updateCurrentPath = (path: string) => {
this.storageConnections[0].path = path;
Store.set(this.STORE_KEY, this.storageConnections);
};

private ensureDefaultBotFoldersExist = () => {
this.storageConnections.forEach(s => {
this.createFolderRecurively(s.defaultPath);
});
};

private isBotFolder = (path: string) => {
// locate Main.dialog
const mainPath = Path.join(path, 'ComposerDialogs/Main', 'Main.dialog');
Expand Down Expand Up @@ -138,13 +119,6 @@ class StorageService {
const result = await Promise.all(children);
return result.filter(item => !!item);
};

private createFolderRecurively = (path: string) => {
if (!fs.existsSync(path)) {
this.createFolderRecurively(Path.dirname(path));
fs.mkdirSync(path);
}
};
}

const service = new StorageService();
Expand Down
4 changes: 1 addition & 3 deletions Composer/packages/server/src/store/data.template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
// Licensed under the MIT License.

import path from 'path';
import os from 'os';

export default {
storageConnections: [
{
id: 'default',
name: 'This PC',
type: 'LocalDisk',
path: '', // this is used as last accessed path, if it is invalid, use defaultPath
defaultPath: path.join(os.homedir(), 'Documents', 'Composer'),
path: path.resolve(__dirname, '../../../../../MyBots'),
},
],
recentBotProjects: [],
Expand Down
Loading