export interface RenameFileDialogData {
name: string;
id: string;
+ path: string;
}
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;
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));
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;
};
? "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
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)];
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];
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('/') }));
}
},
{
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}
{`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." />
</>;