Merge pull request #350 from ONLYOFFICE/bugfix/folder-header-menu

Web: Files: added move, copy and download actions in folder header menu
This commit is contained in:
Ilya Oleshko 2021-10-20 17:39:23 +03:00 committed by GitHub
commit 3d5228c8a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 202 additions and 54 deletions

View File

@ -16,8 +16,10 @@ const OperationsPanelComponent = (props) => {
visible,
provider,
selection,
isFolderActions,
isRecycleBin,
setDestFolderId,
setIsFolderActions,
currentFolderId,
operationsFolders,
setCopyPanelVisible,
@ -25,6 +27,7 @@ const OperationsPanelComponent = (props) => {
setMoveToPanelVisible,
checkOperationConflict,
setThirdPartyMoveDialogVisible,
parentFolderId,
} = props;
const zIndex = 310;
@ -33,7 +36,12 @@ const OperationsPanelComponent = (props) => {
const expandedKeys = props.expandedKeys.map((item) => item.toString());
const onClose = () => {
isCopy ? setCopyPanelVisible(false) : setMoveToPanelVisible(false);
if (isCopy) {
setCopyPanelVisible(false);
setIsFolderActions(false);
} else {
setMoveToPanelVisible(false);
}
setExpandedPanelKeys(null);
};
@ -41,6 +49,10 @@ const OperationsPanelComponent = (props) => {
const folderTitle = treeNode.node.props.title;
const destFolderId = isNaN(+folder[0]) ? folder[0] : +folder[0];
if (isFolderActions && destFolderId === parentFolderId) {
return onClose();
}
if (currentFolderId === destFolderId) {
return onClose();
}
@ -68,8 +80,9 @@ const OperationsPanelComponent = (props) => {
? selection.filter((x) => !x.providerKey)
: selection;
const fileIds = [];
const folderIds = [];
let fileIds = [];
let folderIds = [];
for (let item of items) {
if (item.fileExst || item.contentLength) {
@ -81,6 +94,13 @@ const OperationsPanelComponent = (props) => {
}
}
if (isFolderActions) {
fileIds = [];
folderIds = [];
folderIds.push(currentFolderId);
}
if (!folderIds.length && !fileIds.length) return;
checkOperationConflict({
@ -152,10 +172,12 @@ export default inject(
const {
moveToPanelVisible,
copyPanelVisible,
isFolderActions,
setCopyPanelVisible,
setMoveToPanelVisible,
setDestFolderId,
setThirdPartyMoveDialogVisible,
setIsFolderActions,
} = dialogsStore;
const selections = selection.length ? selection : [bufferSelection];
@ -167,16 +189,19 @@ export default inject(
? expandedPanelKeys
: selectedFolderStore.pathParts,
currentFolderId: selectedFolderStore.id,
parentFolderId: selectedFolderStore.parentId,
isRecycleBin: isRecycleBinFolder,
filter,
operationsFolders,
visible: copyPanelVisible || moveToPanelVisible,
provider,
selection: selections,
isFolderActions,
setCopyPanelVisible,
setMoveToPanelVisible,
setDestFolderId,
setIsFolderActions,
setThirdPartyMoveDialogVisible,
checkOperationConflict,
setExpandedPanelKeys,

View File

@ -78,7 +78,11 @@ class SharingPanelComponent extends React.Component {
};
updateRowData = (newRowData) => {
const { getFileInfo, getFolderInfo } = this.props;
const { getFileInfo, getFolderInfo, isFolderActions, id } = this.props;
if (isFolderActions) {
return getFolderInfo(id);
}
for (let item of newRowData) {
!item.fileExst ? getFolderInfo(item.id) : getFileInfo(item.id);
@ -105,7 +109,9 @@ class SharingPanelComponent extends React.Component {
isDesktop,
setEncryptionAccess,
setShareFiles,
setIsFolderActions,
onSuccess,
isFolderActions,
} = this.props;
let folderIds = [];
@ -153,6 +159,13 @@ class SharingPanelComponent extends React.Component {
}
}
if (isFolderActions) {
folderIds = [];
fileIds = [];
folderIds.push(selection[0]);
}
const owner = shareDataItems.find((x) => x.isOwner);
const ownerId =
filesOwnerId !== owner.sharedTo.id ? owner.sharedTo.id : null;
@ -205,7 +218,10 @@ class SharingPanelComponent extends React.Component {
})
.then(() => onSuccess && onSuccess())
.catch((err) => toastr.error(err))
.finally(() => setIsLoading(false));
.finally(() => {
setIsFolderActions(false);
setIsLoading(false);
});
};
onNotifyUsersChange = () =>
this.setState({ isNotifyUsers: !this.state.isNotifyUsers });
@ -240,9 +256,10 @@ class SharingPanelComponent extends React.Component {
};
getData = () => {
const { selection } = this.props;
const folderId = [];
const fileId = [];
const { selection, id, access } = this.props;
let folderId = [];
let fileId = [];
for (let item of selection) {
if (item.access === 1 || item.access === 0) {
@ -254,6 +271,13 @@ class SharingPanelComponent extends React.Component {
}
}
if (this.props.isFolderActions) {
folderId = [];
fileId = [];
folderId = access === 1 || access === 0 ? [id] : [];
}
return [folderId, fileId];
};
@ -269,7 +293,6 @@ class SharingPanelComponent extends React.Component {
const returnValue = this.getData();
const folderId = returnValue[0];
const fileId = returnValue[1];
if (folderId.length !== 0 || fileId.length !== 0) {
!isMobile && setIsLoading(true);
getShareUsers(folderId, fileId)
@ -341,10 +364,14 @@ class SharingPanelComponent extends React.Component {
onCancel,
setSharingPanelVisible,
selectUploadedFile,
setIsFolderActions,
setSelection,
setBufferSelection,
} = this.props;
setSharingPanelVisible(false);
setSelection([]);
selectUploadedFile([]);
setBufferSelection(null);
onCancel && onCancel();
@ -618,12 +645,21 @@ class SharingPanelComponent extends React.Component {
const SharingPanel = inject(
(
{ auth, filesStore, uploadDataStore, dialogsStore, treeFoldersStore },
{
auth,
filesStore,
uploadDataStore,
dialogsStore,
treeFoldersStore,
selectedFolderStore,
},
{ uploadPanelVisible }
) => {
const { replaceFileStream, setEncryptionAccess } = auth;
const { personal, customNames, isDesktopClient } = auth.settingsStore;
const { id, access } = selectedFolderStore;
const {
selection,
bufferSelection,
@ -635,13 +671,19 @@ const SharingPanel = inject(
getShareUsers,
setShareFiles,
setIsLoading,
setSelection,
getFileInfo,
getFolderInfo,
isLoading,
setBufferSelection,
} = filesStore;
const { isPrivacyFolder } = treeFoldersStore;
const { setSharingPanelVisible, sharingPanelVisible } = dialogsStore;
const {
setSharingPanelVisible,
sharingPanelVisible,
setIsFolderActions,
isFolderActions,
} = dialogsStore;
const {
selectedUploadFile,
selectUploadedFile,
@ -661,11 +703,14 @@ const SharingPanel = inject(
: [bufferSelection],
isLoading,
isPrivacy: isPrivacyFolder,
isFolderActions,
selectedUploadFile,
canShareOwnerChange,
setIsLoading,
setSharingPanelVisible,
setIsFolderActions,
setSelection,
sharingPanelVisible,
selectUploadedFile,
updateUploadedItem,
@ -679,7 +724,9 @@ const SharingPanel = inject(
setShareFiles,
getFileInfo,
getFolderInfo,
id,
setBufferSelection,
access,
};
}
)(

View File

@ -208,15 +208,32 @@ class SectionHeaderContent extends React.Component {
toastr.success(t("Translations:LinkCopySuccess"));
};
onMoveAction = () => this.props.setMoveToPanelVisible(true);
onCopyAction = () => this.props.setCopyPanelVisible(true);
downloadAction = () =>
onMoveAction = () => {
this.props.setIsFolderActions(true);
this.props.setBufferSelection(this.props.currentFolderId);
return this.props.setMoveToPanelVisible(true);
};
onCopyAction = () => {
this.props.setIsFolderActions(true);
this.props.setBufferSelection(this.props.currentFolderId);
return this.props.setCopyPanelVisible(true);
};
downloadAction = () => {
this.props.setBufferSelection(this.props.currentFolderId);
this.props.setIsFolderActions(true);
this.props
.downloadAction(this.props.t("Translations:ArchivingData"))
.downloadAction(this.props.t("Translations:ArchivingData"), [
this.props.currentFolderId,
])
.catch((err) => toastr.error(err));
};
renameAction = () => console.log("renameAction click");
onOpenSharingPanel = () => this.props.setSharingPanelVisible(true);
onOpenSharingPanel = () => {
this.props.setBufferSelection(this.props.currentFolderId);
this.props.setIsFolderActions(true);
return this.props.setSharingPanelVisible(true);
};
onDeleteAction = () => {
const {
@ -225,10 +242,18 @@ class SectionHeaderContent extends React.Component {
confirmDelete,
setDeleteDialogVisible,
isThirdPartySelection,
currentFolderId,
getFolderInfo,
setBufferSelection,
} = this.props;
this.props.setIsFolderActions(true);
if (confirmDelete || isThirdPartySelection) {
setDeleteDialogVisible(true);
getFolderInfo(currentFolderId).then((data) => {
setBufferSelection(data);
setDeleteDialogVisible(true);
});
} else {
const translations = {
deleteOperation: t("Translations:DeleteOperation"),
@ -236,45 +261,48 @@ class SectionHeaderContent extends React.Component {
deleteSelectedElem: t("Translations:DeleteSelectedElem"),
};
deleteAction(translations);
deleteAction(translations, [currentFolderId], true).catch((err) =>
toastr.error(err)
);
}
};
onEmptyTrashAction = () => this.props.setEmptyTrashDialogVisible(true);
getContextOptionsFolder = () => {
const { t } = this.props;
const { t, personal } = this.props;
return [
{
key: "sharing-settings",
label: t("SharingSettings"),
onClick: this.onOpenSharingPanel,
disabled: true,
disabled: personal ? true : false,
},
{
key: "link-portal-users",
label: t("LinkForPortalUsers"),
onClick: this.createLinkForPortalUsers,
disabled: false,
disabled: personal ? true : false,
},
{ key: "separator-2", isSeparator: true },
{
key: "move-to",
label: t("MoveTo"),
onClick: this.onMoveAction,
disabled: true,
disabled: false,
},
{
key: "copy",
label: t("Translations:Copy"),
onClick: this.onCopyAction,
disabled: true,
disabled: false,
},
{
key: "download",
label: t("Common:Download"),
onClick: this.downloadAction,
disabled: true,
disabled: false,
},
{
key: "rename",
@ -286,7 +314,7 @@ class SectionHeaderContent extends React.Component {
key: "delete",
label: t("Common:Delete"),
onClick: this.onDeleteAction,
disabled: true,
disabled: false,
},
];
};
@ -418,19 +446,18 @@ class SectionHeaderContent extends React.Component {
getData={this.getContextOptionsPlus}
isDisabled={false}
/>
{!personal && (
<ContextMenuButton
className="option-button"
directionX="right"
iconName="images/vertical-dots.react.svg"
size={17}
color="#A3A9AE"
hoverColor="#657077"
isFill
getData={this.getContextOptionsFolder}
isDisabled={false}
/>
)}
<ContextMenuButton
className="option-button"
directionX="right"
iconName="images/vertical-dots.react.svg"
size={17}
color="#A3A9AE"
hoverColor="#657077"
isFill
getData={this.getContextOptionsFolder}
isDisabled={false}
/>
</>
) : (
canCreate && (
@ -469,6 +496,7 @@ export default inject(
}) => {
const {
setSelected,
setSelection,
fileActionStore,
fetchFiles,
filter,
@ -481,6 +509,8 @@ export default inject(
viewAs,
cbMenuItems,
getCheckboxItemLabel,
getFolderInfo,
setBufferSelection,
} = filesStore;
const { setAction } = fileActionStore;
const {
@ -488,6 +518,7 @@ export default inject(
setMoveToPanelVisible,
setCopyPanelVisible,
setDeleteDialogVisible,
setIsFolderActions,
} = dialogsStore;
const { deleteAction, downloadAction, getHeaderMenu } = filesActionsStore;
@ -509,14 +540,18 @@ export default inject(
personal: auth.settingsStore.personal,
viewAs,
cbMenuItems,
getFolderInfo,
setSelected,
setSelection,
setAction,
setIsLoading,
fetchFiles,
setSharingPanelVisible,
setMoveToPanelVisible,
setCopyPanelVisible,
setBufferSelection,
setIsFolderActions,
deleteAction,
setDeleteDialogVisible,
downloadAction,

View File

@ -20,6 +20,7 @@ class DialogsStore {
newFilesPanelVisible = false;
conflictResolveDialogVisible = false;
convertDialogVisible = false;
isFolderActions = false;
removeItem = null;
connectItem = null;
@ -44,6 +45,10 @@ class DialogsStore {
this.sharingPanelVisible = sharingPanelVisible;
};
setIsFolderActions = (isFolderActions) => {
this.isFolderActions = isFolderActions;
};
setChangeOwnerPanelVisible = (ownerPanelVisible) => {
this.ownerPanelVisible = ownerPanelVisible;
};

View File

@ -61,13 +61,24 @@ class FilesActionStore {
clearSecondaryProgressData,
} = this.uploadDataStore.secondaryProgressDataStore;
let updatedFolder = this.selectedFolderStore.id;
if (this.dialogsStore.isFolderActions) {
updatedFolder = this.selectedFolderStore.parentId;
}
const { filter, fetchFiles } = this.filesStore;
fetchFiles(this.selectedFolderStore.id, filter, true, true).finally(() =>
setTimeout(() => clearSecondaryProgressData(), TIMEOUT)
);
fetchFiles(updatedFolder, filter, true, true).finally(() => {
this.dialogsStore.setIsFolderActions(false);
return setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
};
deleteAction = async (translations, newSelection = null) => {
deleteAction = async (
translations,
newSelection = null,
withoutDialog = false
) => {
const { isRecycleBinFolder, isPrivacyFolder } = this.treeFoldersStore;
const selection = newSelection ? newSelection : this.filesStore.selection;
@ -88,8 +99,8 @@ class FilesActionStore {
const deleteAfter = false; //Delete after finished TODO: get from settings
const immediately = isRecycleBinFolder || isPrivacyFolder ? true : false; //Don't move to the Recycle Bin
const folderIds = [];
const fileIds = [];
let folderIds = [];
let fileIds = [];
let i = 0;
while (selection.length !== i) {
@ -101,6 +112,13 @@ class FilesActionStore {
i++;
}
if (this.dialogsStore.isFolderActions && withoutDialog) {
folderIds = [];
fileIds = [];
folderIds.push(selection[0]);
}
if (folderIds.length || fileIds.length) {
this.isMediaOpen();
@ -211,18 +229,18 @@ class FilesActionStore {
}
};
downloadAction = (label) => {
downloadAction = (label, folderId) => {
const { bufferSelection } = this.filesStore;
const selection = this.filesStore.selection.length
? this.filesStore.selection
: [bufferSelection];
const fileIds = [];
const folderIds = [];
let fileIds = [];
let folderIds = [];
const items = [];
if (selection.length === 1 && selection[0].fileExst) {
if (selection.length === 1 && selection[0].fileExst && !folderId) {
window.open(selection[0].viewUrl, "_self");
return Promise.resolve();
}
@ -237,6 +255,14 @@ class FilesActionStore {
}
}
if (this.dialogsStore.isFolderActions) {
fileIds = [];
folderIds = [];
folderIds.push(bufferSelection);
this.dialogsStore.setIsFolderActions(false);
}
return this.downloadFiles(fileIds, folderIds, label);
};

View File

@ -1573,6 +1573,7 @@ class FilesStore {
getFolderInfo = async (id) => {
const folderInfo = await api.files.getFolderInfo(id);
this.setFolder(folderInfo);
return folderInfo;
};
openDocEditor = (id, providerKey = null, tab = null, url = null) => {

View File

@ -904,7 +904,15 @@ class UploadDataStore {
label,
} = this.secondaryProgressDataStore;
getFolder(destFolderId).then((data) => {
let receivedFolder = destFolderId;
let updatedFolder = this.selectedFolderStore.id;
if (this.dialogsStore.isFolderActions) {
receivedFolder = this.selectedFolderStore.parentId;
updatedFolder = destFolderId;
}
getFolder(receivedFolder).then((data) => {
let newTreeFolders = treeFolders;
let path = data.pathParts.slice(0);
let folders = data.folders;
@ -912,11 +920,12 @@ class UploadDataStore {
loopTreeFolders(path, newTreeFolders, folders, foldersCount);
if (!isCopy || destFolderId === this.selectedFolderStore.id) {
fetchFiles(this.selectedFolderStore.id, filter, true, true).finally(
() => {
this.filesStore
.fetchFiles(updatedFolder, this.filesStore.filter, true, true)
.finally(() => {
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
}
);
this.dialogsStore.setIsFolderActions(false);
});
} else {
setSecondaryProgressBarData({
icon: pbData.icon,

@ -1 +1 @@
Subproject commit b1063eae56d183b5c0b6eb887115c378f3941ebe
Subproject commit 8177bad15d567d997a79478a65d32662a6f773b1