[ARVADOS-WORKBENCH2] updated: 2.1.0-61-g142654bd
Git user
git at public.arvados.org
Thu Nov 12 00:13:31 UTC 2020
Summary of changes:
cypress/integration/collection-panel.spec.js | 77 +++++++++++++++++++++-
.../collection-panel-files.tsx | 3 +-
src/components/rename-dialog/rename-dialog.tsx | 44 -------------
src/components/tree/virtual-tree.tsx | 2 +-
.../collection-panel-files-actions.ts | 7 +-
src/validators/valid-name.tsx | 23 ++++++-
src/validators/validators.tsx | 3 +-
.../collection-files-item-action-set.ts | 5 +-
.../actions/copy-to-clipboard-action.test.tsx | 2 +-
.../actions/file-viewer-action.test.tsx | 2 +-
.../rename-file-dialog/rename-file-dialog.tsx | 10 +--
11 files changed, 115 insertions(+), 63 deletions(-)
delete mode 100644 src/components/rename-dialog/rename-dialog.tsx
via 142654bd7633e8d2e038d28a28a3954928766e68 (commit)
via d4a6611549777e48c6c92a002791bd4b0e42a6f4 (commit)
via d6af4135a2b881fbc746f6ba86a117a25221c6f0 (commit)
via b527533a2d7ffa52b3f999f0ed293b83311fe59f (commit)
via 27886bedb6f236f4aa7288473670d896b3a48ac7 (commit)
from 6528692d3b49adaa03934fd059b8fec52c0bd0b1 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 142654bd7633e8d2e038d28a28a3954928766e68
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date: Wed Nov 11 21:12:43 2020 -0300
15685: Adds integration tests, fixes rename dialog error reporting.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>
diff --git a/cypress/integration/collection-panel.spec.js b/cypress/integration/collection-panel.spec.js
index f0c53f3c..c3f729f9 100644
--- a/cypress/integration/collection-panel.spec.js
+++ b/cypress/integration/collection-panel.spec.js
@@ -165,6 +165,53 @@ describe('Collection panel tests', function() {
});
});
+ it('renames a file to a different directory', function() {
+ // Creates the collection using the admin token so we can set up
+ // a bogus manifest text without block signatures.
+ 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"})
+ .as('testCollection').then(function() {
+ cy.loginAs(activeUser);
+ cy.visit(`/collections/${this.testCollection.uuid}`);
+ // Rename 'bar' to 'subdir/foo'
+ cy.get('[data-cy=collection-files-panel]')
+ .contains('bar').rightclick();
+ cy.get('[data-cy=context-menu]')
+ .contains('Rename')
+ .click();
+ cy.get('[data-cy=form-dialog]')
+ .should('contain', 'Rename')
+ .within(() => {
+ cy.get('input').type(`{selectall}{backspace}subdir/foo`);
+ });
+ cy.get('[data-cy=form-submit-btn]').click();
+ cy.get('[data-cy=collection-files-panel]')
+ .should('not.contain', 'bar')
+ .and('contain', 'subdir');
+ // Look for the "arrow icon" and expand the "subdir" directory.
+ cy.get('[data-cy=virtual-file-tree] > div > i').click();
+ // Rename 'subdir/foo' to 'baz'
+ cy.get('[data-cy=collection-files-panel]')
+ .contains('foo').rightclick();
+ cy.get('[data-cy=context-menu]')
+ .contains('Rename')
+ .click();
+ cy.get('[data-cy=form-dialog]')
+ .should('contain', 'Rename')
+ .within(() => {
+ cy.get('input')
+ .should('have.value', 'subdir/foo')
+ .type(`{selectall}{backspace}baz`);
+ });
+ cy.get('[data-cy=form-submit-btn]').click();
+ cy.get('[data-cy=collection-files-panel]')
+ .should('contain', 'subdir') // empty dir kept
+ .and('contain', 'baz');
+ });
+ });
+
it('tries to rename a file with an illegal names', function() {
// Creates the collection using the admin token so we can set up
// a bogus manifest text without block signatures.
@@ -175,8 +222,8 @@ describe('Collection panel tests', function() {
.as('testCollection').then(function() {
cy.loginAs(activeUser);
cy.visit(`/collections/${this.testCollection.uuid}`);
- const illegalNames = ['', '.', '..'];
- illegalNames.forEach((name) => {
+ const illegalNamesFromBackend = ['.', '..'];
+ illegalNamesFromBackend.forEach((name) => {
cy.get('[data-cy=collection-files-panel]')
.contains('bar').rightclick();
cy.get('[data-cy=context-menu]')
@@ -194,6 +241,32 @@ describe('Collection panel tests', function() {
cy.contains('Could not rename');
});
cy.get('[data-cy=form-cancel-btn]').click();
+ });
+ const illegalNamesFromUI = [
+ ['', 'This field is required'],
+ [' ', 'Leading/trailing whitespaces not allowed'],
+ [' foo', 'Leading/trailing whitespaces not allowed'],
+ ['foo ', 'Leading/trailing whitespaces not allowed'],
+ ['//foo', 'Empty dir name not allowed']
+ ]
+ illegalNamesFromUI.forEach(([name, errMsg]) => {
+ cy.get('[data-cy=collection-files-panel]')
+ .contains('bar').rightclick();
+ cy.get('[data-cy=context-menu]')
+ .contains('Rename')
+ .click();
+ cy.get('[data-cy=form-dialog]')
+ .should('contain', 'Rename')
+ .within(() => {
+ cy.get('input').type(`{selectall}{backspace}${name}`);
+ });
+ cy.get('[data-cy=form-cancel-btn]').focus();
+ cy.get('[data-cy=form-dialog]')
+ .should('contain', 'Rename')
+ .within(() => {
+ cy.contains(`${errMsg}`);
+ });
+ cy.get('[data-cy=form-cancel-btn]').click();
})
});
});
diff --git a/src/components/tree/virtual-tree.tsx b/src/components/tree/virtual-tree.tsx
index 6db3d1e2..54938969 100644
--- a/src/components/tree/virtual-tree.tsx
+++ b/src/components/tree/virtual-tree.tsx
@@ -130,7 +130,7 @@ export const Row = <T, _>(itemList: VirtualTreeItem<T>[], render: any, treeProp
: undefined;
};
- return <div style={style}>
+ return <div data-cy='virtual-file-tree' style={style}>
<ListItem button className={listItem}
style={{
paddingLeft: (level + 1) * levelIndentation,
diff --git a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
index e77798f8..7b2b2557 100644
--- a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
+++ b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
@@ -147,7 +147,7 @@ export const renameFile = (newFullPath: string) =>
dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'File name changed.', hideDuration: 2000 }));
} catch (e) {
const errors: FormErrors<RenameFileDialogData, string> = {
- name: `Could not rename the file: ${e.responseText}`
+ path: `Could not rename the file: ${e.responseText}`
};
dispatch(stopSubmit(RENAME_FILE_DIALOG, errors));
}
commit d4a6611549777e48c6c92a002791bd4b0e42a6f4
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date: Wed Nov 11 18:46:47 2020 -0300
15685: Cleans up tests with example data.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>
diff --git a/src/views-components/context-menu/actions/copy-to-clipboard-action.test.tsx b/src/views-components/context-menu/actions/copy-to-clipboard-action.test.tsx
index 1ada703b..83cd0328 100644
--- a/src/views-components/context-menu/actions/copy-to-clipboard-action.test.tsx
+++ b/src/views-components/context-menu/actions/copy-to-clipboard-action.test.tsx
@@ -18,7 +18,7 @@ describe('CopyToClipboardAction', () => {
beforeEach(() => {
props = {
onClick: jest.fn(),
- href: 'https://collections.ardev.roche.com/c=ardev-4zz18-k0hamvtwyit6q56/t=1ha4ykd3w14ed19b2gh3uyjrjup38vsx27x1utwdne0bxcfg5d/LIMS/1.html',
+ href: 'https://collections.example.com/c=zzzzz-4zz18-k0hamvtwyit6q56/t=xxxxxxxx/LIMS/1.html',
};
});
diff --git a/src/views-components/context-menu/actions/file-viewer-action.test.tsx b/src/views-components/context-menu/actions/file-viewer-action.test.tsx
index fa455def..75f90d83 100644
--- a/src/views-components/context-menu/actions/file-viewer-action.test.tsx
+++ b/src/views-components/context-menu/actions/file-viewer-action.test.tsx
@@ -15,7 +15,7 @@ describe('FileViewerAction', () => {
beforeEach(() => {
props = {
onClick: jest.fn(),
- href: 'https://collections.ardev.roche.com/c=ardev-4zz18-k0hamvtwyit6q56/t=1ha4ykd3w14ed19b2gh3uyjrjup38vsx27x1utwdne0bxcfg5d/LIMS/1.html',
+ href: 'https://collections.example.com/c=zzzzz-4zz18-k0hamvtwyit6q56/t=xxxxxxx/LIMS/1.html',
};
});
commit d6af4135a2b881fbc746f6ba86a117a25221c6f0
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date: Wed Nov 11 18:25:45 2020 -0300
15685: Adds empty dir name validation to rename file dialog.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>
diff --git a/src/validators/valid-name.tsx b/src/validators/valid-name.tsx
index 000e27b0..c3650542 100644
--- a/src/validators/valid-name.tsx
+++ b/src/validators/valid-name.tsx
@@ -29,6 +29,9 @@ export const validFileName = (value: string) => {
};
export const validFilePath = (filePath: string) => {
- const errors = filePath.split('/').map(pathPart => validFileName(pathPart));
+ const errors = filePath.split('/').map(pathPart => {
+ if (pathPart === "") { return "Empty dir name not allowed"; }
+ return validFileName(pathPart);
+ });
return errors.filter(e => e !== undefined)[0];
};
\ No newline at end of file
commit b527533a2d7ffa52b3f999f0ed293b83311fe59f
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date: Wed Nov 11 18:10:28 2020 -0300
15685: Adds file path validation on rename file dialog.
Also, allows edition of the complete path instead of just the name, to mnatch
workbench1 behavior, enabling the user to move the file to a directory inside
the collection.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>
diff --git a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
index 19f5a7ee..e77798f8 100644
--- a/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
+++ b/src/store/collection-panel/collection-panel-files/collection-panel-files-actions.ts
@@ -121,6 +121,7 @@ export const RENAME_FILE_DIALOG = 'renameFileDialog';
export interface RenameFileDialogData {
name: string;
id: string;
+ path: string;
}
export const openRenameFileDialog = (data: RenameFileDialogData) =>
@@ -129,7 +130,7 @@ export const openRenameFileDialog = (data: RenameFileDialogData) =>
dispatch(dialogActions.OPEN_DIALOG({ id: RENAME_FILE_DIALOG, data }));
};
-export const renameFile = (newName: string) =>
+export const renameFile = (newFullPath: string) =>
async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
const dialog = getDialog<RenameFileDialogData>(getState().dialog, RENAME_FILE_DIALOG);
const currentCollection = getState().collectionPanel.item;
@@ -138,7 +139,7 @@ export const renameFile = (newName: string) =>
if (file) {
dispatch(startSubmit(RENAME_FILE_DIALOG));
const oldPath = getFileFullPath(file);
- const newPath = getFileFullPath({ ...file, name: newName });
+ const newPath = newFullPath;
try {
await services.collectionService.moveFile(currentCollection.uuid, oldPath, newPath);
dispatch<any>(loadCollectionFiles(currentCollection.uuid));
diff --git a/src/validators/valid-name.tsx b/src/validators/valid-name.tsx
index da967123..000e27b0 100644
--- a/src/validators/valid-name.tsx
+++ b/src/validators/valid-name.tsx
@@ -4,12 +4,12 @@
export const disallowDotName = /^\.{1,2}$/;
export const disallowSlash = /\//;
-
-const ERROR_MESSAGE = "Name cannot be '.' or '..' or contain '/' characters";
+export const disallowLeadingWhitespaces = /^\s+/;
+export const disallowTrailingWhitespaces = /\s+$/;
export const validName = (value: string) => {
return [disallowDotName, disallowSlash].find(aRule => value.match(aRule) !== null)
- ? ERROR_MESSAGE
+ ? "Name cannot be '.' or '..' or contain '/' characters"
: undefined;
};
@@ -18,3 +18,17 @@ export const validNameAllowSlash = (value: string) => {
? "Name cannot be '.' or '..'"
: undefined;
};
+
+export const validFileName = (value: string) => {
+ return [
+ disallowLeadingWhitespaces,
+ disallowTrailingWhitespaces
+ ].find(aRule => value.match(aRule) !== null)
+ ? `Leading/trailing whitespaces not allowed on '${value}'`
+ : undefined;
+};
+
+export const validFilePath = (filePath: string) => {
+ const errors = filePath.split('/').map(pathPart => validFileName(pathPart));
+ return errors.filter(e => e !== undefined)[0];
+};
\ No newline at end of file
diff --git a/src/validators/validators.tsx b/src/validators/validators.tsx
index d9eca97f..81fed2cc 100644
--- a/src/validators/validators.tsx
+++ b/src/validators/validators.tsx
@@ -6,7 +6,7 @@ import { require } from './require';
import { maxLength } from './max-length';
import { isRsaKey } from './is-rsa-key';
import { isRemoteHost } from "./is-remote-host";
-import { validName, validNameAllowSlash } from "./valid-name";
+import { validFilePath, validName, validNameAllowSlash } from "./valid-name";
export const TAG_KEY_VALIDATION = [require, maxLength(255)];
export const TAG_VALUE_VALIDATION = [require, maxLength(255)];
@@ -21,6 +21,7 @@ export const COLLECTION_PROJECT_VALIDATION = [require];
export const COPY_NAME_VALIDATION = [require, maxLength(255)];
export const COPY_FILE_VALIDATION = [require];
+export const RENAME_FILE_VALIDATION = [require, validFilePath];
export const MOVE_TO_VALIDATION = [require];
diff --git a/src/views-components/context-menu/action-sets/collection-files-item-action-set.ts b/src/views-components/context-menu/action-sets/collection-files-item-action-set.ts
index 6ce62ca9..bfbdec61 100644
--- a/src/views-components/context-menu/action-sets/collection-files-item-action-set.ts
+++ b/src/views-components/context-menu/action-sets/collection-files-item-action-set.ts
@@ -29,7 +29,10 @@ export const collectionFilesItemActionSet: ContextMenuActionSet = readOnlyCollec
name: "Rename",
icon: RenameIcon,
execute: (dispatch, resource) => {
- dispatch<any>(openRenameFileDialog({ name: resource.name, id: resource.uuid }));
+ dispatch<any>(openRenameFileDialog({
+ name: resource.name,
+ id: resource.uuid,
+ path: resource.uuid.split('/').slice(1).join('/') }));
}
},
{
diff --git a/src/views-components/rename-file-dialog/rename-file-dialog.tsx b/src/views-components/rename-file-dialog/rename-file-dialog.tsx
index d05c110b..9fbf6c9c 100644
--- a/src/views-components/rename-file-dialog/rename-file-dialog.tsx
+++ b/src/views-components/rename-file-dialog/rename-file-dialog.tsx
@@ -11,16 +11,17 @@ import { DialogContentText } from '@material-ui/core';
import { TextField } from '~/components/text-field/text-field';
import { RENAME_FILE_DIALOG, RenameFileDialogData, renameFile } from '~/store/collection-panel/collection-panel-files/collection-panel-files-actions';
import { WarningCollection } from '~/components/warning-collection/warning-collection';
+import { RENAME_FILE_VALIDATION } from '~/validators/validators';
export const RenameFileDialog = compose(
withDialog(RENAME_FILE_DIALOG),
reduxForm({
form: RENAME_FILE_DIALOG,
- onSubmit: (data: { name: string }, dispatch) => {
- dispatch<any>(renameFile(data.name));
+ onSubmit: (data: { path: string }, dispatch) => {
+ dispatch<any>(renameFile(data.path));
}
})
-)((props: WithDialogProps<RenameFileDialogData> & InjectedFormProps<{ name: string }>) =>
+)((props: WithDialogProps<RenameFileDialogData> & InjectedFormProps<{ name: string, path: string }>) =>
<FormDialog
dialogTitle='Rename'
formFields={RenameDialogFormFields}
@@ -33,9 +34,10 @@ const RenameDialogFormFields = (props: WithDialogProps<RenameFileDialogData>) =>
{`Please, enter a new name for ${props.data.name}`}
</DialogContentText>
<Field
- name='name'
+ name='path'
component={TextField}
autoFocus={true}
+ validate={RENAME_FILE_VALIDATION}
/>
<WarningCollection text="Renaming a file will change the collection's content address." />
</>;
commit 27886bedb6f236f4aa7288473670d896b3a48ac7
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date: Wed Nov 11 18:08:17 2020 -0300
15685: Removes unused code.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>
diff --git a/src/components/collection-panel-files/collection-panel-files.tsx b/src/components/collection-panel-files/collection-panel-files.tsx
index 29f20be2..a89c3a92 100644
--- a/src/components/collection-panel-files/collection-panel-files.tsx
+++ b/src/components/collection-panel-files/collection-panel-files.tsx
@@ -128,8 +128,7 @@ export const CollectionPanelFilesComponent = ({ onItemMenuOpen, onSearchChange,
: <div style={{ height: 'calc(100% - 60px)' }}>
<FileTree
onMenuOpen={(ev, item) => onItemMenuOpen(ev, item, isWritable)}
- {...treeProps}
- items={treeProps.items} /></div>}
+ {...treeProps} /></div>}
</>
}
</Card>);
diff --git a/src/components/rename-dialog/rename-dialog.tsx b/src/components/rename-dialog/rename-dialog.tsx
deleted file mode 100644
index 75c25b78..00000000
--- a/src/components/rename-dialog/rename-dialog.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) The Arvados Authors. All rights reserved.
-//
-// SPDX-License-Identifier: AGPL-3.0
-
-import * as React from "react";
-import { InjectedFormProps, Field } from "redux-form";
-import { Dialog, DialogTitle, DialogContent, DialogActions, Button, DialogContentText, CircularProgress } from "@material-ui/core";
-import { WithDialogProps } from "~/store/dialog/with-dialog";
-import { TextField } from "../text-field/text-field";
-
-export const RenameDialog = (props: WithDialogProps<string> & InjectedFormProps<{ name: string }>) =>
- <form>
- <Dialog open={props.open}>
- <DialogTitle>{`Rename`}</DialogTitle>
- <DialogContent>
- <DialogContentText>
- {`Please, enter a new name for ${props.data}`}
- </DialogContentText>
- <Field
- name='name'
- component={TextField}
- />
- </DialogContent>
- <DialogActions>
- <Button
- variant='text'
- color='primary'
- disabled={props.submitting}
- onClick={props.closeDialog}>
- Cancel
- </Button>
- <Button
- variant='contained'
- color='primary'
- type='submit'
- onClick={props.handleSubmit}
- disabled={props.pristine || props.invalid || props.submitting}>
- {props.submitting
- ? <CircularProgress size={20} />
- : 'Ok'}
- </Button>
- </DialogActions>
- </Dialog>
- </form>;
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list