Merge pull request #698 from ONLYOFFICE/feature/create-from-modal
Feature/create from modal
This commit is contained in:
commit
477f386047
@ -29,6 +29,7 @@ import {
|
||||
ArticleMainButtonContent,
|
||||
} from "./components/Article";
|
||||
import FormGallery from "./pages/FormGallery";
|
||||
import GlobalEvents from "./components/GlobalEvents";
|
||||
|
||||
const { proxyURL } = AppServerConfig;
|
||||
const homepage = config.homepage;
|
||||
@ -169,6 +170,7 @@ class FilesContent extends React.Component {
|
||||
|
||||
return (
|
||||
<>
|
||||
<GlobalEvents />
|
||||
<Panels />
|
||||
<FilesArticle history={this.props.history} />
|
||||
<FilesSection />
|
||||
|
@ -21,384 +21,19 @@ export default function withContent(WrappedContent) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const {
|
||||
item,
|
||||
fileActionId,
|
||||
fileActionExt,
|
||||
fileActionTemplateId,
|
||||
fromTemplate,
|
||||
} = props;
|
||||
let titleWithoutExt = props.titleWithoutExt;
|
||||
if (
|
||||
fileActionId === -1 &&
|
||||
item.id === fileActionId &&
|
||||
fileActionTemplateId === null &&
|
||||
!fromTemplate
|
||||
) {
|
||||
titleWithoutExt = getDefaultFileName(fileActionExt);
|
||||
}
|
||||
|
||||
this.state = { itemTitle: titleWithoutExt };
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
fileActionId,
|
||||
fileActionExt,
|
||||
setIsUpdatingRowItem,
|
||||
isUpdatingRowItem,
|
||||
isEdit,
|
||||
titleWithoutExt,
|
||||
} = this.props;
|
||||
if (fileActionId === -1 && fileActionExt !== prevProps.fileActionExt) {
|
||||
const itemTitle = getDefaultFileName(fileActionExt);
|
||||
this.setState({ itemTitle });
|
||||
}
|
||||
if (fileActionId === null && prevProps.fileActionId !== fileActionId) {
|
||||
isUpdatingRowItem && setIsUpdatingRowItem(false);
|
||||
}
|
||||
const { titleWithoutExt } = this.props;
|
||||
|
||||
if (!isEdit && titleWithoutExt !== this.state.itemTitle) {
|
||||
if (titleWithoutExt !== this.state.itemTitle) {
|
||||
this.setState({ itemTitle: titleWithoutExt });
|
||||
}
|
||||
}
|
||||
|
||||
completeAction = (id) => {
|
||||
const { editCompleteAction, item } = this.props;
|
||||
|
||||
const isCancel =
|
||||
(id.currentTarget && id.currentTarget.dataset.action === "cancel") ||
|
||||
id.keyCode === 27;
|
||||
editCompleteAction(id, item, isCancel);
|
||||
};
|
||||
|
||||
updateItem = () => {
|
||||
const {
|
||||
t,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
item,
|
||||
setIsLoading,
|
||||
fileActionId,
|
||||
editCompleteAction,
|
||||
addActiveItems,
|
||||
clearActiveOperations,
|
||||
} = this.props;
|
||||
|
||||
const { itemTitle } = this.state;
|
||||
const originalTitle = getTitleWithoutExst(item);
|
||||
|
||||
setIsLoading(true);
|
||||
let timerId;
|
||||
|
||||
const isSameTitle =
|
||||
originalTitle.trim() === itemTitle.trim() || itemTitle.trim() === "";
|
||||
|
||||
const isFile = item.fileExst || item.contentLength;
|
||||
|
||||
if (isSameTitle) {
|
||||
this.setState({
|
||||
itemTitle: originalTitle,
|
||||
});
|
||||
return editCompleteAction(fileActionId, item, isSameTitle);
|
||||
} else {
|
||||
timerId = setTimeout(() => {
|
||||
isFile ? addActiveItems([item.id]) : addActiveItems(null, [item.id]);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
isFile
|
||||
? updateFile(fileActionId, itemTitle)
|
||||
.then(() => this.completeAction(fileActionId))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
t("FileRenamed", {
|
||||
oldTitle: item.title,
|
||||
newTitle: itemTitle + item.fileExst,
|
||||
})
|
||||
)
|
||||
)
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
this.completeAction(fileActionId);
|
||||
})
|
||||
.finally(() => {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
clearActiveOperations([item.id]);
|
||||
|
||||
setIsLoading(false);
|
||||
})
|
||||
: renameFolder(fileActionId, itemTitle)
|
||||
.then(() => this.completeAction(fileActionId))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
t("FolderRenamed", {
|
||||
folderTitle: item.title,
|
||||
newFoldedTitle: itemTitle,
|
||||
})
|
||||
)
|
||||
)
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
this.completeAction(fileActionId);
|
||||
})
|
||||
.finally(() => {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
clearActiveOperations(null, [item.id]);
|
||||
|
||||
setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
cancelUpdateItem = (e) => {
|
||||
const { item } = this.props;
|
||||
|
||||
const originalTitle = getTitleWithoutExst(item);
|
||||
this.setState({
|
||||
itemTitle: originalTitle,
|
||||
});
|
||||
|
||||
return this.completeAction(e);
|
||||
};
|
||||
|
||||
onClickUpdateItem = (e, open = true) => {
|
||||
const {
|
||||
fileActionType,
|
||||
setIsUpdatingRowItem,
|
||||
addActiveItems,
|
||||
item,
|
||||
} = this.props;
|
||||
|
||||
setIsUpdatingRowItem(true);
|
||||
|
||||
if (fileActionType === FileAction.Create) {
|
||||
!item.fileExst && !item.contentLength
|
||||
? addActiveItems(null, [item.id])
|
||||
: addActiveItems([item.id]);
|
||||
this.createItem(e, open);
|
||||
} else {
|
||||
this.updateItem(e);
|
||||
}
|
||||
};
|
||||
|
||||
createItem = (e, open) => {
|
||||
const {
|
||||
createFile,
|
||||
createFolder,
|
||||
fileActionTemplateId,
|
||||
isDesktop,
|
||||
isPrivacy,
|
||||
item,
|
||||
openDocEditor,
|
||||
replaceFileStream,
|
||||
setEncryptionAccess,
|
||||
setIsLoading,
|
||||
t,
|
||||
setConvertPasswordDialogVisible,
|
||||
setFormCreationInfo,
|
||||
setIsUpdatingRowItem,
|
||||
clearActiveOperations,
|
||||
addActiveItems,
|
||||
fileCopyAs,
|
||||
fromTemplate,
|
||||
gallerySelected,
|
||||
setCreatedItem,
|
||||
} = this.props;
|
||||
const { itemTitle } = this.state;
|
||||
const { parentId, fileExst } = item;
|
||||
|
||||
const isMakeFormFromFile = fileActionTemplateId ? true : false;
|
||||
|
||||
let title = itemTitle;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const itemId = e.currentTarget.dataset.itemid;
|
||||
|
||||
let createdFileId, createdFolderId;
|
||||
|
||||
if (itemTitle.trim() === "") {
|
||||
title =
|
||||
fileActionTemplateId === null
|
||||
? getDefaultFileName(item.fileExst)
|
||||
: getTitleWithoutExst(item);
|
||||
|
||||
this.setState({
|
||||
itemTitle: title,
|
||||
});
|
||||
}
|
||||
|
||||
let tab =
|
||||
!isDesktop && item.fileExst && open
|
||||
? window.open(
|
||||
combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
config.homepage,
|
||||
"/doceditor"
|
||||
),
|
||||
"_blank"
|
||||
)
|
||||
: null;
|
||||
|
||||
if (!item.fileExst && !item.contentLength) {
|
||||
createFolder(item.parentId, title)
|
||||
.then((folder) => {
|
||||
createdFolderId = folder.id;
|
||||
addActiveItems(null, [folder.id]);
|
||||
setCreatedItem({ id: createdFolderId, type: "folder" });
|
||||
})
|
||||
.then(() => this.completeAction(itemId))
|
||||
.catch((e) => {
|
||||
toastr.error(e);
|
||||
this.completeAction(itemId);
|
||||
})
|
||||
.finally(() => {
|
||||
const folderIds = [+itemId];
|
||||
createdFolderId && folderIds.push(createdFolderId);
|
||||
|
||||
setIsUpdatingRowItem(false);
|
||||
clearActiveOperations(null, folderIds);
|
||||
|
||||
return setIsLoading(false);
|
||||
});
|
||||
} else {
|
||||
if (isMakeFormFromFile) {
|
||||
fileCopyAs(
|
||||
fileActionTemplateId,
|
||||
`${title}.${item.fileExst}`,
|
||||
item.parentId
|
||||
)
|
||||
.then((file) => {
|
||||
createdFileId = file.id;
|
||||
addActiveItems([file.id]);
|
||||
|
||||
open && openDocEditor(file.id, file.providerKey, tab);
|
||||
})
|
||||
.then(() => this.completeAction(itemId))
|
||||
.catch((err) => {
|
||||
if (err.indexOf("password") == -1) {
|
||||
toastr.error(err, t("Common:Warning"));
|
||||
return;
|
||||
}
|
||||
|
||||
toastr.error(
|
||||
t("Translations:FileProtected"),
|
||||
t("Common:Warning")
|
||||
);
|
||||
|
||||
setFormCreationInfo({
|
||||
newTitle: `${title}.${item.fileExst}`,
|
||||
fromExst: ".docx",
|
||||
toExst: item.fileExst,
|
||||
open,
|
||||
actionId: itemId,
|
||||
fileInfo: {
|
||||
id: fileActionTemplateId,
|
||||
folderId: item.parentId,
|
||||
fileExst: item.fileExst,
|
||||
},
|
||||
});
|
||||
setConvertPasswordDialogVisible(true);
|
||||
|
||||
open && openDocEditor(null, null, tab);
|
||||
})
|
||||
.finally(() => {
|
||||
const fileIds = [+itemId];
|
||||
createdFileId && fileIds.push(createdFileId);
|
||||
|
||||
setIsUpdatingRowItem(false);
|
||||
clearActiveOperations(fileIds);
|
||||
|
||||
return setIsLoading(false);
|
||||
});
|
||||
} else if (fromTemplate) {
|
||||
createFile(
|
||||
parentId,
|
||||
`${itemTitle}.${fileExst}`,
|
||||
undefined,
|
||||
gallerySelected.id
|
||||
)
|
||||
.then((file) => {
|
||||
createdFileId = file.id;
|
||||
setCreatedItem({ id: createdFileId, type: "file" });
|
||||
addActiveItems([file.id]);
|
||||
|
||||
return open && openDocEditor(file.id, file.providerKey, tab);
|
||||
})
|
||||
.then(() => this.completeAction(itemId))
|
||||
.catch((e) => {
|
||||
toastr.error(e);
|
||||
tab && tab.close();
|
||||
this.completeAction(itemId);
|
||||
})
|
||||
.finally(() => {
|
||||
const fileIds = [+itemId];
|
||||
createdFileId && fileIds.push(createdFileId);
|
||||
|
||||
setIsUpdatingRowItem(false);
|
||||
clearActiveOperations(fileIds);
|
||||
|
||||
return setIsLoading(false);
|
||||
});
|
||||
} else {
|
||||
createFile(item.parentId, `${title}.${item.fileExst}`)
|
||||
.then((file) => {
|
||||
createdFileId = file.id;
|
||||
setCreatedItem({ id: createdFileId, type: "file" });
|
||||
addActiveItems([file.id]);
|
||||
|
||||
if (isPrivacy) {
|
||||
return setEncryptionAccess(file).then((encryptedFile) => {
|
||||
if (!encryptedFile) return Promise.resolve();
|
||||
toastr.info(t("Translations:EncryptedFileSaving"));
|
||||
return replaceFileStream(
|
||||
file.id,
|
||||
encryptedFile,
|
||||
true,
|
||||
false
|
||||
).then(
|
||||
() => open && openDocEditor(file.id, file.providerKey, tab)
|
||||
);
|
||||
});
|
||||
}
|
||||
return open && openDocEditor(file.id, file.providerKey, tab);
|
||||
})
|
||||
.then(() => this.completeAction(itemId))
|
||||
.catch((e) => {
|
||||
toastr.error(e);
|
||||
tab && tab.close();
|
||||
this.completeAction(itemId);
|
||||
})
|
||||
.finally(() => {
|
||||
const fileIds = [+itemId];
|
||||
createdFileId && fileIds.push(createdFileId);
|
||||
|
||||
setIsUpdatingRowItem(false);
|
||||
clearActiveOperations(fileIds);
|
||||
|
||||
return setIsLoading(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
renameTitle = (e) => {
|
||||
const { t, folderFormValidation } = this.props;
|
||||
|
||||
let title = e.target.value;
|
||||
//const chars = '*+:"<>?|/'; TODO: think how to solve problem with interpolation escape values in i18n translate
|
||||
|
||||
if (title.match(folderFormValidation)) {
|
||||
toastr.warning(t("ContainsSpecCharacter"));
|
||||
}
|
||||
|
||||
title = title.replace(folderFormValidation, "_");
|
||||
|
||||
return this.setState({ itemTitle: title });
|
||||
};
|
||||
|
||||
getStatusByDate = (create) => {
|
||||
const { culture, item, personal } = this.props;
|
||||
const { created, updated } = item;
|
||||
@ -413,7 +48,6 @@ export default function withContent(WrappedContent) {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { itemTitle } = this.state;
|
||||
const {
|
||||
element,
|
||||
isDesktop,
|
||||
@ -421,23 +55,13 @@ export default function withContent(WrappedContent) {
|
||||
item,
|
||||
onFilesClick,
|
||||
t,
|
||||
viewAs,
|
||||
|
||||
viewer,
|
||||
isUpdatingRowItem,
|
||||
passwordEntryProcess,
|
||||
isEdit,
|
||||
|
||||
titleWithoutExt,
|
||||
} = this.props;
|
||||
const {
|
||||
access,
|
||||
createdBy,
|
||||
fileExst,
|
||||
fileStatus,
|
||||
href,
|
||||
icon,
|
||||
id,
|
||||
isFolder,
|
||||
} = item;
|
||||
|
||||
const { access, createdBy, fileExst, fileStatus, href, icon, id } = item;
|
||||
|
||||
const updatedDate = this.getStatusByDate(false);
|
||||
const createdDate = this.getStatusByDate(true);
|
||||
@ -462,27 +86,8 @@ export default function withContent(WrappedContent) {
|
||||
const newItems =
|
||||
item.new || (fileStatus & FileStatus.IsNew) === FileStatus.IsNew;
|
||||
const showNew = !!newItems;
|
||||
const elementIcon = element ? (
|
||||
element
|
||||
) : (
|
||||
<ItemIcon id={id} icon={icon} fileExst={fileExst} />
|
||||
);
|
||||
|
||||
return isEdit ? (
|
||||
<EditingWrapperComponent
|
||||
className={"editing-wrapper-component"}
|
||||
elementIcon={elementIcon}
|
||||
itemTitle={itemTitle}
|
||||
itemId={id}
|
||||
viewAs={viewAs}
|
||||
renameTitle={this.renameTitle}
|
||||
onClickUpdateItem={this.onClickUpdateItem}
|
||||
cancelUpdateItem={this.cancelUpdateItem}
|
||||
isUpdatingRowItem={isUpdatingRowItem}
|
||||
passwordEntryProcess={passwordEntryProcess}
|
||||
isFolder={item.fileExst ? false : true}
|
||||
/>
|
||||
) : (
|
||||
return (
|
||||
<WrappedContent
|
||||
titleWithoutExt={titleWithoutExt}
|
||||
updatedDate={updatedDate}
|
||||
@ -531,13 +136,6 @@ export default function withContent(WrappedContent) {
|
||||
const { clearActiveOperations, fileCopyAs } = uploadDataStore;
|
||||
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
|
||||
|
||||
const {
|
||||
extension: fileActionExt,
|
||||
id: fileActionId,
|
||||
templateId: fileActionTemplateId,
|
||||
type: fileActionType,
|
||||
fromTemplate,
|
||||
} = filesStore.fileActionStore;
|
||||
const { replaceFileStream, setEncryptionAccess } = auth;
|
||||
|
||||
const {
|
||||
@ -553,20 +151,14 @@ export default function withContent(WrappedContent) {
|
||||
setFormCreationInfo,
|
||||
} = dialogsStore;
|
||||
|
||||
const isEdit =
|
||||
item.id === fileActionId && item.fileExst === fileActionExt;
|
||||
|
||||
const titleWithoutExt = getTitleWithoutExst(item, fromTemplate);
|
||||
const titleWithoutExt = getTitleWithoutExst(item, false);
|
||||
|
||||
return {
|
||||
createFile,
|
||||
createFolder,
|
||||
culture,
|
||||
editCompleteAction,
|
||||
fileActionExt,
|
||||
fileActionId,
|
||||
fileActionTemplateId,
|
||||
fileActionType,
|
||||
|
||||
folderFormValidation,
|
||||
homepage: config.homepage,
|
||||
isDesktop: isDesktopClient,
|
||||
@ -589,9 +181,9 @@ export default function withContent(WrappedContent) {
|
||||
addActiveItems,
|
||||
clearActiveOperations,
|
||||
fileCopyAs,
|
||||
isEdit,
|
||||
|
||||
titleWithoutExt,
|
||||
fromTemplate,
|
||||
|
||||
gallerySelected,
|
||||
setCreatedItem,
|
||||
personal,
|
||||
|
@ -172,9 +172,7 @@ export default function withFileActions(WrappedFileItem) {
|
||||
draggable,
|
||||
allowShareIn,
|
||||
isPrivacy,
|
||||
actionType,
|
||||
actionExtension,
|
||||
actionId,
|
||||
|
||||
sectionWidth,
|
||||
checked,
|
||||
dragging,
|
||||
@ -186,9 +184,6 @@ export default function withFileActions(WrappedFileItem) {
|
||||
} = this.props;
|
||||
const { fileExst, access, id } = item;
|
||||
|
||||
const isEdit =
|
||||
actionType !== null && actionId === id && fileExst === actionExtension;
|
||||
|
||||
const isDragging = isFolder && access < 2 && !isTrashFolder && !isPrivacy;
|
||||
|
||||
let className = isDragging ? " droppable" : "";
|
||||
@ -209,13 +204,12 @@ export default function withFileActions(WrappedFileItem) {
|
||||
|
||||
const showShare =
|
||||
!isShareable ||
|
||||
isEdit ||
|
||||
(isPrivacy && (!isDesktop || !fileExst)) ||
|
||||
(personal && !canWebEdit && !canViewedDocs)
|
||||
? false
|
||||
: true;
|
||||
|
||||
const checkedProps = isEdit || id <= 0 ? false : checked;
|
||||
const checkedProps = id <= 0 ? false : checked;
|
||||
|
||||
return (
|
||||
<WrappedFileItem
|
||||
@ -235,7 +229,6 @@ export default function withFileActions(WrappedFileItem) {
|
||||
showShare={showShare}
|
||||
checkedProps={checkedProps}
|
||||
dragging={dragging}
|
||||
isEdit={isEdit}
|
||||
getContextModel={this.getContextModel}
|
||||
{...this.props}
|
||||
/>
|
||||
@ -277,7 +270,7 @@ export default function withFileActions(WrappedFileItem) {
|
||||
selection,
|
||||
setTooltipPosition,
|
||||
setStartDrag,
|
||||
fileActionStore,
|
||||
|
||||
getFolderInfo,
|
||||
viewAs,
|
||||
bufferSelection,
|
||||
@ -290,14 +283,12 @@ export default function withFileActions(WrappedFileItem) {
|
||||
} = filesStore;
|
||||
|
||||
const { startUpload } = uploadDataStore;
|
||||
const { type, extension, id } = fileActionStore;
|
||||
|
||||
const selectedItem = selection.find(
|
||||
(x) => x.id === item.id && x.fileExst === item.fileExst
|
||||
);
|
||||
|
||||
const draggable =
|
||||
!isRecycleBinFolder && selectedItem && selectedItem.id !== id;
|
||||
const draggable = !isRecycleBinFolder && selectedItem;
|
||||
|
||||
const isFolder = selectedItem ? false : !item.isFolder ? false : true;
|
||||
const canWebEdit = settingsStore.canWebEdit(item.fileExst);
|
||||
@ -338,9 +329,7 @@ export default function withFileActions(WrappedFileItem) {
|
||||
setStartDrag,
|
||||
isFolder,
|
||||
allowShareIn: filesStore.canShare,
|
||||
actionType: type,
|
||||
actionExtension: extension,
|
||||
actionId: id,
|
||||
|
||||
checked: !!selectedItem,
|
||||
//parentFolder: selectedFolderStore.parentId,
|
||||
setParentId: selectedFolderStore.setParentId,
|
||||
|
@ -2,6 +2,7 @@ import React, { useEffect } from "react";
|
||||
import { useHotkeys } from "react-hotkeys-hook";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import { FileAction } from "@appserver/common/constants";
|
||||
import { Events } from "../helpers/constants";
|
||||
import toastr from "studio/toastr";
|
||||
|
||||
const withHotkeys = (Component) => {
|
||||
@ -12,7 +13,6 @@ const withHotkeys = (Component) => {
|
||||
setSelected,
|
||||
viewAs,
|
||||
setViewAs,
|
||||
setAction,
|
||||
setHotkeyPanelVisible,
|
||||
confirmDelete,
|
||||
setDeleteDialogVisible,
|
||||
@ -65,6 +65,20 @@ const withHotkeys = (Component) => {
|
||||
const folderWithNoAction =
|
||||
isFavoritesFolder || isRecentFolder || isTrashFolder;
|
||||
|
||||
const onCreate = (extension) => {
|
||||
if (folderWithNoAction) return;
|
||||
const event = new Event(Events.CREATE);
|
||||
|
||||
const payload = {
|
||||
extension: extension,
|
||||
id: -1,
|
||||
};
|
||||
|
||||
event.payload = payload;
|
||||
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
|
||||
@ -163,48 +177,28 @@ const withHotkeys = (Component) => {
|
||||
);
|
||||
|
||||
//Crete document
|
||||
useHotkeys(
|
||||
"Shift+d",
|
||||
() => {
|
||||
if (folderWithNoAction) return;
|
||||
setAction({ type: FileAction.Create, extension: "docx", id: -1 });
|
||||
},
|
||||
|
||||
{ ...hotkeysFilter, ...{ keyup: true } }
|
||||
);
|
||||
useHotkeys("Shift+d", () => onCreate("docx"), {
|
||||
...hotkeysFilter,
|
||||
...{ keyup: true },
|
||||
});
|
||||
|
||||
//Crete spreadsheet
|
||||
useHotkeys(
|
||||
"Shift+s",
|
||||
() => {
|
||||
if (folderWithNoAction) return;
|
||||
setAction({ type: FileAction.Create, extension: "xlsx", id: -1 });
|
||||
},
|
||||
|
||||
{ ...hotkeysFilter, ...{ keyup: true } }
|
||||
);
|
||||
useHotkeys("Shift+s", () => onCreate("xlsx"), {
|
||||
...hotkeysFilter,
|
||||
...{ keyup: true },
|
||||
});
|
||||
|
||||
//Crete presentation
|
||||
useHotkeys(
|
||||
"Shift+p",
|
||||
() => {
|
||||
if (folderWithNoAction) return;
|
||||
setAction({ type: FileAction.Create, extension: "pptx", id: -1 });
|
||||
},
|
||||
|
||||
{ ...hotkeysFilter, ...{ keyup: true } }
|
||||
);
|
||||
useHotkeys("Shift+p", () => onCreate("pptx"), {
|
||||
...hotkeysFilter,
|
||||
...{ keyup: true },
|
||||
});
|
||||
|
||||
//Crete form template
|
||||
useHotkeys(
|
||||
"Shift+o",
|
||||
() => {
|
||||
if (folderWithNoAction) return;
|
||||
setAction({ type: FileAction.Create, extension: "docxf", id: -1 });
|
||||
},
|
||||
|
||||
{ ...hotkeysFilter, ...{ keyup: true } }
|
||||
);
|
||||
useHotkeys("Shift+o", () => onCreate("docxf"), {
|
||||
...hotkeysFilter,
|
||||
...{ keyup: true },
|
||||
});
|
||||
|
||||
//Crete form template from file
|
||||
useHotkeys(
|
||||
@ -218,14 +212,10 @@ const withHotkeys = (Component) => {
|
||||
);
|
||||
|
||||
//Crete folder
|
||||
useHotkeys(
|
||||
"Shift+f",
|
||||
() => {
|
||||
if (folderWithNoAction) return;
|
||||
setAction({ type: FileAction.Create, id: -1 });
|
||||
},
|
||||
{ ...hotkeysFilter, ...{ keyup: true } }
|
||||
);
|
||||
useHotkeys("Shift+f", () => onCreate(null), {
|
||||
...hotkeysFilter,
|
||||
...{ keyup: true },
|
||||
});
|
||||
|
||||
//Delete selection
|
||||
useHotkeys(
|
||||
@ -329,7 +319,6 @@ const withHotkeys = (Component) => {
|
||||
enabledHotkeys,
|
||||
selection,
|
||||
} = filesStore;
|
||||
const { setAction } = fileActionStore;
|
||||
|
||||
const {
|
||||
selectFile,
|
||||
@ -376,7 +365,6 @@ const withHotkeys = (Component) => {
|
||||
setSelected,
|
||||
viewAs,
|
||||
setViewAs,
|
||||
setAction,
|
||||
|
||||
setHotkeyPanelVisible,
|
||||
setDeleteDialogVisible,
|
||||
|
@ -67,8 +67,6 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
isTrashFolder,
|
||||
isAdmin,
|
||||
showShare,
|
||||
fileActionExt,
|
||||
fileActionId,
|
||||
sectionWidth,
|
||||
viewAs,
|
||||
} = this.props;
|
||||
@ -79,9 +77,7 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
access === ShareAccessRights.FullAccess ||
|
||||
access === ShareAccessRights.None; // TODO: fix access type for owner (now - None)
|
||||
|
||||
const isEdit = id === fileActionId && fileExst === fileActionExt;
|
||||
|
||||
const quickButtonsComponent = !isEdit ? (
|
||||
const quickButtonsComponent = (
|
||||
<QuickButtons
|
||||
t={t}
|
||||
theme={theme}
|
||||
@ -98,7 +94,7 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
onClickFavorite={this.onClickFavorite}
|
||||
onClickShare={this.onClickShare}
|
||||
/>
|
||||
) : null;
|
||||
);
|
||||
|
||||
return (
|
||||
<WrappedComponent
|
||||
@ -125,10 +121,6 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
onSelectItem,
|
||||
} = filesActionsStore;
|
||||
|
||||
const {
|
||||
extension: fileActionExt,
|
||||
id: fileActionId,
|
||||
} = filesStore.fileActionStore;
|
||||
const { setSharingPanelVisible } = dialogsStore;
|
||||
const { canWebEdit } = settingsStore;
|
||||
return {
|
||||
@ -137,8 +129,6 @@ export default function withQuickButtons(WrappedComponent) {
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
lockFileAction,
|
||||
setFavoriteAction,
|
||||
fileActionExt,
|
||||
fileActionId,
|
||||
onSelectItem,
|
||||
setSharingPanelVisible,
|
||||
canWebEdit,
|
||||
|
@ -14,6 +14,7 @@ import MobileView from "./MobileView";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import config from "../../../../package.json";
|
||||
import withLoader from "../../../HOCs/withLoader";
|
||||
import { Events } from "../../../helpers/constants";
|
||||
|
||||
const ArticleMainButtonContent = (props) => {
|
||||
const {
|
||||
@ -47,11 +48,16 @@ const ArticleMainButtonContent = (props) => {
|
||||
const onCreate = React.useCallback(
|
||||
(e) => {
|
||||
const format = e.action || null;
|
||||
setAction({
|
||||
type: FileAction.Create,
|
||||
|
||||
const event = new Event(Events.CREATE);
|
||||
|
||||
const payload = {
|
||||
extension: format,
|
||||
id: -1,
|
||||
});
|
||||
};
|
||||
event.payload = payload;
|
||||
|
||||
window.dispatchEvent(event);
|
||||
},
|
||||
[setAction]
|
||||
);
|
||||
@ -286,13 +292,7 @@ export default inject(
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
}) => {
|
||||
const {
|
||||
isLoaded,
|
||||
firstLoad,
|
||||
isLoading,
|
||||
fileActionStore,
|
||||
canCreate,
|
||||
} = filesStore;
|
||||
const { isLoaded, firstLoad, isLoading, canCreate } = filesStore;
|
||||
const {
|
||||
isPrivacyFolder,
|
||||
isFavoritesFolder,
|
||||
@ -321,7 +321,6 @@ export default inject(
|
||||
isShareFolder,
|
||||
canCreate,
|
||||
|
||||
setAction: fileActionStore.setAction,
|
||||
startUpload,
|
||||
|
||||
setSelectFileDialogVisible,
|
||||
|
@ -5,6 +5,7 @@ import EmptyFilterContainer from "./EmptyFilterContainer";
|
||||
import EmptyFolderContainer from "./EmptyFolderContainer";
|
||||
import { FileAction } from "@appserver/common/constants";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { Events } from "../../helpers/constants";
|
||||
|
||||
const linkStyles = {
|
||||
isHovered: true,
|
||||
@ -16,7 +17,6 @@ const linkStyles = {
|
||||
|
||||
const EmptyContainer = ({
|
||||
isFiltered,
|
||||
setAction,
|
||||
isPrivacyFolder,
|
||||
parentId,
|
||||
isEncryptionSupport,
|
||||
@ -26,11 +26,16 @@ const EmptyContainer = ({
|
||||
|
||||
const onCreate = (e) => {
|
||||
const format = e.currentTarget.dataset.format || null;
|
||||
setAction({
|
||||
type: FileAction.Create,
|
||||
|
||||
const event = new Event(Events.CREATE);
|
||||
|
||||
const payload = {
|
||||
extension: format,
|
||||
id: -1,
|
||||
});
|
||||
};
|
||||
event.payload = payload;
|
||||
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
return isFiltered ? (
|
||||
@ -59,7 +64,6 @@ export default inject(
|
||||
isEncryptionSupport: auth.settingsStore.isEncryptionSupport,
|
||||
theme: auth.settingsStore.theme,
|
||||
isFiltered,
|
||||
setAction: filesStore.fileActionStore.setAction,
|
||||
isPrivacyFolder,
|
||||
parentId: selectedFolderStore.parentId,
|
||||
};
|
||||
|
@ -0,0 +1,312 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import toastr from "studio/toastr";
|
||||
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
|
||||
import config from "../../../package.json";
|
||||
|
||||
import { getTitleWithoutExst } from "../../helpers/files-helpers";
|
||||
import { getDefaultFileName } from "../../helpers/utils";
|
||||
|
||||
import Dialog from "./sub-components/Dialog";
|
||||
|
||||
const CreateEvent = ({
|
||||
id,
|
||||
type,
|
||||
extension,
|
||||
title,
|
||||
templateId,
|
||||
fromTemplate,
|
||||
onClose,
|
||||
|
||||
setIsLoading,
|
||||
createFile,
|
||||
createFolder,
|
||||
addActiveItems,
|
||||
openDocEditor,
|
||||
setIsUpdatingRowItem,
|
||||
gallerySelected,
|
||||
setCreatedItem,
|
||||
|
||||
parentId,
|
||||
|
||||
isPrivacy,
|
||||
isDesktop,
|
||||
editCompleteAction,
|
||||
|
||||
clearActiveOperations,
|
||||
fileCopyAs,
|
||||
|
||||
setConvertPasswordDialogVisible,
|
||||
setFormCreationInfo,
|
||||
|
||||
replaceFileStream,
|
||||
setEncryptionAccess,
|
||||
}) => {
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
const [headerTitle, setHeaderTitle] = React.useState(null);
|
||||
const [startValue, setStartValue] = React.useState("");
|
||||
|
||||
const { t } = useTranslation(["Translations", "Common"]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const defaultName = getDefaultFileName(extension);
|
||||
|
||||
if (title) {
|
||||
const item = { fileExst: extension, title: title };
|
||||
|
||||
setStartValue(getTitleWithoutExst(item, fromTemplate));
|
||||
} else {
|
||||
setStartValue(defaultName);
|
||||
}
|
||||
|
||||
setHeaderTitle(defaultName);
|
||||
setVisible(true);
|
||||
}, [extension, title, fromTemplate]);
|
||||
|
||||
const onSave = (e, value, open = true) => {
|
||||
let item;
|
||||
let createdFileId, createdFolderId;
|
||||
|
||||
const isMakeFormFromFile = templateId ? true : false;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const newValue = value;
|
||||
|
||||
if (value.trim() === "") {
|
||||
newValue =
|
||||
templateId === null
|
||||
? getDefaultFileName(extension)
|
||||
: getTitleWithoutExst({ fileExst: extension });
|
||||
|
||||
setStartValue(newValue);
|
||||
}
|
||||
|
||||
let tab =
|
||||
!isDesktop && extension && open
|
||||
? window.open(
|
||||
combineUrl(AppServerConfig.proxyURL, config.homepage, "/doceditor"),
|
||||
"_blank"
|
||||
)
|
||||
: null;
|
||||
|
||||
if (!extension) {
|
||||
createFolder(parentId, newValue)
|
||||
.then((folder) => {
|
||||
item = folder;
|
||||
createdFolderId = folder.id;
|
||||
addActiveItems(null, [folder.id]);
|
||||
setCreatedItem({ id: createdFolderId, type: "folder" });
|
||||
})
|
||||
.then(() => editCompleteAction(id, item, false, type))
|
||||
.catch((e) => toastr.error(e))
|
||||
.finally(() => {
|
||||
const folderIds = [+id];
|
||||
createdFolderId && folderIds.push(createdFolderId);
|
||||
|
||||
clearActiveOperations(null, folderIds);
|
||||
onClose();
|
||||
return setIsLoading(false);
|
||||
});
|
||||
} else {
|
||||
if (isMakeFormFromFile) {
|
||||
fileCopyAs(templateId, `${newValue}.${extension}`, parentId)
|
||||
.then((file) => {
|
||||
item = file;
|
||||
createdFileId = file.id;
|
||||
addActiveItems([file.id]);
|
||||
|
||||
open && openDocEditor(file.id, file.providerKey, tab);
|
||||
})
|
||||
.then(() => editCompleteAction(id, item, false, type))
|
||||
.catch((err) => {
|
||||
if (err.indexOf("password") == -1) {
|
||||
toastr.error(err, t("Common:Warning"));
|
||||
return;
|
||||
}
|
||||
|
||||
toastr.error(t("Translations:FileProtected"), t("Common:Warning"));
|
||||
|
||||
setVisible(false);
|
||||
|
||||
setFormCreationInfo({
|
||||
newTitle: `${newValue}.${extension}`,
|
||||
fromExst: ".docx",
|
||||
toExst: extension,
|
||||
open,
|
||||
actionId: id,
|
||||
fileInfo: {
|
||||
id: templateId,
|
||||
folderId: parentId,
|
||||
fileExst: extension,
|
||||
},
|
||||
});
|
||||
setConvertPasswordDialogVisible(true);
|
||||
|
||||
open && openDocEditor(null, null, tab);
|
||||
})
|
||||
.finally(() => {
|
||||
const fileIds = [+id];
|
||||
createdFileId && fileIds.push(createdFileId);
|
||||
|
||||
clearActiveOperations(fileIds);
|
||||
onClose();
|
||||
return setIsLoading(false);
|
||||
});
|
||||
} else if (fromTemplate) {
|
||||
createFile(
|
||||
parentId,
|
||||
`${newValue}.${extension}`,
|
||||
undefined,
|
||||
gallerySelected.id
|
||||
)
|
||||
.then((file) => {
|
||||
item = file;
|
||||
createdFileId = file.id;
|
||||
setCreatedItem({ id: createdFileId, type: "file" });
|
||||
addActiveItems([file.id]);
|
||||
|
||||
return open && openDocEditor(file.id, file.providerKey, tab);
|
||||
})
|
||||
.then(() => editCompleteAction(id, item, false, type))
|
||||
.catch((e) => toastr.error(e))
|
||||
.finally(() => {
|
||||
const fileIds = [+id];
|
||||
createdFileId && fileIds.push(createdFileId);
|
||||
|
||||
clearActiveOperations(fileIds);
|
||||
onClose();
|
||||
return setIsLoading(false);
|
||||
});
|
||||
} else {
|
||||
createFile(parentId, `${newValue}.${extension}`)
|
||||
.then((file) => {
|
||||
createdFileId = file.id;
|
||||
item = file;
|
||||
setCreatedItem({ id: createdFileId, type: "file" });
|
||||
addActiveItems([file.id]);
|
||||
|
||||
if (isPrivacy) {
|
||||
return setEncryptionAccess(file).then((encryptedFile) => {
|
||||
if (!encryptedFile) return Promise.resolve();
|
||||
toastr.info(t("Translations:EncryptedFileSaving"));
|
||||
|
||||
return replaceFileStream(
|
||||
file.id,
|
||||
encryptedFile,
|
||||
true,
|
||||
false
|
||||
).then(
|
||||
() => open && openDocEditor(file.id, file.providerKey, tab)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return open && openDocEditor(file.id, file.providerKey, tab);
|
||||
})
|
||||
.then(() => editCompleteAction(id, item, false, type))
|
||||
.catch((e) => toastr.error(e))
|
||||
.finally(() => {
|
||||
const fileIds = [+id];
|
||||
createdFileId && fileIds.push(createdFileId);
|
||||
|
||||
clearActiveOperations(fileIds);
|
||||
onClose();
|
||||
return setIsLoading(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onCancel = React.useCallback(
|
||||
(e) => {
|
||||
onClose && onClose();
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
t={t}
|
||||
visible={visible}
|
||||
title={headerTitle}
|
||||
startValue={startValue}
|
||||
onSave={onSave}
|
||||
onCancel={onCancel}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(
|
||||
({
|
||||
auth,
|
||||
filesStore,
|
||||
filesActionsStore,
|
||||
selectedFolderStore,
|
||||
treeFoldersStore,
|
||||
uploadDataStore,
|
||||
dialogsStore,
|
||||
}) => {
|
||||
const {
|
||||
setIsLoading,
|
||||
createFile,
|
||||
createFolder,
|
||||
addActiveItems,
|
||||
openDocEditor,
|
||||
setIsUpdatingRowItem,
|
||||
gallerySelected,
|
||||
setCreatedItem,
|
||||
} = filesStore;
|
||||
|
||||
const { editCompleteAction } = filesActionsStore;
|
||||
|
||||
const { clearActiveOperations, fileCopyAs } = uploadDataStore;
|
||||
|
||||
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
|
||||
|
||||
const { id: parentId } = selectedFolderStore;
|
||||
|
||||
const { replaceFileStream, setEncryptionAccess } = auth;
|
||||
|
||||
const { isDesktopClient } = auth.settingsStore;
|
||||
|
||||
const {
|
||||
setConvertPasswordDialogVisible,
|
||||
|
||||
setFormCreationInfo,
|
||||
} = dialogsStore;
|
||||
|
||||
return {
|
||||
setIsLoading,
|
||||
createFile,
|
||||
createFolder,
|
||||
addActiveItems,
|
||||
openDocEditor,
|
||||
setIsUpdatingRowItem,
|
||||
gallerySelected,
|
||||
setCreatedItem,
|
||||
|
||||
parentId,
|
||||
|
||||
isDesktop: isDesktopClient,
|
||||
isPrivacy: isPrivacyFolder,
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
editCompleteAction,
|
||||
|
||||
clearActiveOperations,
|
||||
fileCopyAs,
|
||||
|
||||
setConvertPasswordDialogVisible,
|
||||
setFormCreationInfo,
|
||||
|
||||
replaceFileStream,
|
||||
setEncryptionAccess,
|
||||
};
|
||||
}
|
||||
)(observer(CreateEvent));
|
@ -0,0 +1,142 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import toastr from "studio/toastr";
|
||||
|
||||
import { getTitleWithoutExst } from "../../helpers/files-helpers";
|
||||
|
||||
import Dialog from "./sub-components/Dialog";
|
||||
|
||||
const RenameEvent = ({
|
||||
type,
|
||||
item,
|
||||
onClose,
|
||||
|
||||
setIsLoading,
|
||||
addActiveItems,
|
||||
|
||||
updateFile,
|
||||
renameFolder,
|
||||
|
||||
editCompleteAction,
|
||||
clearActiveOperations,
|
||||
}) => {
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
|
||||
const [startValue, setStartValue] = React.useState("");
|
||||
|
||||
const { t } = useTranslation(["Home"]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setStartValue(getTitleWithoutExst(item, false));
|
||||
|
||||
setVisible(true);
|
||||
}, [item]);
|
||||
|
||||
const onUpdate = React.useCallback((e, value) => {
|
||||
const originalTitle = getTitleWithoutExst(item);
|
||||
|
||||
setIsLoading(true);
|
||||
let timerId;
|
||||
|
||||
const isSameTitle =
|
||||
originalTitle.trim() === value.trim() || value.trim() === "";
|
||||
|
||||
const isFile = item.fileExst || item.contentLength;
|
||||
|
||||
if (isSameTitle) {
|
||||
setStartValue(originalTitle);
|
||||
|
||||
return editCompleteAction(item.id, item, isSameTitle, type);
|
||||
} else {
|
||||
timerId = setTimeout(() => {
|
||||
isFile ? addActiveItems([item.id]) : addActiveItems(null, [item.id]);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
isFile
|
||||
? updateFile(item.id, value)
|
||||
.then(() => editCompleteAction(item.id, item, false, type))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
t("FileRenamed", {
|
||||
oldTitle: item.title,
|
||||
newTitle: value + item.fileExst,
|
||||
})
|
||||
)
|
||||
)
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
editCompleteAction(item.id, item, false, type);
|
||||
})
|
||||
.finally(() => {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
clearActiveOperations([item.id]);
|
||||
|
||||
setIsLoading(false);
|
||||
onClose();
|
||||
})
|
||||
: renameFolder(item.id, value)
|
||||
.then(() => editCompleteAction(item.id, item, false, type))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
t("FolderRenamed", {
|
||||
folderTitle: item.title,
|
||||
newFoldedTitle: value,
|
||||
})
|
||||
)
|
||||
)
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
editCompleteAction(item.id, item, false, type);
|
||||
})
|
||||
.finally(() => {
|
||||
clearTimeout(timerId);
|
||||
timerId = null;
|
||||
clearActiveOperations(null, [item.id]);
|
||||
|
||||
setIsLoading(false);
|
||||
onClose();
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onCancel = React.useCallback(
|
||||
(e) => {
|
||||
onClose && onClose();
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
t={t}
|
||||
visible={visible}
|
||||
title={t("Home: Rename")}
|
||||
startValue={startValue}
|
||||
onSave={onUpdate}
|
||||
onCancel={onCancel}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ filesStore, filesActionsStore, uploadDataStore }) => {
|
||||
const { setIsLoading, addActiveItems, updateFile, renameFolder } = filesStore;
|
||||
|
||||
const { editCompleteAction } = filesActionsStore;
|
||||
|
||||
const { clearActiveOperations } = uploadDataStore;
|
||||
|
||||
return {
|
||||
setIsLoading,
|
||||
addActiveItems,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
|
||||
editCompleteAction,
|
||||
|
||||
clearActiveOperations,
|
||||
};
|
||||
})(observer(RenameEvent));
|
@ -0,0 +1,93 @@
|
||||
import React from "react";
|
||||
|
||||
import { FileAction } from "@appserver/common/constants";
|
||||
|
||||
import { Events } from "../../helpers/constants";
|
||||
|
||||
import CreateEvent from "./CreateEvent";
|
||||
import RenameEvent from "./RenameEvent";
|
||||
|
||||
const GlobalEvents = () => {
|
||||
const [createDialogProps, setCreateDialogProps] = React.useState({
|
||||
visible: false,
|
||||
id: null,
|
||||
type: null,
|
||||
extension: null,
|
||||
title: "",
|
||||
templateId: null,
|
||||
fromTemplate: null,
|
||||
onClose: null,
|
||||
});
|
||||
|
||||
const [renameDialogProps, setRenameDialogProps] = React.useState({
|
||||
visible: false,
|
||||
item: null,
|
||||
onClose: null,
|
||||
});
|
||||
|
||||
const onCreate = React.useCallback((e) => {
|
||||
const { payload } = e;
|
||||
|
||||
const visible = payload.id ? true : false;
|
||||
|
||||
setCreateDialogProps({
|
||||
visible: visible,
|
||||
id: payload.id,
|
||||
type: FileAction.Create,
|
||||
extension: payload.extension,
|
||||
title: payload.title || null,
|
||||
templateId: payload.templateId || null,
|
||||
fromTemplate: payload.fromTemplate || null,
|
||||
onClose: () => {
|
||||
setCreateDialogProps({
|
||||
visible: false,
|
||||
id: null,
|
||||
type: null,
|
||||
extension: null,
|
||||
title: "",
|
||||
templateId: null,
|
||||
fromTemplate: null,
|
||||
onClose: null,
|
||||
});
|
||||
},
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onRename = React.useCallback((e) => {
|
||||
const visible = e.item ? true : false;
|
||||
|
||||
setRenameDialogProps({
|
||||
visible: visible,
|
||||
type: FileAction.Rename,
|
||||
item: e.item,
|
||||
onClose: () => {
|
||||
setRenameDialogProps({
|
||||
visible: false,
|
||||
typ: null,
|
||||
item: null,
|
||||
});
|
||||
},
|
||||
});
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
window.addEventListener(Events.CREATE, onCreate);
|
||||
window.addEventListener(Events.RENAME, onRename);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(Events.CREATE, onCreate);
|
||||
window.removeEventListener(Events.RENAME, onRename);
|
||||
};
|
||||
}, [onRename, onCreate]);
|
||||
|
||||
return [
|
||||
createDialogProps.visible && (
|
||||
<CreateEvent key={Events.CREATE} {...createDialogProps} />
|
||||
),
|
||||
renameDialogProps.visible && (
|
||||
<RenameEvent key={Events.RENAME} {...renameDialogProps} />
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
export default React.memo(GlobalEvents);
|
@ -0,0 +1,120 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import toastr from "@appserver/components/toast/toastr";
|
||||
import ModalDialog from "@appserver/components/modal-dialog";
|
||||
import TextInput from "@appserver/components/text-input";
|
||||
import SaveCancelButtons from "@appserver/components/save-cancel-buttons";
|
||||
|
||||
const StyledModalDialog = styled(ModalDialog)`
|
||||
width: 400px;
|
||||
|
||||
@media (max-width: 400px) {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledSaveCancelButtons = styled(SaveCancelButtons)`
|
||||
position: relative !important;
|
||||
|
||||
padding: 8px 0 0;
|
||||
|
||||
.buttons-flex {
|
||||
width: 100%;
|
||||
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 8px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const Dialog = ({
|
||||
t,
|
||||
title,
|
||||
startValue,
|
||||
visible,
|
||||
folderFormValidation,
|
||||
onSave,
|
||||
onCancel,
|
||||
onClose,
|
||||
}) => {
|
||||
const [value, setValue] = React.useState("");
|
||||
const [isDisabled, setIsDisabled] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (startValue) setValue(startValue);
|
||||
}, [startValue]);
|
||||
|
||||
const onChange = React.useCallback((e) => {
|
||||
let newValue = e.target.value;
|
||||
|
||||
if (newValue.match(folderFormValidation)) {
|
||||
toastr.warning(t("ContainsSpecCharacter"));
|
||||
}
|
||||
|
||||
newValue = newValue.replace(folderFormValidation, "_");
|
||||
|
||||
setValue(newValue);
|
||||
}, []);
|
||||
|
||||
const onFocus = React.useCallback((e) => {
|
||||
e.target.select();
|
||||
}, []);
|
||||
|
||||
const onSaveAction = React.useCallback(
|
||||
(e) => {
|
||||
setIsDisabled(true);
|
||||
onSave && onSave(e, value);
|
||||
},
|
||||
[onSave, value]
|
||||
);
|
||||
|
||||
const onCancelAction = React.useCallback((e) => {
|
||||
onCancel && onCancel(e);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<StyledModalDialog
|
||||
visible={visible}
|
||||
displayType={"modal"}
|
||||
scale={true}
|
||||
onClose={onClose}
|
||||
>
|
||||
<ModalDialog.Header>{title}</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<TextInput
|
||||
name={"create"}
|
||||
type={"text"}
|
||||
scale={true}
|
||||
value={value}
|
||||
isAutoFocussed={true}
|
||||
tabIndex={1}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
<StyledSaveCancelButtons
|
||||
saveButtonLabel={"Save"}
|
||||
cancelButtonLabel={"Cancel"}
|
||||
onSaveClick={onSaveAction}
|
||||
onCancelClick={onCancelAction}
|
||||
showReminder={!isDisabled}
|
||||
/>
|
||||
</ModalDialog.Footer>
|
||||
</StyledModalDialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => {
|
||||
const { folderFormValidation } = auth.settingsStore;
|
||||
|
||||
return { folderFormValidation };
|
||||
})(observer(Dialog));
|
@ -23,35 +23,42 @@ const ItemIcon = ({
|
||||
fileExst,
|
||||
isPrivacy,
|
||||
viewAs,
|
||||
actionType,
|
||||
actionExtension,
|
||||
actionId,
|
||||
// actionType,
|
||||
// actionExtension,
|
||||
// actionId,
|
||||
}) => {
|
||||
const isEdit =
|
||||
(actionType !== null && actionId === id && fileExst === actionExtension) ||
|
||||
id <= 0;
|
||||
// const isEdit =
|
||||
// (actionType !== null && actionId === id && fileExst === actionExtension) ||
|
||||
// id <= 0;
|
||||
|
||||
// return (
|
||||
// <>
|
||||
// <StyledIcon
|
||||
// className={`react-svg-icon${isEdit ? " is-edit" : ""}`}
|
||||
// src={icon}
|
||||
// />
|
||||
// {isPrivacy && fileExst && (
|
||||
// <EncryptedFileIcon isEdit={isEdit && viewAs !== "tile"} />
|
||||
// )}
|
||||
// </>
|
||||
// );
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledIcon
|
||||
className={`react-svg-icon${isEdit ? " is-edit" : ""}`}
|
||||
src={icon}
|
||||
/>
|
||||
{isPrivacy && fileExst && (
|
||||
<EncryptedFileIcon isEdit={isEdit && viewAs !== "tile"} />
|
||||
)}
|
||||
<StyledIcon className={`react-svg-icon`} src={icon} />
|
||||
{isPrivacy && fileExst && <EncryptedFileIcon isEdit={false} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ filesStore, treeFoldersStore }) => {
|
||||
const { type, extension, id } = filesStore.fileActionStore;
|
||||
// const { type, extension, id } = filesStore.fileActionStore;
|
||||
|
||||
return {
|
||||
viewAs: filesStore.viewAs,
|
||||
isPrivacy: treeFoldersStore.isPrivacyFolder,
|
||||
actionType: type,
|
||||
actionExtension: extension,
|
||||
actionId: id,
|
||||
// actionType: type,
|
||||
// actionExtension: extension,
|
||||
// actionId: id,
|
||||
};
|
||||
})(observer(ItemIcon));
|
||||
|
@ -10,3 +10,5 @@ export const thumbnailStatuses = {
|
||||
};
|
||||
|
||||
export const ADS_TIMEOUT = 300000; // 5 min
|
||||
|
||||
export const Events = Object.freeze({ CREATE: "create", RENAME: "rename" });
|
||||
|
@ -20,7 +20,6 @@ const SectionBodyContent = (props) => {
|
||||
const {
|
||||
t,
|
||||
tReady,
|
||||
fileActionId,
|
||||
isEmptyFilesList,
|
||||
folderId,
|
||||
dragging,
|
||||
@ -243,7 +242,7 @@ const SectionBodyContent = (props) => {
|
||||
return (
|
||||
<Consumer>
|
||||
{(context) =>
|
||||
(!fileActionId && isEmptyFilesList) || null ? (
|
||||
isEmptyFilesList || null ? (
|
||||
<>
|
||||
<EmptyContainer />
|
||||
</>
|
||||
@ -277,7 +276,6 @@ export default inject(
|
||||
uploadDataStore,
|
||||
}) => {
|
||||
const {
|
||||
fileActionStore,
|
||||
isEmptyFilesList,
|
||||
dragging,
|
||||
setDragging,
|
||||
@ -299,7 +297,7 @@ export default inject(
|
||||
dragging,
|
||||
startDrag,
|
||||
setStartDrag,
|
||||
fileActionId: fileActionStore.id,
|
||||
|
||||
isEmptyFilesList,
|
||||
setDragging,
|
||||
folderId: selectedFolderStore.id,
|
||||
|
@ -13,6 +13,7 @@ import { Consumer } from "@appserver/components/utils/context";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import TableGroupMenu from "@appserver/components/table-container/TableGroupMenu";
|
||||
import Navigation from "@appserver/common/components/Navigation";
|
||||
import { Events } from "../../../../helpers/constants";
|
||||
import config from "../../../../../package.json";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
|
||||
@ -49,11 +50,16 @@ class SectionHeaderContent extends React.Component {
|
||||
}
|
||||
|
||||
onCreate = (format) => {
|
||||
this.props.setAction({
|
||||
type: FileAction.Create,
|
||||
const event = new Event(Events.CREATE);
|
||||
|
||||
const payload = {
|
||||
extension: format,
|
||||
id: -1,
|
||||
});
|
||||
};
|
||||
|
||||
event.payload = payload;
|
||||
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
createDocument = () => this.onCreate("docx");
|
||||
@ -445,7 +451,7 @@ export default inject(
|
||||
const {
|
||||
setSelected,
|
||||
setSelection,
|
||||
fileActionStore,
|
||||
|
||||
canCreate,
|
||||
isHeaderVisible,
|
||||
isHeaderIndeterminate,
|
||||
@ -462,7 +468,7 @@ export default inject(
|
||||
activeFiles,
|
||||
activeFolders,
|
||||
} = filesStore;
|
||||
const { setAction } = fileActionStore;
|
||||
|
||||
const {
|
||||
setSharingPanelVisible,
|
||||
setMoveToPanelVisible,
|
||||
@ -509,7 +515,7 @@ export default inject(
|
||||
|
||||
setSelected,
|
||||
setSelection,
|
||||
setAction,
|
||||
|
||||
setSharingPanelVisible,
|
||||
setMoveToPanelVisible,
|
||||
setCopyPanelVisible,
|
||||
|
@ -32,7 +32,7 @@ import DragTooltip from "../../components/DragTooltip";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import config from "../../../package.json";
|
||||
import { Consumer } from "@appserver/components/utils/context";
|
||||
import { FileAction } from "@appserver/common/constants";
|
||||
import { Events } from "../../helpers/constants";
|
||||
|
||||
class PureHome extends React.Component {
|
||||
componentDidMount() {
|
||||
@ -48,7 +48,6 @@ class PureHome extends React.Component {
|
||||
isMediaOrImage,
|
||||
getFileInfo,
|
||||
gallerySelected,
|
||||
setAction,
|
||||
setIsUpdatingRowItem,
|
||||
} = this.props;
|
||||
|
||||
@ -169,13 +168,19 @@ class PureHome extends React.Component {
|
||||
.then(() => {
|
||||
if (gallerySelected) {
|
||||
setIsUpdatingRowItem(false);
|
||||
setAction({
|
||||
type: FileAction.Create,
|
||||
|
||||
const event = new Event(Events.CREATE);
|
||||
|
||||
const payload = {
|
||||
extension: "docxf",
|
||||
id: -1,
|
||||
fromTemplate: true,
|
||||
title: gallerySelected.attributes.name_form,
|
||||
id: -1,
|
||||
});
|
||||
};
|
||||
|
||||
event.payload = payload;
|
||||
|
||||
window.dispatchEvent(event);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@ -290,7 +295,7 @@ class PureHome extends React.Component {
|
||||
//console.log("Home render");
|
||||
const {
|
||||
viewAs,
|
||||
fileActionId,
|
||||
|
||||
firstLoad,
|
||||
isHeaderVisible,
|
||||
isPrivacyFolder,
|
||||
@ -337,9 +342,7 @@ class PureHome extends React.Component {
|
||||
clearUploadedFilesHistory={clearUploadedFilesHistory}
|
||||
viewAs={viewAs}
|
||||
hideAside={
|
||||
!!fileActionId ||
|
||||
primaryProgressDataVisible ||
|
||||
secondaryProgressDataStoreVisible //TODO: use hideArticle action
|
||||
primaryProgressDataVisible || secondaryProgressDataStoreVisible //TODO: use hideArticle action
|
||||
}
|
||||
isLoaded={!firstLoad}
|
||||
isHeaderVisible={isHeaderVisible}
|
||||
@ -412,7 +415,6 @@ export default inject(
|
||||
firstLoad,
|
||||
setFirstLoad,
|
||||
fetchFiles,
|
||||
fileActionStore,
|
||||
selection,
|
||||
setSelections,
|
||||
dragging,
|
||||
@ -425,7 +427,6 @@ export default inject(
|
||||
setIsUpdatingRowItem,
|
||||
} = filesStore;
|
||||
|
||||
const { id, setAction } = fileActionStore;
|
||||
const {
|
||||
isRecycleBinFolder,
|
||||
isPrivacyFolder,
|
||||
@ -478,7 +479,6 @@ export default inject(
|
||||
homepage: config.homepage,
|
||||
firstLoad,
|
||||
dragging,
|
||||
fileActionId: id,
|
||||
viewAs,
|
||||
uploaded,
|
||||
converted,
|
||||
@ -527,7 +527,6 @@ export default inject(
|
||||
isMediaOrImage: settingsStore.isMediaOrImage,
|
||||
getFileInfo,
|
||||
gallerySelected,
|
||||
setAction,
|
||||
setIsUpdatingRowItem,
|
||||
};
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
isMobile as isMobileUtils,
|
||||
isTablet as isTabletUtils,
|
||||
} from "@appserver/components/utils/device";
|
||||
import { Events } from "../helpers/constants";
|
||||
|
||||
class ContextOptionsStore {
|
||||
authStore;
|
||||
@ -246,12 +247,11 @@ class ContextOptionsStore {
|
||||
};
|
||||
|
||||
onClickRename = (item) => {
|
||||
const { id, fileExst } = item;
|
||||
this.filesStore.fileActionStore.setAction({
|
||||
type: FileAction.Rename,
|
||||
extension: fileExst,
|
||||
id,
|
||||
});
|
||||
const event = new Event(Events.RENAME);
|
||||
|
||||
event.item = item;
|
||||
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
onChangeThirdPartyInfo = (providerKey) => {
|
||||
@ -793,13 +793,11 @@ class ContextOptionsStore {
|
||||
|
||||
getModel = (item, t) => {
|
||||
const { selection } = this.filesStore;
|
||||
const { type, id, extension } = this.filesStore.fileActionStore;
|
||||
|
||||
const { fileExst, contextOptions } = item;
|
||||
|
||||
const isEdit = !!type && id === item.id && fileExst === extension;
|
||||
|
||||
const contextOptionsProps =
|
||||
!isEdit && contextOptions && contextOptions.length > 0
|
||||
contextOptions && contextOptions.length > 0
|
||||
? selection.length > 1
|
||||
? this.getGroupContextOptions(t)
|
||||
: this.getFilesContextOptions(item, t)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { getNewFiles } from "@appserver/common/api/files";
|
||||
import { FileAction } from "@appserver/common/constants";
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import { Events } from "../helpers/constants";
|
||||
|
||||
class DialogsStore {
|
||||
authStore;
|
||||
@ -212,18 +213,21 @@ class DialogsStore {
|
||||
};
|
||||
|
||||
createMasterForm = async (fileInfo) => {
|
||||
const { setAction } = this.filesStore.fileActionStore;
|
||||
|
||||
let newTitle = fileInfo.title;
|
||||
newTitle = newTitle.substring(0, newTitle.lastIndexOf("."));
|
||||
|
||||
setAction({
|
||||
type: FileAction.Create,
|
||||
const event = new Event(Events.CREATE);
|
||||
|
||||
const payload = {
|
||||
extension: "docxf",
|
||||
id: -1,
|
||||
title: `${newTitle}.docxf`,
|
||||
templateId: fileInfo.id,
|
||||
});
|
||||
};
|
||||
|
||||
event.payload = payload;
|
||||
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
get someDialogIsOpen() {
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { makeAutoObservable } from "mobx";
|
||||
|
||||
class FileActionStore {
|
||||
id = null;
|
||||
type = null;
|
||||
extension = null;
|
||||
title = "";
|
||||
templateId = null;
|
||||
fromTemplate = null;
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
setAction = (fileAction) => {
|
||||
if (fileAction.fromTemplate === undefined && this.fromTemplate) return;
|
||||
|
||||
const fileActionItems = Object.keys(fileAction);
|
||||
for (let key of fileActionItems) {
|
||||
if (key in this) {
|
||||
this[key] = fileAction[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new FileActionStore();
|
@ -20,7 +20,7 @@ import {
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import toastr from "studio/toastr";
|
||||
|
||||
import { TIMEOUT } from "../helpers/constants";
|
||||
import { Events, TIMEOUT } from "../helpers/constants";
|
||||
import { loopTreeFolders, checkProtocol } from "../helpers/files-helpers";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
@ -453,16 +453,16 @@ class FilesActionStore {
|
||||
return this.downloadFiles(fileIds, folderIds, label);
|
||||
};
|
||||
|
||||
editCompleteAction = async (id, selectedItem, isCancelled = false) => {
|
||||
editCompleteAction = async (id, selectedItem, isCancelled = false, type) => {
|
||||
const {
|
||||
filter,
|
||||
folders,
|
||||
files,
|
||||
fileActionStore,
|
||||
|
||||
fetchFiles,
|
||||
setIsLoading,
|
||||
} = this.filesStore;
|
||||
const { type, setAction } = fileActionStore;
|
||||
|
||||
const { treeFolders, setTreeFolders } = this.treeFoldersStore;
|
||||
|
||||
const items = [...folders, ...files];
|
||||
@ -480,14 +480,7 @@ class FilesActionStore {
|
||||
setTreeFolders(treeFolders);
|
||||
}
|
||||
}
|
||||
setAction({
|
||||
type: null,
|
||||
id: null,
|
||||
extension: null,
|
||||
title: "",
|
||||
templateId: null,
|
||||
fromTemplate: null,
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
type === FileAction.Rename &&
|
||||
this.onSelectItem(
|
||||
|
@ -26,7 +26,7 @@ class FilesStore {
|
||||
authStore;
|
||||
settingsStore;
|
||||
userStore;
|
||||
fileActionStore;
|
||||
|
||||
selectedFolderStore;
|
||||
treeFoldersStore;
|
||||
filesSettingsStore;
|
||||
@ -78,7 +78,7 @@ class FilesStore {
|
||||
authStore,
|
||||
settingsStore,
|
||||
userStore,
|
||||
fileActionStore,
|
||||
|
||||
selectedFolderStore,
|
||||
treeFoldersStore,
|
||||
filesSettingsStore
|
||||
@ -90,7 +90,7 @@ class FilesStore {
|
||||
this.authStore = authStore;
|
||||
this.settingsStore = settingsStore;
|
||||
this.userStore = userStore;
|
||||
this.fileActionStore = fileActionStore;
|
||||
|
||||
this.selectedFolderStore = selectedFolderStore;
|
||||
this.treeFoldersStore = treeFoldersStore;
|
||||
this.filesSettingsStore = filesSettingsStore;
|
||||
@ -654,7 +654,6 @@ class FilesStore {
|
||||
});
|
||||
|
||||
if (clearFilter) {
|
||||
this.fileActionStore.setAction({ type: null });
|
||||
if (clearSelection) {
|
||||
this.setSelected("close");
|
||||
}
|
||||
@ -1669,10 +1668,6 @@ class FilesStore {
|
||||
};
|
||||
});
|
||||
|
||||
if (this.fileActionStore.type === FileAction.Create) {
|
||||
this.onCreateAddTempItem(newItem);
|
||||
}
|
||||
|
||||
return newItem;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import FilesStore from "./FilesStore";
|
||||
import fileActionStore from "./FileActionStore";
|
||||
import SelectedFolderStore from "./SelectedFolderStore";
|
||||
import TreeFoldersStore from "./TreeFoldersStore";
|
||||
import thirdPartyStore from "./ThirdPartyStore";
|
||||
@ -26,7 +25,6 @@ const filesStore = new FilesStore(
|
||||
store.auth,
|
||||
store.auth.settingsStore,
|
||||
store.auth.userStore,
|
||||
fileActionStore,
|
||||
selectedFolderStore,
|
||||
treeFoldersStore,
|
||||
settingsStore,
|
||||
|
Loading…
Reference in New Issue
Block a user