From 56928577220e0c7e0f04821ae59ba599a09b71fc Mon Sep 17 00:00:00 2001 From: gopienkonikita Date: Thu, 27 Jun 2024 13:02:44 +0300 Subject: [PATCH 1/3] Web: Files: rewritten logic of the header context-menu --- .../ItemTitle/Rooms/context-btn.js | 41 +- .../src/pages/Home/Section/Header/index.js | 585 +----------------- .../client/src/store/ContextOptionsStore.js | 203 ++++-- .../client/src/store/FilesActionsStore.js | 7 +- packages/client/src/store/FilesStore.js | 18 +- 5 files changed, 197 insertions(+), 657 deletions(-) diff --git a/packages/client/src/pages/Home/InfoPanel/Body/sub-components/ItemTitle/Rooms/context-btn.js b/packages/client/src/pages/Home/InfoPanel/Body/sub-components/ItemTitle/Rooms/context-btn.js index 667efffae1..59bb0e911b 100644 --- a/packages/client/src/pages/Home/InfoPanel/Body/sub-components/ItemTitle/Rooms/context-btn.js +++ b/packages/client/src/pages/Home/InfoPanel/Body/sub-components/ItemTitle/Rooms/context-btn.js @@ -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([ diff --git a/packages/client/src/pages/Home/Section/Header/index.js b/packages/client/src/pages/Home/Section/Header/index.js index 2ab7448746..d08ada1ff0 100644 --- a/packages/client/src/pages/Home/Section/Header/index.js +++ b/packages/client/src/pages/Home/Section/Header/index.js @@ -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 CopyToReactSvgUrl from "PUBLIC_DIR/images/copyTo.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 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,42 +203,28 @@ 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, + onEmptyTrashAction, + getHeaderOptions, } = props; - const navigate = useNavigate(); const location = useLocation(); const { groupId } = useParams(); @@ -313,413 +245,16 @@ 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_copy-external-link", - key: "copy-external-link", - label: t("Files:CopySharedLink"), - icon: CopyToReactSvgUrl, - 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_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_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_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_download", - key: "download", - label: t("Common:Download"), - onClick: onDownloadAction, - disabled: !security?.Download, - icon: DownloadReactSvgUrl, - }, - { - 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), - - 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, - }, - ]; + return getHeaderOptions(t, selectedFolder); }; const onSelect = (e) => { @@ -1041,23 +576,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, @@ -1065,16 +596,10 @@ export default inject( isHeaderVisible, isHeaderIndeterminate, isHeaderChecked, - isThirdPartySelection, cbMenuItems, getCheckboxItemLabel, getCheckboxItemId, isEmptyFilesList, - getFolderInfo, - setBufferSelection, - - activeFiles, - activeFolders, roomsForRestore, roomsForDelete, @@ -1082,8 +607,6 @@ export default inject( isEmptyPage, categoryType, - getPrimaryLink, - setSelection, } = filesStore; const { @@ -1097,58 +620,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; @@ -1161,7 +653,6 @@ export default inject( } = peopleStore.groupsStore; const { theme, frameConfig, isFrame, currentDeviceType } = settingsStore; - const { isGracePeriod } = currentTariffStatusStore; const isRoom = !!roomType; const isPublicRoomType = roomType === RoomsType.PublicRoom; @@ -1169,15 +660,11 @@ export default inject( const isFormRoomType = roomType === RoomsType.FormRoom; const { - onClickEditRoom, - onClickInviteUsers, - onShowInfoPanel, - onClickArchive, - onClickReconnectStorage, - onCopyLink, onCreateAndCopySharedLink, getFolderModel, onCreateRoom, + getHeaderOptions, + onEmptyTrashAction, } = contextOptionsStore; const canRestoreAll = isArchiveFolder && roomsForRestore.length > 0; @@ -1205,7 +692,7 @@ export default inject( } = headerMenuStore; const { setSelected: setAccountsSelected } = selectionStore; - const { isPublicRoom, primaryLink, setExternalLink } = publicRoomStore; + const { isPublicRoom } = publicRoomStore; let folderPath = navigationPath; @@ -1218,10 +705,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); @@ -1237,17 +720,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, @@ -1256,70 +735,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, @@ -1336,31 +781,23 @@ 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, + onEmptyTrashAction, + getHeaderOptions, }; }, )( diff --git a/packages/client/src/store/ContextOptionsStore.js b/packages/client/src/store/ContextOptionsStore.js index 64b458fad8..fa975936f0 100644 --- a/packages/client/src/store/ContextOptionsStore.js +++ b/packages/client/src/store/ContextOptionsStore.js @@ -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); }; @@ -503,12 +515,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; @@ -517,23 +529,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) => @@ -1072,7 +1067,139 @@ class ContextOptionsStore { return { pinOptions, muteOptions }; }; - getFilesContextOptions = (item, t, isInfoPanel) => { + onEmptyTrashAction = () => { + const { activeFiles, activeFolders } = this.filesStore; + const isExistActiveItems = [...activeFiles, ...activeFolders].length > 0; + + if (isExistActiveItems || 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, setBufferSelection } = + this.filesStore; + + setBufferSelection(item); + + 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 }; + } + const { contextOptions, isEditing } = item; const isRootThirdPartyFolder = @@ -1197,7 +1324,7 @@ class ContextOptionsStore { icon: MoveReactSvgUrl, onClick: isEditing ? () => this.onShowEditingToast(t) - : this.onMoveAction, + : () => this.onMoveAction(item), disabled: false, }, { @@ -1205,7 +1332,7 @@ class ContextOptionsStore { key: "copy-to", label: t("Common:Copy"), icon: CopyReactSvgUrl, - onClick: this.onCopyAction, + onClick: () => this.onCopyAction(item), disabled: false, }, { @@ -1227,7 +1354,7 @@ class ContextOptionsStore { icon: MoveReactSvgUrl, onClick: isEditing ? () => this.onShowEditingToast(t) - : this.onMoveAction, + : () => this.onMoveAction(item), disabled: false, }, { @@ -1235,7 +1362,7 @@ class ContextOptionsStore { key: "copy-to", label: t("Common:Copy"), icon: CopyReactSvgUrl, - onClick: this.onCopyAction, + onClick: () => this.onCopyAction(item), disabled: false, }, { @@ -1369,7 +1496,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", @@ -1425,7 +1552,7 @@ class ContextOptionsStore { disabled: (isPublicRoomType && item.canCopyPublicLink && !isArchive) || this.publicRoomStore.isPublicRoom || - !item.security.CopyLink, + !item.security?.CopyLink, }, { id: "option_copy-external-link", @@ -1691,7 +1818,7 @@ class ContextOptionsStore { !(isCollaborator && option.key === "create-room"), ); - return newOptions; + return trimSeparator(newOptions); }; getGroupContextOptions = (t) => { diff --git a/packages/client/src/store/FilesActionsStore.js b/packages/client/src/store/FilesActionsStore.js index 0c49b8c8e1..3f6461ba83 100644 --- a/packages/client/src/store/FilesActionsStore.js +++ b/packages/client/src/store/FilesActionsStore.js @@ -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(); } diff --git a/packages/client/src/store/FilesStore.js b/packages/client/src/store/FilesStore.js index aa96bf51b4..6766b3bc5a 100644 --- a/packages/client/src/store/FilesStore.js +++ b/packages/client/src/store/FilesStore.js @@ -1986,7 +1986,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 = @@ -2098,6 +2098,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", @@ -2466,10 +2474,6 @@ class FilesStore { } } - // if (fromInfoPanel) { - // roomOptions = this.removeOptions(roomOptions, ["external-link"]); - // } - roomOptions = this.removeSeparator(roomOptions); return roomOptions; @@ -2499,6 +2503,10 @@ class FilesStore { "delete", ]; + if (optionsToRemove.length) { + folderOptions = this.removeOptions(folderOptions, optionsToRemove); + } + if (!canDownload) { folderOptions = this.removeOptions(folderOptions, ["download"]); } From 116c72c261995d5d93473ae1074df27a1a6753b6 Mon Sep 17 00:00:00 2001 From: gopienkonikita Date: Thu, 27 Jun 2024 13:49:53 +0300 Subject: [PATCH 2/3] Web: Files: Navigation: added onContextClick --- packages/client/src/pages/Home/Section/Header/index.js | 8 ++++++++ packages/client/src/store/ContextOptionsStore.js | 5 +---- packages/shared/components/navigation/Navigation.tsx | 2 ++ packages/shared/components/navigation/Navigation.types.ts | 2 ++ .../components/navigation/sub-components/ContextBtn.tsx | 2 ++ .../components/navigation/sub-components/ControlBtn.tsx | 3 +++ 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/client/src/pages/Home/Section/Header/index.js b/packages/client/src/pages/Home/Section/Header/index.js index d08ada1ff0..664438e466 100644 --- a/packages/client/src/pages/Home/Section/Header/index.js +++ b/packages/client/src/pages/Home/Section/Header/index.js @@ -223,6 +223,7 @@ const SectionHeaderContent = (props) => { onCreateRoom, onEmptyTrashAction, getHeaderOptions, + setBufferSelection, } = props; const location = useLocation(); @@ -257,6 +258,10 @@ const SectionHeaderContent = (props) => { return getHeaderOptions(t, selectedFolder); }; + const onContextOptionsClick = () => { + setBufferSelection(selectedFolder); + }; + const onSelect = (e) => { const key = e.currentTarget.dataset.key; @@ -540,6 +545,7 @@ const SectionHeaderContent = (props) => { onNavigationButtonClick={onNavigationButtonClick} tariffBar={} showNavigationButton={!!showNavigationButton} + onContextOptionsClick={onContextOptionsClick} /> )} @@ -607,6 +613,7 @@ export default inject( isEmptyPage, categoryType, + setBufferSelection, } = filesStore; const { @@ -798,6 +805,7 @@ export default inject( onCreateRoom, onEmptyTrashAction, getHeaderOptions, + setBufferSelection, }; }, )( diff --git a/packages/client/src/store/ContextOptionsStore.js b/packages/client/src/store/ContextOptionsStore.js index 94c01333de..a1780776e9 100644 --- a/packages/client/src/store/ContextOptionsStore.js +++ b/packages/client/src/store/ContextOptionsStore.js @@ -1110,10 +1110,7 @@ class ContextOptionsStore { getHeaderOptions = (t, item) => { const { isRecycleBinFolder, isArchiveFolder } = this.treeFoldersStore; - const { roomsForDelete, roomsForRestore, setBufferSelection } = - this.filesStore; - - setBufferSelection(item); + const { roomsForDelete, roomsForRestore } = this.filesStore; const canRestoreAll = roomsForRestore.length > 0; const canDeleteAll = roomsForDelete.length > 0; diff --git a/packages/shared/components/navigation/Navigation.tsx b/packages/shared/components/navigation/Navigation.tsx index 8b92dd8d32..fff0ff1cf2 100644 --- a/packages/shared/components/navigation/Navigation.tsx +++ b/packages/shared/components/navigation/Navigation.tsx @@ -82,6 +82,7 @@ const Navigation = ({ onNavigationButtonClick, tariffBar, showNavigationButton, + onContextClick, ...rest }: INavigationProps) => { const [isOpen, setIsOpen] = React.useState(false); @@ -291,6 +292,7 @@ const Navigation = ({ tariffBar={tariffBar} title={title} isEmptyPage={isEmptyPage} + onContextClick={onContextClick} /> {isDesktop && !hideInfoPanel && ( diff --git a/packages/shared/components/navigation/Navigation.types.ts b/packages/shared/components/navigation/Navigation.types.ts index ce6782fce2..751a72bd76 100644 --- a/packages/shared/components/navigation/Navigation.types.ts +++ b/packages/shared/components/navigation/Navigation.types.ts @@ -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 { diff --git a/packages/shared/components/navigation/sub-components/ContextBtn.tsx b/packages/shared/components/navigation/sub-components/ContextBtn.tsx index eed4dfcd14..d5be5ffc43 100644 --- a/packages/shared/components/navigation/sub-components/ContextBtn.tsx +++ b/packages/shared/components/navigation/sub-components/ContextBtn.tsx @@ -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) => { + onContextOptionsClick?.(); if (withMenu) toggle(e, !isOpen); }; diff --git a/packages/shared/components/navigation/sub-components/ControlBtn.tsx b/packages/shared/components/navigation/sub-components/ControlBtn.tsx index 62525b3d81..ed362e6498 100644 --- a/packages/shared/components/navigation/sub-components/ControlBtn.tsx +++ b/packages/shared/components/navigation/sub-components/ControlBtn.tsx @@ -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} /> )} From 1de638e5ccb7dccd538f37b93e99413affe52eb8 Mon Sep 17 00:00:00 2001 From: gopienkonikita Date: Thu, 27 Jun 2024 16:12:42 +0300 Subject: [PATCH 3/3] Web: Files: Context-menu: fix --- packages/client/src/store/ContextOptionsStore.js | 8 +++++++- packages/shared/components/navigation/Navigation.tsx | 4 ++-- packages/shared/components/navigation/Navigation.types.ts | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/client/src/store/ContextOptionsStore.js b/packages/client/src/store/ContextOptionsStore.js index a1780776e9..a231e3dfca 100644 --- a/packages/client/src/store/ContextOptionsStore.js +++ b/packages/client/src/store/ContextOptionsStore.js @@ -1073,7 +1073,8 @@ class ContextOptionsStore { const { activeFiles, activeFolders } = this.filesStore; const isExistActiveItems = [...activeFiles, ...activeFolders].length > 0; - if (isExistActiveItems || emptyTrashInProgress) return; + if (isExistActiveItems || this.filesActionsStore.emptyTrashInProgress) + return; this.dialogsStore.setEmptyTrashDialogVisible(true); }; @@ -1197,6 +1198,11 @@ class ContextOptionsStore { optionsToRemove, ); item = { ...item, contextOptions }; + } else { + item.contextOptions = this.filesStore.removeOptions( + item.contextOptions, + optionsToRemove, + ); } const { contextOptions, isEditing } = item; diff --git a/packages/shared/components/navigation/Navigation.tsx b/packages/shared/components/navigation/Navigation.tsx index fff0ff1cf2..507d1361c6 100644 --- a/packages/shared/components/navigation/Navigation.tsx +++ b/packages/shared/components/navigation/Navigation.tsx @@ -82,7 +82,7 @@ const Navigation = ({ onNavigationButtonClick, tariffBar, showNavigationButton, - onContextClick, + onContextOptionsClick, ...rest }: INavigationProps) => { const [isOpen, setIsOpen] = React.useState(false); @@ -292,7 +292,7 @@ const Navigation = ({ tariffBar={tariffBar} title={title} isEmptyPage={isEmptyPage} - onContextClick={onContextClick} + onContextOptionsClick={onContextOptionsClick} /> {isDesktop && !hideInfoPanel && ( diff --git a/packages/shared/components/navigation/Navigation.types.ts b/packages/shared/components/navigation/Navigation.types.ts index 751a72bd76..dcf25adc90 100644 --- a/packages/shared/components/navigation/Navigation.types.ts +++ b/packages/shared/components/navigation/Navigation.types.ts @@ -203,4 +203,5 @@ export interface INavigationProps { onNavigationButtonClick?: () => void; tariffBar: React.ReactElement; showNavigationButton: boolean; + onContextOptionsClick?: () => void; }