fix: moved path into the file entry
This commit is contained in:
		| @ -5,7 +5,6 @@ import { | ||||
|   type FileExplorerRow, | ||||
|   type FileExplorerRender, | ||||
|   type FileExplorerRowContextMenuProps, | ||||
|   constructPath, | ||||
| } from '@src/components/Explorer/utils' | ||||
| import { ContextMenu, ContextMenuItem } from '@src/components/ContextMenu' | ||||
| import { useRef } from 'react' | ||||
| @ -59,19 +58,18 @@ const Spacer = (level: number) => { | ||||
| export const FileExplorer = ({ | ||||
|   rowsToRender, | ||||
|   selectedRow, | ||||
|   renamingRow, | ||||
| }: { | ||||
|   rowsToRender: FileExplorerRow[] | ||||
|   selectedRow: FileExplorerEntry | null | ||||
|   renamingRow: FileExplorerRow | null | ||||
| }) => { | ||||
|   // Local state for selection and what is opened | ||||
|   // diff this against new Project value that comes in | ||||
|   return ( | ||||
|     <div role="presentation" className="p-px"> | ||||
|       {rowsToRender.map((row, index, original) => { | ||||
|         const key = constructPath({ | ||||
|           parentPath: row.parentPath, | ||||
|           name: row.name, | ||||
|         }) | ||||
|         const key = row.key | ||||
|         const renderRow: FileExplorerRender = { | ||||
|           ...row, | ||||
|           domIndex: index, | ||||
| @ -82,6 +80,7 @@ export const FileExplorer = ({ | ||||
|             key={key} | ||||
|             row={renderRow} | ||||
|             selectedRow={selectedRow} | ||||
|             renamingRow={renamingRow} | ||||
|           ></FileExplorerRowElement> | ||||
|         ) | ||||
|       })} | ||||
| @ -89,6 +88,115 @@ export const FileExplorer = ({ | ||||
|   ) | ||||
| } | ||||
|  | ||||
| function FileExplorerRowContextMenu({ | ||||
|   itemRef, | ||||
|   onRename, | ||||
|   onDelete, | ||||
|   onClone, | ||||
|   onOpenInNewWindow, | ||||
|   callback, | ||||
| }: FileExplorerRowContextMenuProps) { | ||||
|   const platform = usePlatform() | ||||
|   const metaKey = platform === 'macos' ? '⌘' : 'Ctrl' | ||||
|   return ( | ||||
|     <ContextMenu | ||||
|       menuTargetElement={itemRef} | ||||
|       callback={callback} | ||||
|       items={[ | ||||
|         <ContextMenuItem | ||||
|           data-testid="context-menu-rename" | ||||
|           onClick={onRename} | ||||
|           hotkey="Enter" | ||||
|         > | ||||
|           Rename | ||||
|         </ContextMenuItem>, | ||||
|         <ContextMenuItem | ||||
|           data-testid="context-menu-delete" | ||||
|           onClick={onDelete} | ||||
|           hotkey={metaKey + ' + Del'} | ||||
|         > | ||||
|           Delete | ||||
|         </ContextMenuItem>, | ||||
|         <ContextMenuItem | ||||
|           data-testid="context-menu-clone" | ||||
|           onClick={onClone} | ||||
|           hotkey="" | ||||
|         > | ||||
|           Clone | ||||
|         </ContextMenuItem>, | ||||
|         <ContextMenuItem | ||||
|           data-testid="context-menu-open-in-new-window" | ||||
|         onClick={onOpenInNewWindow} | ||||
|           > | ||||
|           Open in new window | ||||
|         </ContextMenuItem>, | ||||
|       ]} | ||||
|       /> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| function RenameForm({ | ||||
|   row, | ||||
|   onSubmit, | ||||
| }: { | ||||
|   row: FileExplorerRender | ||||
|   onSubmit: () => void | ||||
| }) { | ||||
|   const inputRef = useRef<HTMLInputElement>(null) | ||||
|  | ||||
|   function handleRenameSubmit(e: React.KeyboardEvent<HTMLElement>) { | ||||
|     if (e.key !== 'Enter') { | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     // TODO: Do the renaming | ||||
|     // newName: inputRef.current?.value || fileOrDir.name || '', | ||||
|  | ||||
|     // To get out of the renaming state, without this the current file is still in renaming mode | ||||
|     onSubmit() | ||||
|   } | ||||
|  | ||||
|   function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) { | ||||
|     if (e.key === 'Escape') { | ||||
|       e.stopPropagation() | ||||
|       onSubmit() | ||||
|     } else if (e.key === 'Enter') { | ||||
|       // This is needed to prevent events to bubble up and the form to be submitted. | ||||
|       // (Alternatively the form could be changed into a div.) | ||||
|       // Bug without this: | ||||
|       // - open a parent folder (close and open if it's already open) | ||||
|       // - right click -> rename one of its children | ||||
|       // - give new name and press enter | ||||
|       // -> new name is not applied, old name is reverted | ||||
|       e.preventDefault() | ||||
|       e.stopPropagation() | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return ( | ||||
|     <form onKeyUp={handleRenameSubmit}> | ||||
|       <label> | ||||
|         <span className="sr-only">Rename file</span> | ||||
|         <input | ||||
|           data-testid="file-rename-field" | ||||
|           ref={inputRef} | ||||
|           type="text" | ||||
|           autoFocus | ||||
|           autoCapitalize="off" | ||||
|           autoCorrect="off" | ||||
|           placeholder={row.name} | ||||
|           className="w-full py-1 bg-transparent text-chalkboard-100 placeholder:text-chalkboard-70 dark:text-chalkboard-10 dark:placeholder:text-chalkboard-50 focus:outline-none focus:ring-0" | ||||
|           onKeyDown={handleKeyDown} | ||||
|           onBlur={onSubmit} | ||||
|         /> | ||||
|       </label> | ||||
|       <button className="sr-only" type="submit"> | ||||
|         Submit | ||||
|       </button> | ||||
|     </form> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Making div soup! | ||||
|  * A row is a folder or a file. | ||||
| @ -96,9 +204,11 @@ export const FileExplorer = ({ | ||||
| export const FileExplorerRowElement = ({ | ||||
|   row, | ||||
|   selectedRow, | ||||
|   renamingRow | ||||
| }: { | ||||
|   row: FileExplorerRender | ||||
|   selectedRow: FileExplorerEntry | null | ||||
|   renamingRow: FileExplorerRow | null | ||||
|   domLength: number | ||||
| }) => { | ||||
|   const isSelected = | ||||
| @ -163,50 +273,3 @@ export const FileExplorerRowElement = ({ | ||||
|     </div> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| function FileExplorerRowContextMenu({ | ||||
|   itemRef, | ||||
|   onRename, | ||||
|   onDelete, | ||||
|   onClone, | ||||
|   onOpenInNewWindow, | ||||
|   callback, | ||||
| }: FileExplorerRowContextMenuProps) { | ||||
|   const platform = usePlatform() | ||||
|   const metaKey = platform === 'macos' ? '⌘' : 'Ctrl' | ||||
|   return ( | ||||
|     <ContextMenu | ||||
|       menuTargetElement={itemRef} | ||||
|       callback={callback} | ||||
|       items={[ | ||||
|         <ContextMenuItem | ||||
|           data-testid="context-menu-rename" | ||||
|           onClick={onRename} | ||||
|           hotkey="Enter" | ||||
|         > | ||||
|           Rename | ||||
|         </ContextMenuItem>, | ||||
|         <ContextMenuItem | ||||
|           data-testid="context-menu-delete" | ||||
|           onClick={onDelete} | ||||
|           hotkey={metaKey + ' + Del'} | ||||
|         > | ||||
|           Delete | ||||
|         </ContextMenuItem>, | ||||
|         <ContextMenuItem | ||||
|           data-testid="context-menu-clone" | ||||
|           onClick={onClone} | ||||
|           hotkey="" | ||||
|         > | ||||
|           Clone | ||||
|         </ContextMenuItem>, | ||||
|         <ContextMenuItem | ||||
|           data-testid="context-menu-open-in-new-window" | ||||
|           onClick={onOpenInNewWindow} | ||||
|         > | ||||
|           Open in new window | ||||
|         </ContextMenuItem>, | ||||
|       ]} | ||||
|     /> | ||||
|   ) | ||||
| } | ||||
|  | ||||
| @ -23,11 +23,7 @@ const isFileExplorerEntryOpened = ( | ||||
|   rows: { [key: string]: boolean }, | ||||
|   entry: FileExplorerEntry | ||||
| ): boolean => { | ||||
|   const key = constructPath({ | ||||
|     parentPath: entry.parentPath, | ||||
|     name: entry.name, | ||||
|   }) | ||||
|   return rows[key] | ||||
|   return rows[entry.key] | ||||
| } | ||||
|  | ||||
| /** | ||||
| @ -52,6 +48,8 @@ export const ProjectExplorer = ({ | ||||
|   // -1 is the parent container, -2 is nothing is selected | ||||
|   const [activeIndex, setActiveIndex] = useState<number>(NOTHING_IS_SELECTED) | ||||
|   const [rowsToRender, setRowsToRender] = useState<FileExplorerRow[]>([]) | ||||
|   const [renamingRow, setRenamingRow] = useState<FileExplorerRow | null>(null) | ||||
|  | ||||
|   const fileExplorerContainer = useRef(null) | ||||
|   const openedRowsRef = useRef(openedRows) | ||||
|   const rowsToRenderRef = useRef(rowsToRender) | ||||
| @ -75,10 +73,7 @@ export const ProjectExplorer = ({ | ||||
|    */ | ||||
|   const onRowClickCallback = (file: FileExplorerEntry, domIndex: number) => { | ||||
|     const newOpenedRows = { ...openedRowsRef.current } | ||||
|     const key = constructPath({ | ||||
|       parentPath: file.parentPath, | ||||
|       name: file.name, | ||||
|     }) | ||||
|     const key = file.key | ||||
|     const value = openedRowsRef.current[key] | ||||
|     newOpenedRows[key] = !value | ||||
|     setOpenedRows(newOpenedRows) | ||||
| @ -127,7 +122,7 @@ export const ProjectExplorer = ({ | ||||
|  | ||||
|         const isOpen = | ||||
|           openedRows[ | ||||
|             constructPath({ parentPath: child.parentPath, name: child.name }) | ||||
|             child.key | ||||
|           ] | ||||
|         const render = | ||||
|           (openedRows[child.parentPath] || project.name === child.parentPath) && | ||||
| @ -155,10 +150,7 @@ export const ProjectExplorer = ({ | ||||
|           }, | ||||
|           rowOpen: () => { | ||||
|             const newOpenedRows = { ...openedRowsRef.current } | ||||
|             const key = constructPath({ | ||||
|               parentPath: child.parentPath, | ||||
|               name: child.name, | ||||
|             }) | ||||
|             const key = child.key | ||||
|             newOpenedRows[key] = true | ||||
|             setOpenedRows(newOpenedRows) | ||||
|           }, | ||||
| @ -182,6 +174,7 @@ export const ProjectExplorer = ({ | ||||
|     requestedRowsToRender.forEach((r, index) => { | ||||
|       r.rowContextMenu = () => { | ||||
|         setActiveIndex(index) | ||||
|         setRenamingRow(r) | ||||
|       } | ||||
|     }) | ||||
|  | ||||
| @ -219,10 +212,7 @@ export const ProjectExplorer = ({ | ||||
|           } else if (shouldCheckOpened && isEntryOpened) { | ||||
|             // close | ||||
|             const newOpenedRows = { ...openedRowsRef.current } | ||||
|             const key = constructPath({ | ||||
|               parentPath: focusedEntry.parentPath, | ||||
|               name: focusedEntry.name, | ||||
|             }) | ||||
|             const key = focusedEntry.key | ||||
|             const value = openedRowsRef.current[key] | ||||
|             newOpenedRows[key] = !value | ||||
|             setOpenedRows(newOpenedRows) | ||||
| @ -234,10 +224,7 @@ export const ProjectExplorer = ({ | ||||
|           } else if (shouldCheckOpened && !isEntryOpened) { | ||||
|             // open! | ||||
|             const newOpenedRows = { ...openedRowsRef.current } | ||||
|             const key = constructPath({ | ||||
|               parentPath: focusedEntry.parentPath, | ||||
|               name: focusedEntry.name, | ||||
|             }) | ||||
|             const key = focusedEntry.key | ||||
|             const value = openedRowsRef.current[key] | ||||
|             newOpenedRows[key] = !value | ||||
|             setOpenedRows(newOpenedRows) | ||||
| @ -265,10 +252,7 @@ export const ProjectExplorer = ({ | ||||
|           if (activeIndexRef.current >= STARTING_INDEX_TO_SELECT) { | ||||
|             // open close folder | ||||
|             const newOpenedRows = { ...openedRowsRef.current } | ||||
|             const key = constructPath({ | ||||
|               parentPath: focusedEntry.parentPath, | ||||
|               name: focusedEntry.name, | ||||
|             }) | ||||
|             const key = focusedEntry.key | ||||
|             const value = openedRowsRef.current[key] | ||||
|             newOpenedRows[key] = !value | ||||
|             setOpenedRows(newOpenedRows) | ||||
|  | ||||
| @ -7,6 +7,7 @@ export interface FileExplorerEntry extends FileEntry { | ||||
|   parentPath: string | ||||
|   level: number | ||||
|   index: number | ||||
|   key: string | ||||
| } | ||||
|  | ||||
| export interface FileExplorerRow extends FileExplorerEntry { | ||||
| @ -70,6 +71,10 @@ const flattenProjectHelper = ( | ||||
|     parentPath, | ||||
|     level, | ||||
|     index, | ||||
|     key: constructPath({ | ||||
|       parentPath, | ||||
|       name: f.name | ||||
|     }) | ||||
|   } | ||||
|   // keep track of the file once within the recursive list that will be built up | ||||
|   list.push(content) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user