cy.createCollection(adminUser.token, {
name: `Test collection ${Math.floor(Math.random() * 999999)}`,
owner_uuid: activeUser.user.uuid,
- manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
+ manifest_text: "./subdir 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo\n. 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
}).as('testCollection1');
});
cy.get('[data-cy=upload-button]').click();
cy.get('[data-cy=collection-files-panel]')
.contains('5mb_a.bin').should('not.exist');
- cy.get('[data-cy=collection-file-count]').should('contain', '1');
+ cy.get('[data-cy=collection-file-count]').should('contain', '2');
cy.fixture('files/5mb.bin', 'base64').then(content => {
cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_a.bin');
cy.get('[data-cy=form-submit-btn]').click();
cy.get('[data-cy=form-submit-btn]').should('not.exist');
+ cy.get('[data-cy=collection-files-panel]')
+ .contains('5mb_a.bin').should('exist');
+ cy.get('[data-cy=collection-file-count]').should('contain', '3');
+
+ cy.get('[data-cy=collection-files-panel]').contains('subdir').click();
+ cy.get('[data-cy=upload-button]').click();
+ cy.fixture('files/5mb.bin', 'base64').then(content => {
+ cy.get('[data-cy=drag-and-drop]').upload(content, '5mb_b.bin');
+ cy.get('[data-cy=form-submit-btn]').click();
+ cy.get('[data-cy=form-submit-btn]').should('not.exist');
+ cy.get('[data-cy=collection-files-right-panel]')
+ .contains('5mb_b.bin').should('exist');
+
+ });
});
- // Confirm that the file browser has been updated.
- cy.get('[data-cy=collection-files-panel]')
- .contains('5mb_a.bin').should('exist');
- // Confirm that the collection panel has been updated.
- cy.get('[data-cy=collection-file-count]').should('contain', '2');
});
});
isWritable: boolean;
isLoading: boolean;
tooManyFiles: boolean;
- onUploadDataClick: () => void;
+ onUploadDataClick: (targetLocation?: string) => void;
onSearchChange: (searchValue: string) => void;
onItemMenuOpen: (event: React.MouseEvent<HTMLElement>, item: TreeItem<FileTreeData>, isWritable: boolean) => void;
onOptionsMenuOpen: (event: React.MouseEvent<HTMLElement>, isWritable: boolean) => void;
</Tooltip>
</div>
<div className={classes.wrapper}>
- <div className={classNames(classes.leftPanel, path.length > 1 ? classes.leftPanelVisible : classes.leftPanelHidden)}>
+ <div className={classNames(classes.leftPanel, path.length > 1 ? classes.leftPanelVisible : classes.leftPanelHidden)} data-cy="collection-files-left-panel">
<Tooltip title="Go back" className={path.length > 1 ? classes.backButton : classes.backButtonHidden}>
<IconButton onClick={() => setPath([...path.slice(0, path.length -1)])}>
<BackIcon />
</div>
</div>
- <div className={classes.rightPanel}>
+ <div className={classes.rightPanel} data-cy="collection-files-right-panel">
<div className={classes.searchWrapper}>
<SearchInput selfClearProp={rightKey} label="Search" value={rightSearch} onSearch={setRightSearch} />
</div>
className={classes.uploadButton}
data-cy='upload-button'
onClick={() => {
- onUploadDataClick();
+ onUploadDataClick(rightKey === leftKey ? undefined : rightKey);
}}
variant='contained'
color='primary'
axiosMock = new MockAdapter(serverApi);
webdavClient = {
delete: jest.fn(),
+ upload: jest.fn(),
} as any;
authService = {} as AuthService;
actions = {
});
});
+ describe('uploadFiles', () => {
+ it('should skip if no files to upload files', async () => {
+ // given
+ const files: File[] = [];
+ const collectionUUID = '';
+
+ // when
+ await collectionService.uploadFiles(collectionUUID, files);
+
+ // then
+ expect(webdavClient.upload).not.toHaveBeenCalled();
+ });
+
+ it('should upload files', async () => {
+ // given
+ const files: File[] = [{name: 'test-file1'} as File];
+ const collectionUUID = 'zzzzz-4zz18-0123456789abcde';
+
+ // when
+ await collectionService.uploadFiles(collectionUUID, files);
+
+ // then
+ expect(webdavClient.upload).toHaveBeenCalledTimes(1);
+ expect(webdavClient.upload.mock.calls[0][0]).toEqual("c=zzzzz-4zz18-0123456789abcde/test-file1");
+ });
+
+ it.only('should upload files with custom uplaod target', async () => {
+ // given
+ const files: File[] = [{name: 'test-file1'} as File];
+ const collectionUUID = 'zzzzz-4zz18-0123456789abcde';
+ const customTarget = 'zzzzz-4zz18-0123456789adddd/test-path/'
+
+ // when
+ await collectionService.uploadFiles(collectionUUID, files, undefined, customTarget);
+
+ // then
+ expect(webdavClient.upload).toHaveBeenCalledTimes(1);
+ expect(webdavClient.upload.mock.calls[0][0]).toEqual("c=zzzzz-4zz18-0123456789adddd/test-path/test-file1");
+ });
+ });
+
describe('deleteFiles', () => {
it('should remove no files', async () => {
// given
await this.update(collectionUuid, { preserveVersion: true });
}
- async uploadFiles(collectionUuid: string, files: File[], onProgress?: UploadProgress) {
+ async uploadFiles(collectionUuid: string, files: File[], onProgress?: UploadProgress, targetLocation: string = '') {
if (collectionUuid === "" || files.length === 0) { return; }
// files have to be uploaded sequentially
for (let idx = 0; idx < files.length; idx++) {
- await this.uploadFile(collectionUuid, files[idx], idx, onProgress);
+ await this.uploadFile(collectionUuid, files[idx], idx, onProgress, targetLocation);
}
await this.update(collectionUuid, { preserveVersion: true });
}
};
}
- private async uploadFile(collectionUuid: string, file: File, fileId: number, onProgress: UploadProgress = () => { return; }) {
- const fileURL = `c=${collectionUuid}/${file.name}`;
+ private async uploadFile(collectionUuid: string, file: File, fileId: number, onProgress: UploadProgress = () => { return; }, targetLocation: string = '') {
+ const fileURL = `c=${targetLocation !== '' ? targetLocation : collectionUuid}/${file.name}`.replace('//', '/');
const requestConfig = {
headers: {
'Content-Type': 'text/octet-stream'
import { loadCollectionPanel } from '../collection-panel/collection-panel-action';
import * as WorkbenchActions from 'store/workbench/workbench-actions';
-export const uploadCollectionFiles = (collectionUuid: string) =>
+export const uploadCollectionFiles = (collectionUuid: string, targetLocation?: string) =>
async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
dispatch(fileUploaderActions.START_UPLOAD());
const files = getState().fileUploader.map(file => file.file);
- await services.collectionService.uploadFiles(collectionUuid, files, handleUploadProgress(dispatch));
+ await services.collectionService.uploadFiles(collectionUuid, files, handleUploadProgress(dispatch), targetLocation);
dispatch(WorkbenchActions.loadCollection(collectionUuid));
dispatch(fileUploaderActions.CLEAR_UPLOAD());
};
export const COLLECTION_UPLOAD_FILES_DIALOG = 'uploadCollectionFilesDialog';
-export const openUploadCollectionFilesDialog = () => (dispatch: Dispatch) => {
+export const openUploadCollectionFilesDialog = (targetLocation?: string) => (dispatch: Dispatch) => {
dispatch(reset(COLLECTION_UPLOAD_FILES_DIALOG));
dispatch(fileUploaderActions.CLEAR_UPLOAD());
- dispatch<any>(dialogActions.OPEN_DIALOG({ id: COLLECTION_UPLOAD_FILES_DIALOG, data: {} }));
+ dispatch<any>(dialogActions.OPEN_DIALOG({ id: COLLECTION_UPLOAD_FILES_DIALOG, data: { targetLocation } }));
};
-export const submitCollectionFiles = () =>
+export const submitCollectionFiles = (targetLocation?: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
const currentCollection = getState().collectionPanel.item;
if (currentCollection) {
try {
dispatch(progressIndicatorActions.START_WORKING(COLLECTION_UPLOAD_FILES_DIALOG));
dispatch(startSubmit(COLLECTION_UPLOAD_FILES_DIALOG));
- await dispatch<any>(uploadCollectionFiles(currentCollection.uuid))
+ await dispatch<any>(uploadCollectionFiles(currentCollection.uuid, targetLocation))
.then(() => dispatch<any>(collectionPanelFilesAction.SET_COLLECTION_FILES({ files: createTree() })));
dispatch<any>(loadCollectionFiles(currentCollection.uuid));
dispatch<any>(loadCollectionPanel(currentCollection.uuid));
};
const mapDispatchToProps = (dispatch: Dispatch): Pick<CollectionPanelFilesProps, 'onSearchChange' | 'onFileClick' | 'onUploadDataClick' | 'onCollapseToggle' | 'onSelectionToggle' | 'onItemMenuOpen' | 'onOptionsMenuOpen'> => ({
- onUploadDataClick: () => {
- dispatch<any>(openUploadCollectionFilesDialog());
+ onUploadDataClick: (targetLocation?: string) => {
+ dispatch<any>(openUploadCollectionFilesDialog(targetLocation));
},
onCollapseToggle: (id) => {
dispatch(collectionPanelFilesAction.TOGGLE_COLLECTION_FILE_COLLAPSE({ id }));
withDialog(COLLECTION_UPLOAD_FILES_DIALOG),
reduxForm<CollectionCreateFormDialogData>({
form: COLLECTION_UPLOAD_FILES_DIALOG,
- onSubmit: (data, dispatch) => {
- dispatch(submitCollectionFiles());
+ onSubmit: (data, dispatch, dialog: any) => {
+ const targetLocation = (dialog.data || {}).targetLocation;
+ dispatch(submitCollectionFiles(targetLocation));
}
})
)(DialogCollectionFilesUpload);