import { FunctionComponent, useCallback, useMemo } from 'react' import { FileItemActionType } from '../AttachedFilesPopover/PopoverFileItemAction' import Icon from '@/Components/Icon/Icon' import { observer } from 'mobx-react-lite' import { formatSizeToReadableString } from '@standardnotes/filepicker' import { useResponsiveAppPane } from '../Panes/ResponsivePaneProvider' import { AppPaneId } from '../Panes/AppPaneMetadata' import MenuItem from '../Menu/MenuItem' import { FileContextMenuBackupOption } from './FileContextMenuBackupOption' import MenuSwitchButtonItem from '../Menu/MenuSwitchButtonItem' import { FileItem } from '@standardnotes/snjs' import AddTagOption from '../NotesOptions/AddTagOption' import { MenuItemIconSize } from '@/Constants/TailwindClassNames' import AddToVaultMenuOption from '../Vaults/AddToVaultMenuOption' import { iconClass } from '../NotesOptions/ClassNames' import { useApplication } from '../ApplicationProvider' import MenuSection from '../Menu/MenuSection' import { ToastType, addToast } from '@standardnotes/toast' type Props = { closeMenu: () => void isFileAttachedToNote?: boolean renameToggleCallback?: (isRenamingFile: boolean) => void shouldShowRenameOption: boolean shouldShowAttachOption: boolean selectedFiles: FileItem[] } const FileMenuOptions: FunctionComponent = ({ closeMenu, isFileAttachedToNote, renameToggleCallback, shouldShowRenameOption, shouldShowAttachOption, selectedFiles, }) => { const application = useApplication() const { shouldUseStreamingAPI, handleFileAction } = application.filesController const { toggleAppPane } = useResponsiveAppPane() const hasProtectedFiles = useMemo(() => selectedFiles.some((file) => file.protected), [selectedFiles]) const hasSelectedMultipleFiles = useMemo(() => selectedFiles.length > 1, [selectedFiles.length]) const canShowZipDownloadOption = shouldUseStreamingAPI && hasSelectedMultipleFiles const totalFileSize = useMemo( () => selectedFiles.map((file) => file.decryptedSize).reduce((prev, next) => prev + next, 0), [selectedFiles], ) const onDetach = useCallback(() => { const file = selectedFiles[0] void handleFileAction({ type: FileItemActionType.DetachFileToNote, payload: { file }, }) closeMenu() }, [closeMenu, handleFileAction, selectedFiles]) const onAttach = useCallback(() => { const file = selectedFiles[0] void handleFileAction({ type: FileItemActionType.AttachFileToNote, payload: { file }, }) closeMenu() }, [closeMenu, handleFileAction, selectedFiles]) const closeMenuAndToggleFilesList = useCallback(() => { toggleAppPane(AppPaneId.Items) closeMenu() }, [closeMenu, toggleAppPane]) const areSomeFilesInReadonlySharedVault = selectedFiles.some((file) => { const vault = application.vaults.getItemVault(file) return vault?.isSharedVaultListing() && application.vaultUsers.isCurrentUserReadonlyVaultMember(vault) }) const hasAdminPermissionForAllSharedFiles = selectedFiles.every((file) => { const vault = application.vaults.getItemVault(file) if (!vault?.isSharedVaultListing()) { return true } return application.vaultUsers.isCurrentUserSharedVaultAdmin(vault) }) if (selectedFiles.length === 0) { return
No files selected
} return ( <> {selectedFiles.length === 1 && (isFileAttachedToNote || shouldShowAttachOption) && ( {isFileAttachedToNote ? ( Detach from note ) : shouldShowAttachOption ? ( Attach to note ) : null} )} {application.featuresController.isVaultsEnabled() && ( )} { void application.filesController.setProtectionForFiles(hasProtectedFiles, selectedFiles) }} disabled={areSomeFilesInReadonlySharedVault} > Password protect { void application.filesController.downloadFiles(selectedFiles) closeMenu() }} > Download {canShowZipDownloadOption ? 'separately' : ''} {canShowZipDownloadOption && ( { application.filesController.downloadFilesAsZip(selectedFiles).catch((error) => { if (error instanceof DOMException && error.name === 'AbortError') { return } console.error(error) addToast({ type: ToastType.Error, message: error.message || 'Failed to download files as archive', }) }) closeMenu() }} > Download as archive )} {shouldShowRenameOption && ( { renameToggleCallback?.(true) }} disabled={areSomeFilesInReadonlySharedVault} > Rename )} { closeMenuAndToggleFilesList() void application.filesController.deleteFilesPermanently(selectedFiles) }} disabled={areSomeFilesInReadonlySharedVault} > Delete permanently
{!hasSelectedMultipleFiles && (
File ID: {selectedFiles[0].uuid}
)}
{hasSelectedMultipleFiles ? 'Total Size:' : 'Size:'}{' '} {formatSizeToReadableString(totalFileSize)}
) } export default observer(FileMenuOptions)