fix merge conflicts

This commit is contained in:
Francesco Sansalvadore committed 2026-04-08 17:27:24 +02:00
1 parent bccc4117d2
commit ba941e9712
6 files changed
+235 -277

No files matched your search

-1
View File
@@ -441,7 +441,6 @@
"components/interfaces/Storage/StorageExplorer/FileExplorerColumn.tsx": 6,
"components/interfaces/Storage/StorageExplorer/FileExplorerRow.tsx": 1,
"components/interfaces/Storage/StorageExplorer/FileExplorerRowEditing.tsx": 2,
"components/interfaces/Storage/StorageExplorer/ItemContextMenu.tsx": 1,
"components/interfaces/Storage/StorageExplorer/MoveItemsModal.tsx": 1,
"components/interfaces/Storage/StorageExplorer/StorageExplorer.tsx": 1,
"components/interfaces/Storage/StorageExplorer/StorageExplorer.utils.tsx": 2,
@@ -41,12 +41,6 @@ export enum STORAGE_ROW_STATUS {
EDITING = 'EDITING',
}
export const CONTEXT_MENU_KEYS = {
STORAGE_COLUMN: 'STORAGE_COLUMN',
STORAGE_ITEM: 'STORAGE_ITEM',
STORAGE_FOLDER: 'STORAGE_FOLDER',
}
export const STORAGE_CLIENT_LIBRARY_MAPPINGS = {
upload: ['INSERT'],
download: ['SELECT'],
@@ -2,12 +2,9 @@ import { noop } from 'lodash'
import { useEffect, useRef } from 'react'
import { cn } from 'ui'
import { CONTEXT_MENU_KEYS, STORAGE_ROW_STATUS, STORAGE_VIEWS } from '../Storage.constants'
import { STORAGE_ROW_STATUS, STORAGE_VIEWS } from '../Storage.constants'
import type { StorageColumn, StorageItemWithColumn } from '../Storage.types'
import { ColumnContextMenu } from './ColumnContextMenu'
import { FileExplorerColumn } from './FileExplorerColumn'
import { FolderContextMenu } from './FolderContextMenu'
import { ItemContextMenu } from './ItemContextMenu'
import { useStorageExplorerStateSnapshot } from '@/state/storage-explorer'
export interface FileExplorerProps {
@@ -52,10 +49,6 @@ export const FileExplorer = ({
snap.view === STORAGE_VIEWS.COLUMNS && 'h-full'
)}
>
<ColumnContextMenu id={CONTEXT_MENU_KEYS.STORAGE_COLUMN} />
<ItemContextMenu id={CONTEXT_MENU_KEYS.STORAGE_ITEM} />
<FolderContextMenu id={CONTEXT_MENU_KEYS.STORAGE_FOLDER} />
{isLoading ? (
<FileExplorerColumn
column={{ id: '', name: '', path: '', items: [], status: STORAGE_ROW_STATUS.LOADING }}
@@ -1,21 +1,33 @@
import { Transition } from '@headlessui/react'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { get, noop, sum } from 'lodash'
import { Upload } from 'lucide-react'
import { get, noop, sum, uniqBy } from 'lodash'
import { ChevronsDown, ChevronsUp, Copy, Eye, FolderPlus, Upload } from 'lucide-react'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useContextMenu } from 'react-contexify'
import { toast } from 'sonner'
import { Checkbox, cn } from 'ui'
import {
Checkbox,
cn,
ContextMenu_Shadcn_,
ContextMenuContent_Shadcn_,
ContextMenuItem_Shadcn_,
ContextMenuSeparator_Shadcn_,
ContextMenuSub_Shadcn_,
ContextMenuSubContent_Shadcn_,
ContextMenuSubTrigger_Shadcn_,
ContextMenuTrigger_Shadcn_,
} from 'ui'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import {
CONTEXT_MENU_KEYS,
STORAGE_ROW_STATUS,
STORAGE_ROW_TYPES,
STORAGE_SORT_BY,
STORAGE_SORT_BY_ORDER,
STORAGE_VIEWS,
} from '../Storage.constants'
import type { StorageColumn, StorageItemWithColumn } from '../Storage.types'
import { FileExplorerRow } from './FileExplorerRow'
import { FileExplorerRowContextMenuProvider } from './FileExplorerRowContextMenu'
import { isPickerItemSelectable, useStorageExplorerPicker } from './StorageExplorerPickerContext'
import { InfiniteListDefault, LoaderForIconMenuItems } from '@/components/ui/InfiniteList'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
@@ -115,12 +127,24 @@ export const FileExplorerColumn = ({
const isEmpty =
visibleColumnItems.filter((item) => item.status !== STORAGE_ROW_STATUS.LOADING).length === 0
const { show } = useContextMenu()
const displayMenu = (event: any) => {
show(event, {
id: CONTEXT_MENU_KEYS.STORAGE_COLUMN,
props: { index },
})
const onSelectCreateFolder = () => {
snap.addNewFolderPlaceholder(index)
}
const onSelectAllItems = () => {
const colFiles = visibleColumnItems
.filter((item) => item.type === STORAGE_ROW_TYPES.FILE)
.map((item) => ({ ...item, columnIndex: index }))
const colFilesId = colFiles.map((item) => item.id).filter(Boolean)
const selectedFromCol = selectedItems.filter((item) => item.id && colFilesId.includes(item.id))
if (selectedFromCol.length === colFiles.length) {
snap.setSelectedItems(
selectedItems.filter((item) => item.id && !colFilesId.includes(item.id))
)
} else {
snap.setSelectedItems(uniqBy(selectedItems.concat(colFiles), 'id'))
}
}
const onDragOver = (event: any) => {
@@ -171,133 +195,213 @@ export const FileExplorerColumn = ({
)
return (
<div
ref={fileExplorerColumnRef}
className={cn(
'hide-scrollbar relative flex flex-col',
fullWidth ? 'w-full' : 'w-64 border-r border-overlay',
snap.view === STORAGE_VIEWS.LIST && 'min-h-0 flex-1 overflow-hidden',
snap.view === STORAGE_VIEWS.COLUMNS && 'h-full flex-shrink-0 overflow-auto'
)}
onContextMenu={displayMenu}
onDragOver={onDragOver}
onDrop={onDrop}
onClick={(event) => {
const eventTarget = get(event.target, ['className'], '')
if (typeof eventTarget === 'string' && eventTarget.includes('react-contexify')) return
onSelectColumnEmptySpace(index)
}}
>
{/* Checkbox selection for select all */}
{snap.view === STORAGE_VIEWS.COLUMNS && (
<ContextMenu_Shadcn_ modal={false}>
<ContextMenuTrigger_Shadcn_ asChild>
<div
ref={fileExplorerColumnRef}
className={cn(
'sticky top-0 z-10 mb-0 flex items-center bg-table-header-light px-2.5 [[data-theme*=dark]_&]:bg-table-header-dark',
haveSelectedItems ? 'h-10 py-3 opacity-100' : 'h-0 py-0 opacity-0',
'transition-all duration-200'
'hide-scrollbar relative flex flex-col',
fullWidth ? 'w-full' : 'w-64 border-r border-overlay',
snap.view === STORAGE_VIEWS.LIST && 'min-h-0 flex-1 overflow-hidden',
snap.view === STORAGE_VIEWS.COLUMNS && 'h-full flex-shrink-0 overflow-auto'
)}
onClick={(event) => event.stopPropagation()}
onDragOver={onDragOver}
onDrop={onDrop}
onClick={() => {
onSelectColumnEmptySpace(index)
}}
>
{columnFiles.length > 0 ? (
<>
<SelectAllCheckbox />
<p className="text-sm text-foreground-light">Select all {columnFiles.length} files</p>
</>
) : (
<p className="text-sm text-foreground-light">No files available for selection</p>
{/* Checkbox selection for select all */}
{snap.view === STORAGE_VIEWS.COLUMNS && (
<div
className={cn(
'sticky top-0 z-10 mb-0 flex items-center bg-table-header-light px-2.5 [[data-theme*=dark]_&]:bg-table-header-dark',
haveSelectedItems ? 'h-10 py-3 opacity-100' : 'h-0 py-0 opacity-0',
'transition-all duration-200'
)}
onClick={(event) => event.stopPropagation()}
>
{columnFiles.length > 0 ? (
<>
<SelectAllCheckbox />
<p className="text-sm text-foreground-light">
Select all {columnFiles.length} files
</p>
</>
) : (
<p className="text-sm text-foreground-light">No files available for selection</p>
)}
</div>
)}
</div>
)}
{/* List Interface Header */}
{snap.view === STORAGE_VIEWS.LIST && (
<div className="sticky top-0 py-2 z-10 flex min-w-min items-center border-b border-overlay bg-surface-100 px-2.5">
<div className="flex w-[40%] min-w-[250px] items-center">
<SelectAllCheckbox />
<p className="text-sm">Name</p>
</div>
<p className="w-[11%] min-w-[100px] text-sm">Size</p>
<p className="w-[14%] min-w-[100px] text-sm">Type</p>
<p className="w-[15%] min-w-[160px] text-sm">Created at</p>
<p className="w-[15%] min-w-[160px] text-sm">Last modified at</p>
</div>
)}
{/* List Interface Header */}
{snap.view === STORAGE_VIEWS.LIST && (
<div className="sticky top-0 py-2 z-10 flex min-w-min items-center border-b border-overlay bg-surface-100 px-2.5">
<div className="flex w-[40%] min-w-[250px] items-center">
<SelectAllCheckbox />
<p className="text-sm">Name</p>
</div>
<p className="w-[11%] min-w-[100px] text-sm">Size</p>
<p className="w-[14%] min-w-[100px] text-sm">Type</p>
<p className="w-[15%] min-w-[160px] text-sm">Created at</p>
<p className="w-[15%] min-w-[160px] text-sm">Last modified at</p>
</div>
)}
{/* Shimmering loaders while fetching contents */}
{column.status === STORAGE_ROW_STATUS.LOADING && (
<div
className={`
{/* Shimmering loaders while fetching contents */}
{column.status === STORAGE_ROW_STATUS.LOADING && (
<div
className={`
${fullWidth ? 'w-full' : 'w-64 border-r border-default'}
px-2 py-1 my-1 flex flex-shrink-0 flex-col space-y-2 overflow-auto
`}
>
<ShimmeringLoader />
<ShimmeringLoader />
<ShimmeringLoader />
>
<ShimmeringLoader />
<ShimmeringLoader />
<ShimmeringLoader />
</div>
)}
{/* Column Interface */}
{columnItems.length > 0 && (
<FileExplorerRowContextMenuProvider>
<InfiniteListDefault
className={snap.view === STORAGE_VIEWS.LIST ? 'min-h-0 flex-1' : 'h-full'}
items={columnItems}
itemProps={itemProps}
getItemKey={getItemKey}
getItemSize={(index: number) =>
index !== 0 && index === columnItems.length ? 85 : 37
}
ItemComponent={FileExplorerRow}
LoaderComponent={LoaderForIconMenuItems}
hasNextPage={column.status !== STORAGE_ROW_STATUS.LOADING && column.hasMoreItems}
isLoadingNextPage={column.isLoadingMoreItems}
onLoadNextPage={() => onColumnLoadMore(index, column)}
/>
</FileExplorerRowContextMenuProvider>
)}
{/* Drag drop upload CTA for when column is empty */}
{!(snap.isSearching && itemSearchString.length > 0) &&
visibleColumnItems.length === 0 &&
column.status !== STORAGE_ROW_STATUS.LOADING && (
<div className="h-full w-full flex flex-col items-center justify-center">
<img
alt="storage-placeholder"
src={`${BASE_PATH}/img/storage-placeholder.svg`}
className="opacity-75 pointer-events-none"
/>
<p className="text-sm my-3 opacity-75">Drop your files here</p>
<p className="w-40 text-center text-xs text-foreground-light">
Or upload them via the "Upload file" button above
</p>
</div>
)}
{snap.isSearching &&
itemSearchString.length > 0 &&
isEmpty &&
column.status !== STORAGE_ROW_STATUS.LOADING && (
<div className="h-full w-full flex flex-col items-center justify-center">
<p className="text-sm my-3 text-foreground">No results found in this folder</p>
<p className="w-40 text-center text-sm text-foreground-light">
Your search for "{itemSearchString}" did not return any results
</p>
</div>
)}
{/* Drag drop upload CTA for when column has files */}
<DragOverOverlay
isOpen={isDraggedOver}
folderIsEmpty={isEmpty}
onDragLeave={() => setIsDraggedOver(false)}
onDrop={() => setIsDraggedOver(false)}
/>
{/* List interface footer */}
{snap.view === STORAGE_VIEWS.LIST && (
<div className="shrink-0 rounded-b-md z-10 flex min-w-min items-center bg-panel-footer-light px-2.5 py-2 [[data-theme*=dark]_&]:bg-panel-footer-dark w-full">
<p className="text-sm">
{formatBytes(columnItemsSize)} for {columnItems.length} items
</p>
</div>
)}
</div>
)}
{/* Column Interface */}
{columnItems.length > 0 && (
<InfiniteListDefault
className={snap.view === STORAGE_VIEWS.LIST ? 'min-h-0 flex-1' : 'h-full'}
items={columnItems}
itemProps={itemProps}
getItemKey={getItemKey}
getItemSize={(index: number) => (index !== 0 && index === columnItems.length ? 85 : 37)}
ItemComponent={FileExplorerRow}
LoaderComponent={LoaderForIconMenuItems}
hasNextPage={column.status !== STORAGE_ROW_STATUS.LOADING && column.hasMoreItems}
isLoadingNextPage={column.isLoadingMoreItems}
onLoadNextPage={() => onColumnLoadMore(index, column)}
/>
)}
{/* Drag drop upload CTA for when column is empty */}
{!(snap.isSearching && itemSearchString.length > 0) &&
visibleColumnItems.length === 0 &&
column.status !== STORAGE_ROW_STATUS.LOADING && (
<div className="h-full w-full flex flex-col items-center justify-center">
<img
alt="storage-placeholder"
src={`${BASE_PATH}/img/storage-placeholder.svg`}
className="opacity-75 pointer-events-none"
/>
<p className="text-sm my-3 opacity-75">Drop your files here</p>
<p className="w-40 text-center text-xs text-foreground-light">
Or upload them via the "Upload file" button above
</p>
</div>
</ContextMenuTrigger_Shadcn_>
<ContextMenuContent_Shadcn_>
{canUpdateStorage && (
<>
<ContextMenuItem_Shadcn_ className="gap-x-2" onSelect={onSelectCreateFolder}>
<FolderPlus size={14} />
<span className="text-xs">New folder</span>
</ContextMenuItem_Shadcn_>
<ContextMenuSeparator_Shadcn_ />
</>
)}
{snap.isSearching &&
itemSearchString.length > 0 &&
isEmpty &&
column.status !== STORAGE_ROW_STATUS.LOADING && (
<div className="h-full w-full flex flex-col items-center justify-center">
<p className="text-sm my-3 text-foreground">No results found in this folder</p>
<p className="w-40 text-center text-sm text-foreground-light">
Your search for "{itemSearchString}" did not return any results
</p>
</div>
)}
{/* Drag drop upload CTA for when column has files */}
<DragOverOverlay
isOpen={isDraggedOver}
folderIsEmpty={isEmpty}
onDragLeave={() => setIsDraggedOver(false)}
onDrop={() => setIsDraggedOver(false)}
/>
{/* List interface footer */}
{snap.view === STORAGE_VIEWS.LIST && (
<div className="shrink-0 rounded-b-md z-10 flex min-w-min items-center bg-panel-footer-light px-2.5 py-2 [[data-theme*=dark]_&]:bg-panel-footer-dark w-full">
<p className="text-sm">
{formatBytes(columnItemsSize)} for {columnItems.length} items
</p>
</div>
)}
</div>
<ContextMenuItem_Shadcn_ className="gap-x-2" onSelect={onSelectAllItems}>
<Copy size={14} />
<span className="text-xs">Select all items</span>
</ContextMenuItem_Shadcn_>
<ContextMenuSub_Shadcn_>
<ContextMenuSubTrigger_Shadcn_ className="gap-x-2">
<Eye size={14} />
<span className="text-xs">View</span>
</ContextMenuSubTrigger_Shadcn_>
<ContextMenuSubContent_Shadcn_>
<ContextMenuItem_Shadcn_ onSelect={() => snap.setView(STORAGE_VIEWS.COLUMNS)}>
<span className="text-xs">As columns</span>
</ContextMenuItem_Shadcn_>
<ContextMenuItem_Shadcn_ onSelect={() => snap.setView(STORAGE_VIEWS.LIST)}>
<span className="text-xs">As list</span>
</ContextMenuItem_Shadcn_>
</ContextMenuSubContent_Shadcn_>
</ContextMenuSub_Shadcn_>
<ContextMenuSub_Shadcn_>
<ContextMenuSubTrigger_Shadcn_ className="gap-x-2">
<ChevronsDown size={14} />
<span className="text-xs">Sort by</span>
</ContextMenuSubTrigger_Shadcn_>
<ContextMenuSubContent_Shadcn_>
<ContextMenuItem_Shadcn_ onSelect={() => void snap.setSortBy(STORAGE_SORT_BY.NAME)}>
<span className="text-xs">Name</span>
</ContextMenuItem_Shadcn_>
<ContextMenuItem_Shadcn_
onSelect={() => void snap.setSortBy(STORAGE_SORT_BY.CREATED_AT)}
>
<span className="text-xs">Last created</span>
</ContextMenuItem_Shadcn_>
<ContextMenuItem_Shadcn_
onSelect={() => void snap.setSortBy(STORAGE_SORT_BY.UPDATED_AT)}
>
<span className="text-xs">Last modified</span>
</ContextMenuItem_Shadcn_>
<ContextMenuItem_Shadcn_
onSelect={() => void snap.setSortBy(STORAGE_SORT_BY.LAST_ACCESSED_AT)}
>
<span className="text-xs">Last accessed</span>
</ContextMenuItem_Shadcn_>
</ContextMenuSubContent_Shadcn_>
</ContextMenuSub_Shadcn_>
<ContextMenuSub_Shadcn_>
<ContextMenuSubTrigger_Shadcn_ className="gap-x-2">
<ChevronsUp size={14} />
<span className="text-xs">Sort by order</span>
</ContextMenuSubTrigger_Shadcn_>
<ContextMenuSubContent_Shadcn_>
<ContextMenuItem_Shadcn_
onSelect={() => void snap.setSortByOrder(STORAGE_SORT_BY_ORDER.ASC)}
>
<span className="text-xs">Ascending</span>
</ContextMenuItem_Shadcn_>
<ContextMenuItem_Shadcn_
onSelect={() => void snap.setSortByOrder(STORAGE_SORT_BY_ORDER.DESC)}
>
<span className="text-xs">Descending</span>
</ContextMenuItem_Shadcn_>
</ContextMenuSubContent_Shadcn_>
</ContextMenuSub_Shadcn_>
</ContextMenuContent_Shadcn_>
</ContextMenu_Shadcn_>
)
}
@@ -17,7 +17,6 @@ import {
Trash2,
} from 'lucide-react'
import type { CSSProperties } from 'react'
import { useContextMenu } from 'react-contexify'
import {
Checkbox,
cn,
@@ -36,13 +35,13 @@ import {
} from 'ui'
import {
CONTEXT_MENU_KEYS,
STORAGE_ROW_STATUS,
STORAGE_ROW_TYPES,
STORAGE_VIEWS,
URL_EXPIRY_DURATION,
} from '../Storage.constants'
import { StorageItemWithColumn, type StorageItem } from '../Storage.types'
import { useFileExplorerContextMenu } from './FileExplorerRowContextMenu'
import { FileExplorerRowEditing } from './FileExplorerRowEditing'
import { copyPathToFolder } from './StorageExplorer.utils'
import { isPickerItemSelectable, useStorageExplorerPicker } from './StorageExplorerPickerContext'
@@ -129,7 +128,7 @@ export const FileExplorerRow = ({
selectRangeItems,
} = useStorageExplorerStateSnapshot()
const picker = useStorageExplorerPicker()
const { show } = useContextMenu()
const ctx = useFileExplorerContextMenu()
const { onCopyUrl } = useCopyUrl()
const isPublic = selectedBucket.public
@@ -275,18 +274,6 @@ export const FileExplorerRow = ({
const createdAt = item.created_at ? new Date(item.created_at).toLocaleString() : '-'
const updatedAt = item.updated_at ? new Date(item.updated_at).toLocaleString() : '-'
const displayMenu = (event: any, rowType: STORAGE_ROW_TYPES) => {
show(event, {
id:
rowType === STORAGE_ROW_TYPES.FILE
? CONTEXT_MENU_KEYS.STORAGE_ITEM
: CONTEXT_MENU_KEYS.STORAGE_FOLDER,
props: {
item: itemWithColumnIndex,
},
})
}
const nameWidth =
view === STORAGE_VIEWS.LIST && item.isCorrupted
? `calc(100% - 60px)`
@@ -307,9 +294,7 @@ export const FileExplorerRow = ({
onContextMenu={(event) => {
event.preventDefault()
event.stopPropagation()
item.type === STORAGE_ROW_TYPES.FILE
? displayMenu(event, STORAGE_ROW_TYPES.FILE)
: displayMenu(event, STORAGE_ROW_TYPES.FOLDER)
ctx?.onRowContextMenu(event, rowOptions)
}}
>
<div
@@ -1,117 +0,0 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { ChevronRight, Copy, Download, Edit, Move, Trash2 } from 'lucide-react'
import { Item, Menu, Separator, Submenu } from 'react-contexify'
import 'react-contexify/dist/ReactContexify.css'
import { URL_EXPIRY_DURATION } from '../Storage.constants'
import { StorageItemWithColumn } from '../Storage.types'
import { useCopyUrl } from './useCopyUrl'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useStorageExplorerStateSnapshot } from '@/state/storage-explorer'
interface ItemContextMenuProps {
id: string
}
export const ItemContextMenu = ({ id = '' }: ItemContextMenuProps) => {
const {
selectedBucket,
setSelectedItemsToDelete,
setSelectedItemToRename,
setSelectedItemsToMove,
setSelectedFileCustomExpiry,
downloadFile,
} = useStorageExplorerStateSnapshot()
const { onCopyUrl } = useCopyUrl()
const isPublic = selectedBucket.public
const { can: canUpdateFiles } = useAsyncCheckPermissions(PermissionAction.STORAGE_WRITE, '*')
const onHandleClick = async (
event: 'copy' | 'rename' | 'move' | 'download',
item: StorageItemWithColumn,
expiresIn?: number
) => {
if (item.isCorrupted) return
if (event === 'copy') {
if (expiresIn !== undefined && expiresIn < 0) {
setSelectedFileCustomExpiry(item)
return
}
if (item.path) {
onCopyUrl(item.path, expiresIn)
}
return
}
if (event === 'rename') {
setSelectedItemToRename(item)
return
}
if (event === 'move') {
setSelectedItemsToMove([item])
return
}
if (event === 'download') {
await downloadFile(item)
}
}
return (
<Menu id={id} animation="fade">
{isPublic ? (
<Item onClick={({ props }) => onHandleClick('copy', props.item)}>
<Copy size={14} />
<span className="ml-2 text-xs">Get URL</span>
</Item>
) : (
<Submenu
label={
<div className="flex items-center space-x-2">
<Copy size={14} />
<span className="text-xs">Get URL</span>
</div>
}
arrow={<ChevronRight size={14} />}
>
<Item
onClick={({ props }) => onHandleClick('copy', props.item, URL_EXPIRY_DURATION.WEEK)}
>
<span className="ml-2 text-xs">Expire in 1 week</span>
</Item>
<Item
onClick={({ props }) => onHandleClick('copy', props.item, URL_EXPIRY_DURATION.MONTH)}
>
<span className="ml-2 text-xs">Expire in 1 month</span>
</Item>
<Item
onClick={({ props }) => onHandleClick('copy', props.item, URL_EXPIRY_DURATION.YEAR)}
>
<span className="ml-2 text-xs">Expire in 1 year</span>
</Item>
<Item onClick={({ props }) => onHandleClick('copy', props.item, -1)}>
<span className="ml-2 text-xs">Custom expiry</span>
</Item>
</Submenu>
)}
<Item onClick={({ props }) => onHandleClick('download', props.item)}>
<Download size={14} strokeWidth={1} />
<span className="ml-2 text-xs">Download</span>
</Item>
{canUpdateFiles && [
<Item key="rename-file" onClick={({ props }) => onHandleClick('rename', props.item)}>
<Edit size={14} strokeWidth={1} />
<span className="ml-2 text-xs">Rename</span>
</Item>,
<Item key="move-file" onClick={({ props }) => onHandleClick('move', props.item)}>
<Move size={14} strokeWidth={1} />
<span className="ml-2 text-xs">Move</span>
</Item>,
<Separator key="file-separator" />,
<Item key="delete-file" onClick={({ props }) => setSelectedItemsToDelete([props.item])}>
<Trash2 size={14} strokeWidth={1} stroke="red" />
<span className="ml-2 text-xs">Delete</span>
</Item>,
]}
</Menu>
)
}