Merge pull request #533 from ONLYOFFICE/refactoring/header-context-menu

Web: Files: rewritten logic of the header context-menu
This commit is contained in:
Ilya Oleshko 2024-06-27 16:55:22 +03:00 committed by GitHub
commit 746c7b342f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 217 additions and 667 deletions

View File

@ -24,16 +24,13 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { useRef, useEffect } from "react";
import { useRef } from "react";
import { withTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
import styled from "styled-components";
import { ContextMenu } from "@docspace/shared/components/context-menu";
import { ContextMenuButton } from "@docspace/shared/components/context-menu-button";
const generalKeys = ["select", "show-info"];
const roomKeys = ["separator0", "room-info"];
const StyledItemContextOptions = styled.div`
height: 16px;
margin: ${({ theme }) =>
@ -45,7 +42,6 @@ const RoomsContextBtn = ({
selection,
itemTitleRef,
getItemContextOptionsKeys,
getItemContextOptionsActions,
onSelectItem,
}) => {
@ -62,37 +58,7 @@ const RoomsContextBtn = ({
};
const getData = () => {
let item = { ...selection };
if (!selection.contextOptions) {
const contextOptions = getItemContextOptionsKeys(selection, true);
item = { ...item, contextOptions };
}
const options = getItemContextOptionsActions(item, t, true);
const removeOptionByKey = (key) => {
const idx = options.findIndex((o) => o.key === key);
if (idx !== -1) options.splice(idx, 1);
};
generalKeys.forEach((key) => removeOptionByKey(key));
if (selection.isRoom) roomKeys.forEach((key) => removeOptionByKey(key));
options.forEach((item, index) => {
const isSeparator = item.key.includes("separator");
const isFirst = index === options.length - 1;
const isLast = index === 0;
const nextItem = isLast ? null : options[index + 1];
const nextIsSeparator = nextItem && nextItem.key.includes("separator");
if (
(isFirst && isSeparator) ||
(isLast && isSeparator) ||
(isSeparator && nextIsSeparator)
)
options.splice(index, 1);
});
return options;
return getItemContextOptionsActions(selection, t, true);
};
return (
@ -120,8 +86,7 @@ const RoomsContextBtn = ({
);
};
export default inject(({ filesStore, contextOptionsStore }) => ({
getItemContextOptionsKeys: filesStore.getFilesContextOptions,
export default inject(({ contextOptionsStore }) => ({
getItemContextOptionsActions: contextOptionsStore.getFilesContextOptions,
}))(
withTranslation([

View File

@ -24,63 +24,32 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import ClearTrashReactSvgUrl from "PUBLIC_DIR/images/clear.trash.react.svg?url";
import ReconnectSvgUrl from "PUBLIC_DIR/images/reconnect.svg?url";
import SettingsReactSvgUrl from "PUBLIC_DIR/images/catalog.settings.react.svg?url";
import DownloadReactSvgUrl from "PUBLIC_DIR/images/download.react.svg?url";
import MoveReactSvgUrl from "PUBLIC_DIR/images/move.react.svg?url";
import RenameReactSvgUrl from "PUBLIC_DIR/images/rename.react.svg?url";
import ShareReactSvgUrl from "PUBLIC_DIR/images/share.react.svg?url";
import InvitationLinkReactSvgUrl from "PUBLIC_DIR/images/invitation.link.react.svg?url";
import InfoOutlineReactSvgUrl from "PUBLIC_DIR/images/info.outline.react.svg?url";
import PersonReactSvgUrl from "PUBLIC_DIR/images/person.react.svg?url";
import RoomArchiveSvgUrl from "PUBLIC_DIR/images/room.archive.svg?url";
import CopyReactSvgUrl from "PUBLIC_DIR/images/copy.react.svg?url";
import CatalogTrashReactSvgUrl from "PUBLIC_DIR/images/catalog.trash.react.svg?url";
import PublicRoomIconUrl from "PUBLIC_DIR/images/public-room.react.svg?url";
import LeaveRoomSvgUrl from "PUBLIC_DIR/images/logout.react.svg?url";
import CatalogRoomsReactSvgUrl from "PUBLIC_DIR/images/catalog.rooms.react.svg?url";
import TabletLinkReactSvgUrl from "PUBLIC_DIR/images/tablet-link.react.svg?url";
import CodeReactSvgUrl from "PUBLIC_DIR/images/code.react.svg?url";
import React from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import styled, { css } from "styled-components";
import copy from "copy-to-clipboard";
import { useNavigate, useLocation, useParams } from "react-router-dom";
import { useLocation, useParams } from "react-router-dom";
import { SectionHeaderSkeleton } from "@docspace/shared/skeletons/sections";
import Navigation from "@docspace/shared/components/navigation";
import FilesFilter from "@docspace/shared/api/files/filter";
import { DropDownItem } from "@docspace/shared/components/drop-down-item";
import { tablet, mobile, Consumer, getLogoUrl } from "@docspace/shared/utils";
import { toastr } from "@docspace/shared/components/toast";
import { TableGroupMenu } from "@docspace/shared/components/table";
import {
Events,
RoomsType,
DeviceType,
FolderType,
ShareAccessRights,
FilesSelectorFilterTypes,
WhiteLabelLogoType,
} from "@docspace/shared/enums";
import { copyShareLink } from "@docspace/shared/utils/copy";
import { CategoryType } from "SRC_DIR/helpers/constants";
import {
getCategoryTypeByFolderType,
getCategoryUrl,
} from "SRC_DIR/helpers/utils";
import TariffBar from "SRC_DIR/components/TariffBar";
import { PRODUCT_NAME } from "@docspace/shared/constants";
const StyledContainer = styled.div`
width: 100%;
@ -180,16 +149,12 @@ const StyledContainer = styled.div`
const SectionHeaderContent = (props) => {
const {
currentFolderId,
currentGroup,
insideGroupTempTitle,
getGroupContextOptions,
t,
isRoomsFolder,
security,
setIsFolderActions,
setBufferSelection,
setMoveToPanelVisible,
tReady,
isInfoPanelVisible,
isRootFolder,
@ -213,26 +178,7 @@ const SectionHeaderContent = (props) => {
isGroupMenuBlocked,
onClickBack,
activeFiles,
activeFolders,
selectedFolder,
setCopyPanelVisible,
setSharingPanelVisible,
deleteAction,
confirmDelete,
setDeleteDialogVisible,
isThirdPartySelection,
getFolderInfo,
setEmptyTrashDialogVisible,
setRestoreAllPanelVisible,
isGracePeriod,
setInviteUsersWarningDialogVisible,
setRestoreAllArchive,
setRestoreRoomDialogVisible,
onCopyLink,
setShareFolderDialogVisible,
setSelected,
cbMenuItems,
@ -257,43 +203,29 @@ const SectionHeaderContent = (props) => {
setAccountsSelected,
setGroupsSelected,
isRoomAdmin,
isCollaborator,
isEmptyPage,
isLoading,
emptyTrashInProgress,
categoryType,
isPublicRoom,
isFormRoomType,
theme,
downloadAction,
isPublicRoomType,
isCustomRoomType,
primaryLink,
getPrimaryLink,
setExternalLink,
moveToPublicRoom,
currentDeviceType,
isFrame,
showTitle,
hideInfoPanel,
onClickArchive,
setLeaveRoomDialogVisible,
inRoom,
onClickCreateRoom,
onCreateAndCopySharedLink,
showNavigationButton,
setSelectFileFormRoomDialogVisible,
deleteRooms,
setSelection,
startUpload,
getFolderModel,
onCreateRoom,
onOpenEmbeddingSettings,
onEmptyTrashAction,
getHeaderOptions,
setBufferSelection,
} = props;
const navigate = useNavigate();
const location = useLocation();
const { groupId } = useParams();
@ -314,421 +246,20 @@ const SectionHeaderContent = (props) => {
const onInputClick = React.useCallback((e) => (e.target.value = null), []);
const createLinkForPortalUsers = () => {
copy(
`${window.location.origin}/filter?folder=${currentFolderId}`, //TODO: Change url by category
);
toastr.success(t("Translations:LinkCopySuccess"));
};
const onMoveAction = () => {
setIsFolderActions(true);
setBufferSelection(selectedFolder);
return setMoveToPanelVisible(true);
};
const onCopyAction = () => {
setIsFolderActions(true);
setBufferSelection(selectedFolder);
return setCopyPanelVisible(true);
};
const onDownloadAction = () => {
downloadAction(t("Translations:ArchivingData"), selectedFolder, [
currentFolderId,
]).catch((err) => toastr.error(err));
};
const onClickArchiveAction = (e) => {
setBufferSelection(selectedFolder);
onClickArchive(e);
};
const onLeaveRoom = () => {
setLeaveRoomDialogVisible(true);
};
const renameAction = () => {
const event = new Event(Events.RENAME);
event.item = selectedFolder;
window.dispatchEvent(event);
};
const onOpenSharingPanel = () => {
setBufferSelection(selectedFolder);
setIsFolderActions(true);
return setSharingPanelVisible(true);
};
const onClickShare = () => {
setShareFolderDialogVisible(true);
};
const onDeleteAction = () => {
setIsFolderActions(true);
if (confirmDelete || isThirdPartySelection) {
getFolderInfo(currentFolderId).then((data) => {
setBufferSelection(data);
setDeleteDialogVisible(true);
});
} else {
const translations = {
deleteOperation: t("Translations:DeleteOperation"),
deleteFromTrash: t("Translations:DeleteFromTrash"),
deleteSelectedElem: t("Translations:DeleteSelectedElem"),
FolderRemoved: t("Files:FolderRemoved"),
};
deleteAction(translations, [selectedFolder], true).catch((err) =>
toastr.error(err),
);
}
};
const onEmptyTrashAction = () => {
const isExistActiveItems = [...activeFiles, ...activeFolders].length > 0;
if (isExistActiveItems || emptyTrashInProgress) return;
setEmptyTrashDialogVisible(true);
};
const onRestoreAllAction = () => {
setRestoreAllPanelVisible;
const isExistActiveItems = [...activeFiles, ...activeFolders].length > 0;
if (isExistActiveItems) return;
setRestoreAllPanelVisible(true);
};
const onRestoreAllArchiveAction = () => {
const isExistActiveItems = [...activeFiles, ...activeFolders].length > 0;
if (isExistActiveItems) return;
if (isGracePeriod) {
setInviteUsersWarningDialogVisible(true);
return;
}
setRestoreAllArchive(true);
setRestoreRoomDialogVisible(true);
};
const onShowInfo = () => {
const { setIsInfoPanelVisible } = props;
setIsInfoPanelVisible(true);
};
const onToggleInfoPanel = () => {
setIsInfoPanelVisible(!isInfoPanelVisible);
};
const onCopyLinkAction = () => {
onCopyLink && onCopyLink({ ...selectedFolder, isFolder: true }, t);
};
const onDownloadAll = () => {
onDownloadAction();
};
const onShareRoom = () => {
copy(window.location.href);
toastr.success(t("Translations:LinkCopySuccess"));
};
const onDeleteRoomInArchive = () => {
setSelection([selectedFolder]);
deleteRooms(t);
};
const getContextOptionsFolder = () => {
const {
t,
isRoom,
isRecycleBinFolder,
isArchiveFolder,
isPersonalRoom,
selectedFolder,
onClickEditRoom,
onClickInviteUsers,
onShowInfoPanel,
onClickReconnectStorage,
canRestoreAll,
canDeleteAll,
security,
haveLinksRight,
isPublicRoom,
isFrame,
} = props;
const isArchive = selectedFolder.rootFolderType === FolderType.Archive;
if (isPublicRoom) {
return [
{
key: "public-room_share",
label: t("Files:CopyLink"),
icon: TabletLinkReactSvgUrl,
onClick: onShareRoom,
disabled: isFrame,
},
{
key: "public-room_edit",
label: t("Common:Download"),
icon: DownloadReactSvgUrl,
onClick: onDownloadAll,
disabled: !security?.Download,
},
];
}
const isDisabled = isRecycleBinFolder || isRoom;
if (isArchiveFolder) {
return [
{
id: "header_option_empty-archive",
key: "empty-archive",
label: t("ArchiveAction"),
onClick: onEmptyTrashAction,
disabled: !canDeleteAll,
icon: ClearTrashReactSvgUrl,
},
{
id: "header_option_restore-all",
key: "restore-all",
label: t("RestoreAll"),
onClick: onRestoreAllArchiveAction,
disabled: !canRestoreAll,
icon: MoveReactSvgUrl,
},
];
}
if (isInsideGroup) {
return getGroupContextOptions(t, currentGroup, false, true);
}
return [
{
id: "header_option_sharing-settings",
key: "sharing-settings",
label: t("Common:Share"),
onClick: onClickShare,
disabled: !selectedFolder.security?.CreateRoomFrom,
icon: ShareReactSvgUrl,
},
{
id: "header_option_link-portal-users",
key: "link-portal-users",
label: t("LinkForPortalUsers", { productName: PRODUCT_NAME }),
onClick: createLinkForPortalUsers,
disabled: true,
icon: InvitationLinkReactSvgUrl,
},
{
id: "header_option_link-for-room-members",
key: "link-for-room-members",
label: t("Files:CopyLink"),
onClick: onCopyLinkAction,
disabled:
isRecycleBinFolder ||
isPersonalRoom ||
!security?.CopyLink ||
((isPublicRoomType || isCustomRoomType || isFormRoomType) &&
haveLinksRight &&
!isArchive),
icon: InvitationLinkReactSvgUrl,
},
{
id: "header_option_empty-trash",
key: "empty-trash",
label: t("Files:EmptyRecycleBin"),
onClick: onEmptyTrashAction,
disabled: !isRecycleBinFolder,
icon: ClearTrashReactSvgUrl,
},
{
id: "header_option_restore-all",
key: "restore-all",
label: t("RestoreAll"),
onClick: onRestoreAllAction,
disabled: !isRecycleBinFolder,
icon: MoveReactSvgUrl,
},
{
id: "header_option_show-info",
key: "show-info",
label: t("Common:Info"),
onClick: onShowInfo,
disabled: isDisabled,
icon: InfoOutlineReactSvgUrl,
},
{
id: "header_option_reconnect-storage",
key: "reconnect-storage",
label: t("Common:ReconnectStorage"),
icon: ReconnectSvgUrl,
onClick: () => onClickReconnectStorage(selectedFolder, t),
disabled: !security?.EditRoom || !security?.Reconnect,
},
{
id: "header_option_edit-room",
key: "edit-room",
label: t("EditRoom"),
icon: SettingsReactSvgUrl,
onClick: () => onClickEditRoom(selectedFolder),
disabled: !isRoom || !security?.EditRoom,
},
{
id: "header_option_invite-users-to-room",
key: "invite-users-to-room",
label: t("Common:InviteUsers"),
icon: PersonReactSvgUrl,
onClick: () =>
onClickInviteUsers(selectedFolder.id, selectedFolder.roomType),
disabled: !isRoom || !security?.EditAccess,
},
{
id: "header_option_copy-external-link",
key: "copy-external-link",
label: t("Files:CopySharedLink"),
icon: TabletLinkReactSvgUrl,
onClick: async () => {
if (primaryLink) {
copyShareLink(primaryLink.sharedTo.shareLink);
toastr.success(t("Translations:LinkCopySuccess"));
} else {
const link = await getPrimaryLink(currentFolderId);
if (link) {
copyShareLink(link.sharedTo.shareLink);
toastr.success(t("Files:LinkSuccessfullyCreatedAndCopied"));
setExternalLink(link);
}
}
},
disabled:
(!isPublicRoomType && !isCustomRoomType && !isFormRoomType) ||
!haveLinksRight ||
isArchive,
},
{
id: "header_option_room-embed",
key: "room-embed",
label: t("Files:Embed"),
icon: CodeReactSvgUrl,
onClick: () => onOpenEmbeddingSettings(selectedFolder),
disabled: !security?.Embed,
},
{
id: "header_option_room-info",
key: "room-info",
label: t("Common:Info"),
icon: InfoOutlineReactSvgUrl,
onClick: onToggleInfoPanel,
disabled: !isRoom,
},
{
id: "header_option_separator-2",
key: "separator-2",
isSeparator: true,
disabled: isRecycleBinFolder,
},
{
id: "header_option_download",
key: "download",
label: t("Common:Download"),
onClick: onDownloadAction,
disabled: !security?.Download,
icon: DownloadReactSvgUrl,
},
{
id: "header_option_archive-room",
key: "archive-room",
label: t("MoveToArchive"),
icon: RoomArchiveSvgUrl,
onClick: onClickArchiveAction,
disabled: !isRoom || !security?.Move || isArchive,
"data-action": "archive",
action: "archive",
},
{
id: "option_create-room",
label: t("Files:CreateRoom"),
key: "create-room",
icon: CatalogRoomsReactSvgUrl,
onClick: () => {
onClickCreateRoom({ title: selectedFolder.title, isFolder: true });
},
disabled: !selectedFolder.security?.CreateRoomFrom,
},
{
id: "option_leave-room",
key: "leave-room",
label: t("LeaveTheRoom"),
icon: LeaveRoomSvgUrl,
onClick: onLeaveRoom,
disabled: isArchive || !inRoom || isPublicRoom,
},
{
id: "header_option_unarchive-room",
key: "unarchive-room",
label: t("Common:Restore"),
onClick: onClickArchiveAction,
disabled: !isArchive || !isRoom,
icon: MoveReactSvgUrl,
},
{
id: "header_option_move-to",
key: "move-to",
label: t("Common:MoveTo"),
onClick: onMoveAction,
disabled: isDisabled || !security?.MoveTo,
icon: MoveReactSvgUrl,
},
{
id: "header_option_copy",
key: "copy",
label: t("Common:Copy"),
onClick: onCopyAction,
disabled:
isDisabled || (isArchive ? !security?.Copy : !security?.CopyTo),
return getHeaderOptions(t, selectedFolder);
};
icon: CopyReactSvgUrl,
},
{
id: "header_option_rename",
key: "rename",
label: t("Common:Rename"),
onClick: renameAction,
disabled: isDisabled || !security?.Rename,
icon: RenameReactSvgUrl,
},
{
id: "header_option_separator-3",
key: "separator-3",
isSeparator: true,
disabled: isDisabled || !security?.Delete,
},
{
id: "header_option_delete",
key: "delete",
label: t("Common:Delete"),
onClick: isArchive ? onDeleteRoomInArchive : onDeleteAction,
disabled: isArchive ? !isRoom : isDisabled || !security?.Delete,
icon: CatalogTrashReactSvgUrl,
},
];
const onContextOptionsClick = () => {
setBufferSelection(selectedFolder);
};
const onSelect = (e) => {
@ -1014,6 +545,7 @@ const SectionHeaderContent = (props) => {
onNavigationButtonClick={onNavigationButtonClick}
tariffBar={<TariffBar />}
showNavigationButton={!!showNavigationButton}
onContextOptionsClick={onContextOptionsClick}
/>
</div>
)}
@ -1050,23 +582,19 @@ export default inject(
({
filesStore,
peopleStore,
dialogsStore,
selectedFolderStore,
treeFoldersStore,
filesActionsStore,
filesSettingsStore,
clientLoadingStore,
publicRoomStore,
contextOptionsStore,
infoPanelStore,
userStore,
currentTariffStatusStore,
settingsStore,
uploadDataStore,
}) => {
const { startUpload } = uploadDataStore;
const isRoomAdmin = userStore.user?.isRoomAdmin;
const isCollaborator = userStore.user?.isCollaborator;
const {
setSelected,
@ -1074,16 +602,10 @@ export default inject(
isHeaderVisible,
isHeaderIndeterminate,
isHeaderChecked,
isThirdPartySelection,
cbMenuItems,
getCheckboxItemLabel,
getCheckboxItemId,
isEmptyFilesList,
getFolderInfo,
setBufferSelection,
activeFiles,
activeFolders,
roomsForRestore,
roomsForDelete,
@ -1091,8 +613,7 @@ export default inject(
isEmptyPage,
categoryType,
getPrimaryLink,
setSelection,
setBufferSelection,
} = filesStore;
const {
@ -1106,58 +627,27 @@ export default inject(
setIsSectionFilterLoading(param);
};
const {
setSharingPanelVisible,
setMoveToPanelVisible,
setCopyPanelVisible,
setDeleteDialogVisible,
setEmptyTrashDialogVisible,
setIsFolderActions,
setRestoreAllPanelVisible,
setRestoreRoomDialogVisible,
setRestoreAllArchive,
setInviteUsersWarningDialogVisible,
setLeaveRoomDialogVisible,
setSelectFileFormRoomDialogVisible,
setShareFolderDialogVisible,
} = dialogsStore;
const { isRecycleBinFolder, isRoomsFolder, isArchiveFolder } =
treeFoldersStore;
const {
isRecycleBinFolder,
isRoomsFolder,
isArchiveFolder,
isPersonalRoom,
isArchiveFolderRoot,
} = treeFoldersStore;
const {
deleteAction,
downloadAction,
getHeaderMenu,
isGroupMenuBlocked,
moveToRoomsPage,
onClickBack,
emptyTrashInProgress,
moveToPublicRoom,
onClickCreateRoom,
deleteRooms,
} = filesActionsStore;
const { setIsVisible, isVisible } = infoPanelStore;
const {
title,
id,
roomType,
pathParts,
navigationPath,
security,
inRoom,
access,
canCopyPublicLink,
rootFolderType,
parentRoomType,
isFolder,
shared,
} = selectedFolderStore;
@ -1170,7 +660,6 @@ export default inject(
} = peopleStore.groupsStore;
const { theme, frameConfig, isFrame, currentDeviceType } = settingsStore;
const { isGracePeriod } = currentTariffStatusStore;
const isRoom = !!roomType;
const isPublicRoomType = roomType === RoomsType.PublicRoom;
@ -1178,16 +667,11 @@ export default inject(
const isFormRoomType = roomType === RoomsType.FormRoom;
const {
onClickEditRoom,
onClickInviteUsers,
onShowInfoPanel,
onClickArchive,
onClickReconnectStorage,
onCopyLink,
onCreateAndCopySharedLink,
getFolderModel,
onCreateRoom,
onOpenEmbeddingSettings,
getHeaderOptions,
onEmptyTrashAction,
} = contextOptionsStore;
const canRestoreAll = isArchiveFolder && roomsForRestore.length > 0;
@ -1215,7 +699,7 @@ export default inject(
} = headerMenuStore;
const { setSelected: setAccountsSelected } = selectionStore;
const { isPublicRoom, primaryLink, setExternalLink } = publicRoomStore;
const { isPublicRoom } = publicRoomStore;
let folderPath = navigationPath;
@ -1228,10 +712,6 @@ export default inject(
? pathParts?.length === 1 || pathParts?.length === 2
: pathParts?.length === 1;
const haveLinksRight =
access === ShareAccessRights.RoomManager ||
access === ShareAccessRights.None;
const isArchive = rootFolderType === FolderType.Archive;
const sharedItem = navigationPath.find((r) => r.shared);
@ -1247,17 +727,13 @@ export default inject(
(sharedItem && sharedItem.canCopyPublicLink);
return {
isGracePeriod,
setInviteUsersWarningDialogVisible,
showText: settingsStore.showText,
isDesktop: settingsStore.isDesktopClient,
showHeaderLoader,
isLoading,
isRootFolder: isPublicRoom && !folderPath?.length ? true : isRoot,
isPersonalRoom,
title,
isRoom,
currentFolderId: id,
navigationPath: folderPath,
@ -1266,70 +742,36 @@ export default inject(
isHeaderVisible,
isHeaderIndeterminate,
isHeaderChecked,
isThirdPartySelection,
isTabletView: settingsStore.isTabletView,
confirmDelete: filesSettingsStore.confirmDelete,
cbMenuItems,
setSelectedNode: treeFoldersStore.setSelectedNode,
getFolderInfo,
setSelected,
security,
canCopyPublicLink,
setSharingPanelVisible,
setMoveToPanelVisible,
setCopyPanelVisible,
setBufferSelection,
setIsFolderActions,
deleteAction,
setDeleteDialogVisible,
downloadAction,
getHeaderMenu,
getCheckboxItemLabel,
getCheckboxItemId,
isRecycleBinFolder,
setEmptyTrashDialogVisible,
isEmptyFilesList,
isEmptyArchive,
isArchiveFolder,
setIsLoading,
activeFiles,
activeFolders,
isRoomsFolder,
setRestoreAllPanelVisible,
setRestoreRoomDialogVisible,
setRestoreAllArchive,
selectedFolder,
onClickEditRoom,
onClickCreateRoom,
onClickInviteUsers,
onShowInfoPanel,
onClickArchive,
onCopyLink,
isEmptyArchive,
canRestoreAll,
canDeleteAll,
isGroupMenuBlocked,
moveToRoomsPage,
onClickBack,
isPublicRoomType,
isCustomRoomType,
isFormRoomType,
isPublicRoom,
primaryLink,
getPrimaryLink,
setExternalLink,
moveToPublicRoom,
@ -1346,32 +788,24 @@ export default inject(
getAccountsCheckboxItemLabel,
setAccountsSelected,
isRoomAdmin,
isCollaborator,
isEmptyPage,
emptyTrashInProgress,
categoryType,
theme,
isFrame,
showTitle: frameConfig?.showTitle,
hideInfoPanel: isFrame && !frameConfig?.infoPanelVisible,
currentDeviceType,
setLeaveRoomDialogVisible,
inRoom,
insideGroupTempTitle,
currentGroup,
getGroupContextOptions,
onCreateAndCopySharedLink,
showNavigationButton,
haveLinksRight,
setSelectFileFormRoomDialogVisible,
deleteRooms,
setSelection,
setShareFolderDialogVisible,
startUpload,
onClickReconnectStorage,
getFolderModel,
onCreateRoom,
onOpenEmbeddingSettings,
onEmptyTrashAction,
getHeaderOptions,
setBufferSelection,
};
},
)(

View File

@ -56,7 +56,6 @@ import UnmuteReactSvgUrl from "PUBLIC_DIR/images/unmute.react.svg?url";
import MuteReactSvgUrl from "PUBLIC_DIR/images/icons/16/mute.react.svg?url";
import ShareReactSvgUrl from "PUBLIC_DIR/images/share.react.svg?url";
import InvitationLinkReactSvgUrl from "PUBLIC_DIR/images/invitation.link.react.svg?url";
import CopyToReactSvgUrl from "PUBLIC_DIR/images/copyTo.react.svg?url";
import TabletLinkReactSvgUrl from "PUBLIC_DIR/images/tablet-link.react.svg?url";
import MailReactSvgUrl from "PUBLIC_DIR/images/mail.react.svg?url";
import RoomArchiveSvgUrl from "PUBLIC_DIR/images/room.archive.svg?url";
@ -70,7 +69,6 @@ import PersonDefaultReactSvgUrl from "PUBLIC_DIR/images/person.default.react.svg
import InviteAgainReactSvgUrl from "PUBLIC_DIR/images/invite.again.react.svg?url";
import PersonUserReactSvgUrl from "PUBLIC_DIR/images/person.user.react.svg?url";
import GroupReactSvgUrl from "PUBLIC_DIR/images/group.react.svg?url";
import FolderLockedReactSvgUrl from "PUBLIC_DIR/images/folder.locked.react.svg?url";
import ActionsDocumentsReactSvgUrl from "PUBLIC_DIR/images/actions.documents.react.svg?url";
import SpreadsheetReactSvgUrl from "PUBLIC_DIR/images/spreadsheet.react.svg?url";
import ActionsPresentationReactSvgUrl from "PUBLIC_DIR/images/actions.presentation.react.svg?url";
@ -81,17 +79,18 @@ import CatalogFolderReactSvgUrl from "PUBLIC_DIR/images/catalog.folder.react.svg
import ActionsUploadReactSvgUrl from "PUBLIC_DIR/images/actions.upload.react.svg?url";
import PluginMoreReactSvgUrl from "PUBLIC_DIR/images/plugin.more.react.svg?url";
import CodeReactSvgUrl from "PUBLIC_DIR/images/code.react.svg?url";
import ClearTrashReactSvgUrl from "PUBLIC_DIR/images/clear.trash.react.svg?url";
import { getCategoryUrl } from "@docspace/client/src/helpers/utils";
import { makeAutoObservable } from "mobx";
import copy from "copy-to-clipboard";
import saveAs from "file-saver";
import { isMobile, isIOS, isTablet } from "react-device-detect";
import { isMobile, isTablet } from "react-device-detect";
import config from "PACKAGE_FILE";
import { toastr } from "@docspace/shared/components/toast";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import { isDesktop } from "@docspace/shared/utils";
import { isDesktop, trimSeparator } from "@docspace/shared/utils";
import { getDefaultAccessUser } from "@docspace/shared/utils/getDefaultAccessUser";
import { copyShareLink } from "@docspace/shared/utils/copy";
@ -296,24 +295,37 @@ class ContextOptionsStore {
this.dialogsStore.setChangeOwnerPanelVisible(true);
};
onMoveAction = () => {
onMoveAction = (item) => {
const { setIsMobileHidden } = this.infoPanelStore;
const { id, isFolder } = this.selectedFolderStore;
setIsMobileHidden(true);
const isFolderActions = id === item?.id && isFolder === item?.isFolder;
if (isFolderActions) {
this.dialogsStore.setIsFolderActions(true);
}
this.dialogsStore.setMoveToPanelVisible(true);
};
onRestoreAction = () => {
const { setIsMobileHidden } = this.infoPanelStore;
setIsMobileHidden(true);
console.log("Click");
this.dialogsStore.setRestorePanelVisible(true);
};
onCopyAction = () => {
onCopyAction = (item) => {
const { setIsMobileHidden } = this.infoPanelStore;
const { id, isFolder } = this.selectedFolderStore;
setIsMobileHidden(true);
const isFolderActions = id === item?.id && isFolder === item?.isFolder;
if (isFolderActions) {
this.dialogsStore.setIsFolderActions(true);
}
this.dialogsStore.setCopyPanelVisible(true);
};
@ -505,12 +517,12 @@ class ContextOptionsStore {
this.filesStore.openDocEditor(id, preview);
};
isPwa = () => {
return ["fullscreen", "standalone", "minimal-ui"].some(
(displayMode) =>
window.matchMedia("(display-mode: " + displayMode + ")").matches,
);
};
// isPwa = () => {
// return ["fullscreen", "standalone", "minimal-ui"].some(
// (displayMode) =>
// window.matchMedia("(display-mode: " + displayMode + ")").matches,
// );
// };
onClickDownload = (item, t) => {
const { fileExst, contentLength, viewUrl } = item;
@ -519,23 +531,6 @@ class ContextOptionsStore {
const { openUrl } = this.settingsStore;
const { downloadAction } = this.filesActionsStore;
if (isIOS && this.isPwa()) {
const xhr = new XMLHttpRequest();
xhr.open("GET", viewUrl);
xhr.responseType = "blob";
xhr.onload = () => {
saveAs(xhr.response, item.title);
};
xhr.onerror = () => {
console.error("download failed", viewUrl);
};
xhr.send();
return;
}
isFile
? openUrl(viewUrl, UrlActionType.Download)
: downloadAction(t("Translations:ArchivingData"), item).catch((err) =>
@ -1074,7 +1069,142 @@ class ContextOptionsStore {
return { pinOptions, muteOptions };
};
getFilesContextOptions = (item, t, isInfoPanel) => {
onEmptyTrashAction = () => {
const { activeFiles, activeFolders } = this.filesStore;
const isExistActiveItems = [...activeFiles, ...activeFolders].length > 0;
if (isExistActiveItems || this.filesActionsStore.emptyTrashInProgress)
return;
this.dialogsStore.setEmptyTrashDialogVisible(true);
};
onRestoreAllAction = () => {
const { activeFiles, activeFolders } = this.filesStore;
const isExistActiveItems = [...activeFiles, ...activeFolders].length > 0;
if (isExistActiveItems) return;
this.dialogsStore.setRestoreAllPanelVisible(true);
};
onRestoreAllArchiveAction = () => {
const { activeFiles, activeFolders } = this.filesStore;
const {
setInviteUsersWarningDialogVisible,
setRestoreAllArchive,
setRestoreRoomDialogVisible,
} = this.dialogsStore;
const isExistActiveItems = [...activeFiles, ...activeFolders].length > 0;
if (isExistActiveItems) return;
if (this.currentTariffStatusStore.isGracePeriod) {
setInviteUsersWarningDialogVisible(true);
return;
}
setRestoreAllArchive(true);
setRestoreRoomDialogVisible(true);
};
getHeaderOptions = (t, item) => {
const { isRecycleBinFolder, isArchiveFolder } = this.treeFoldersStore;
const { roomsForDelete, roomsForRestore } = this.filesStore;
const canRestoreAll = roomsForRestore.length > 0;
const canDeleteAll = roomsForDelete.length > 0;
if (this.publicRoomStore.isPublicRoom) {
return [
{
key: "public-room_share",
label: t("Files:CopyLink"),
icon: TabletLinkReactSvgUrl,
onClick: () => {
copy(window.location.href);
toastr.success(t("Translations:LinkCopySuccess"));
},
disabled: this.settingsStore.isFrame,
},
{
key: "public-room_edit",
label: t("Common:Download"),
icon: DownloadReactSvgUrl,
onClick: () => {
onClickDownload(item, t);
},
disabled: !item.security?.Download,
},
];
}
if (isRecycleBinFolder) {
return [
{
id: "header_option_empty-trash",
key: "empty-trash",
label: t("Files:EmptyRecycleBin"),
onClick: this.onEmptyTrashAction,
icon: ClearTrashReactSvgUrl,
disabled: false,
},
{
id: "header_option_restore-all",
key: "restore-all",
label: t("RestoreAll"),
onClick: this.onRestoreAllAction,
icon: MoveReactSvgUrl,
disabled: false,
},
];
}
if (isArchiveFolder) {
return [
{
id: "header_option_empty-archive",
key: "empty-archive",
label: t("ArchiveAction"),
onClick: this.onEmptyTrashAction,
disabled: !canDeleteAll,
icon: ClearTrashReactSvgUrl,
},
{
id: "header_option_restore-all",
key: "restore-all",
label: t("RestoreAll"),
onClick: this.onRestoreAllArchiveAction,
disabled: !canRestoreAll,
icon: MoveReactSvgUrl,
},
];
}
return this.getFilesContextOptions(item, t, false, true);
};
getFilesContextOptions = (item, t, isInfoPanel, isHeader) => {
const optionsToRemove = isInfoPanel
? ["select", "room-info", "show-info"]
: isHeader
? ["select"]
: [];
if (!item.contextOptions) {
const contextOptions = this.filesStore.getFilesContextOptions(
item,
optionsToRemove,
);
item = { ...item, contextOptions };
} else {
item.contextOptions = this.filesStore.removeOptions(
item.contextOptions,
optionsToRemove,
);
}
const { contextOptions, isEditing } = item;
const isRootThirdPartyFolder =
@ -1199,7 +1329,7 @@ class ContextOptionsStore {
icon: MoveReactSvgUrl,
onClick: isEditing
? () => this.onShowEditingToast(t)
: this.onMoveAction,
: () => this.onMoveAction(item),
disabled: false,
},
{
@ -1207,7 +1337,7 @@ class ContextOptionsStore {
key: "copy-to",
label: t("Common:Copy"),
icon: CopyReactSvgUrl,
onClick: this.onCopyAction,
onClick: () => this.onCopyAction(item),
disabled: false,
},
{
@ -1229,7 +1359,7 @@ class ContextOptionsStore {
icon: MoveReactSvgUrl,
onClick: isEditing
? () => this.onShowEditingToast(t)
: this.onMoveAction,
: () => this.onMoveAction(item),
disabled: false,
},
{
@ -1237,7 +1367,7 @@ class ContextOptionsStore {
key: "copy-to",
label: t("Common:Copy"),
icon: CopyReactSvgUrl,
onClick: this.onCopyAction,
onClick: () => this.onCopyAction(item),
disabled: false,
},
{
@ -1371,7 +1501,7 @@ class ContextOptionsStore {
label: t("Common:ReconnectStorage"),
icon: ReconnectSvgUrl,
onClick: () => this.onClickReconnectStorage(item, t),
disabled: !item.security?.Reconnect,
disabled: !item.security?.Reconnect || !item.security?.EditRoom,
},
{
id: "option_edit-room",
@ -1427,7 +1557,7 @@ class ContextOptionsStore {
disabled:
(isPublicRoomType && item.canCopyPublicLink && !isArchive) ||
this.publicRoomStore.isPublicRoom ||
!item.security.CopyLink,
!item.security?.CopyLink,
},
{
id: "option_copy-external-link",
@ -1693,7 +1823,7 @@ class ContextOptionsStore {
!(isCollaborator && option.key === "create-room"),
);
return newOptions;
return trimSeparator(newOptions);
};
getGroupContextOptions = (t) => {

View File

@ -660,9 +660,12 @@ class FilesActionStore {
}
};
downloadAction = (label, item, folderId) => {
downloadAction = (label, item) => {
const { bufferSelection } = this.filesStore;
const { openUrl } = this.settingsStore;
const { id, isFolder } = this.selectedFolderStore;
const downloadAsArchive = id === item?.id && isFolder === item?.isFolder;
const selection = item
? [item]
@ -678,7 +681,7 @@ class FilesActionStore {
let folderIds = [];
const items = [];
if (selection.length === 1 && selection[0].fileExst && !folderId) {
if (selection.length === 1 && selection[0].fileExst && !downloadAsArchive) {
openUrl(selection[0].viewUrl, UrlActionType.Download);
return Promise.resolve();
}

View File

@ -1987,7 +1987,7 @@ class FilesStore {
return newOptions.filter((o) => o);
};
getFilesContextOptions = (item, fromInfoPanel) => {
getFilesContextOptions = (item, optionsToRemove = []) => {
const isFile = !!item.fileExst || item.contentLength;
const isRoom = !!item.roomType;
const isFavorite =
@ -2100,6 +2100,10 @@ class FilesStore {
"copy-general-link",
];
if (optionsToRemove.length) {
fileOptions = this.removeOptions(fileOptions, optionsToRemove);
}
if (!canDownload) {
fileOptions = this.removeOptions(fileOptions, ["download"]);
}
@ -2388,6 +2392,10 @@ class FilesStore {
"delete",
];
if (optionsToRemove.length) {
roomOptions = this.removeOptions(roomOptions, optionsToRemove);
}
if (!canEditRoom) {
roomOptions = this.removeOptions(roomOptions, [
"edit-room",
@ -2470,10 +2478,6 @@ class FilesStore {
}
}
// if (fromInfoPanel) {
// roomOptions = this.removeOptions(roomOptions, ["external-link"]);
// }
roomOptions = this.removeSeparator(roomOptions);
return roomOptions;
@ -2503,6 +2507,10 @@ class FilesStore {
"delete",
];
if (optionsToRemove.length) {
folderOptions = this.removeOptions(folderOptions, optionsToRemove);
}
if (!canDownload) {
folderOptions = this.removeOptions(folderOptions, ["download"]);
}

View File

@ -82,6 +82,7 @@ const Navigation = ({
onNavigationButtonClick,
tariffBar,
showNavigationButton,
onContextOptionsClick,
...rest
}: INavigationProps) => {
const [isOpen, setIsOpen] = React.useState(false);
@ -291,6 +292,7 @@ const Navigation = ({
tariffBar={tariffBar}
title={title}
isEmptyPage={isEmptyPage}
onContextOptionsClick={onContextOptionsClick}
/>
</StyledContainer>
{isDesktop && !hideInfoPanel && (

View File

@ -50,6 +50,7 @@ export interface IContextButtonProps {
id: string;
title?: string;
onCloseDropBox?: () => void;
onContextOptionsClick?: () => void;
}
export interface IPlusButtonProps {
@ -95,6 +96,7 @@ export interface IControlButtonProps {
title?: string;
isEmptyPage?: boolean;
onCloseDropBox?: () => void;
onContextOptionsClick?: () => void;
}
export interface ITextProps {
@ -201,4 +203,5 @@ export interface INavigationProps {
onNavigationButtonClick?: () => void;
tariffBar: React.ReactElement;
showNavigationButton: boolean;
onContextOptionsClick?: () => void;
}

View File

@ -41,6 +41,7 @@ const ContextButton = ({
isMobile,
id,
onCloseDropBox,
onContextOptionsClick,
...rest
}: IContextButtonProps) => {
const [isOpen, setIsOpen] = useState(false);
@ -58,6 +59,7 @@ const ContextButton = ({
};
const onClick = (e: React.MouseEvent<HTMLDivElement>) => {
onContextOptionsClick?.();
if (withMenu) toggle(e, !isOpen);
};

View File

@ -63,6 +63,7 @@ const ControlButtons = ({
title,
isEmptyPage,
onCloseDropBox,
onContextOptionsClick,
}: IControlButtonProps) => {
const toggleInfoPanelAction = () => {
toggleInfoPanel?.();
@ -125,6 +126,7 @@ const ControlButtons = ({
isTrashFolder={isTrashFolder}
isMobile={isMobile || false}
onCloseDropBox={onCloseDropBox}
onContextOptionsClick={onContextOptionsClick}
/>
{!isDesktop && (
@ -180,6 +182,7 @@ const ControlButtons = ({
isTrashFolder={isTrashFolder}
isMobile={isMobile || false}
onCloseDropBox={onCloseDropBox}
onContextOptionsClick={onContextOptionsClick}
/>
)}
</>