feat: sort was not sorting folders and files at each level, selection logic was not taking parent into account
This commit is contained in:
		| @ -18,6 +18,12 @@ interface FileExplorerRow extends FileExplorerEntry { | ||||
|   status?: ReactNode | ||||
|   isOpen: boolean | ||||
|   rowClicked: () => void | ||||
|   /** | ||||
|    * Fake file or folder rows are the placeholders for users to input a value | ||||
|    * and write that to disk to be read as a real one. | ||||
|    * they are placed in the DOM as if they are real but not from the source of truth | ||||
|    */ | ||||
|   isFake: boolean | ||||
| } | ||||
|  | ||||
| const StatusDot = () => { | ||||
| @ -71,10 +77,11 @@ const flattenProjectHelper = ( | ||||
|     return | ||||
|   } | ||||
|  | ||||
|   const sortedChildren = sortFilesAndDirectories(f.children.slice()) | ||||
|   // keep recursing down the children | ||||
|   for (let i = 0; i < f.children.length; i++) { | ||||
|   for (let i = 0; i < sortedChildren.length; i++) { | ||||
|     flattenProjectHelper( | ||||
|       f.children[i], | ||||
|       sortedChildren[i], | ||||
|       list, | ||||
|       constructPath({ parentPath: parentPath, name: f.name }), | ||||
|       level + 1 | ||||
| @ -105,6 +112,53 @@ const flattenProject = ( | ||||
|   return flattenTreeInOrder | ||||
| } | ||||
|  | ||||
| const insertFakeRowAtFirstPositionUnderParentAfterFolder = (fileExplorerEntries: FileExplorerEntry[], fakeRow: {path: string, isFile: boolean} | null) : void => { | ||||
|   if (!fakeRow) { | ||||
|     // no op | ||||
|     return | ||||
|   } | ||||
|  | ||||
|   let insertIndex = -1 | ||||
|   let foundEntry = null | ||||
|   for (let index = 0; index < fileExplorerEntries.length; index++) { | ||||
|     const entry = fileExplorerEntries[index] | ||||
|     const path = entry.parentPath | ||||
|     const isFolder = entry.children !== null | ||||
|     const nextEntry = index + 1 < fileExplorerEntries.length ? fileExplorerEntries[index+1] : null | ||||
|  | ||||
|     // Found first folder and my fake row is a folder | ||||
|     if (path === fakeRow.path && isFolder && !fakeRow.isFile) { | ||||
|       console.log('exited1') | ||||
|       insertIndex = index | ||||
|       foundEntry = entry | ||||
|       break | ||||
|     } | ||||
|  | ||||
|     if (fakeRow.isFile && (nextEntry === null || nextEntry.path !== fakeRow.path)) { | ||||
|       insertIndex = index | ||||
|       foundEntry = entry | ||||
|       console.log('inserting file', insertIndex) | ||||
|       break | ||||
|     } | ||||
|     // if (path === fakeRow.path && isFolder && fakeRow.isFile && nextEntry && nextEntry.path !== fakeRow.path) { | ||||
|     //   console.log('exited2') | ||||
|     //   insertIndex = index | ||||
|     //   foundEntry = entry | ||||
|     //   break | ||||
|     // } | ||||
|   } | ||||
|  | ||||
|   if (insertIndex >= 0 && foundEntry) { | ||||
|     const requestedEntry : FileExplorerEntry = { | ||||
|       ...foundEntry, | ||||
|       children: fakeRow.isFile ? null : [], | ||||
|       name: 'dog' | ||||
|     } | ||||
|     console.log(requestedEntry) | ||||
|     fileExplorerEntries.splice(insertIndex, 0, requestedEntry); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Render all the rows of the file explorer in linear layout in the DOM. | ||||
|  * each row is rendered one after another in the same parent DOM element | ||||
| @ -119,11 +173,13 @@ export const FileExplorer = ({ | ||||
|   openedRows, | ||||
|   selectedRow, | ||||
|   onRowClickCallback, | ||||
|   fakeRow | ||||
| }: { | ||||
|   parentProject: Project | ||||
|   openedRows: { [key: string]: boolean } | ||||
|   selectedRow: FileEntry | null | ||||
|   onRowClickCallback: (file: FileExplorerEntry) => void | ||||
|   fakeRow: {path: string, isFile: boolean} | null | ||||
| }) => { | ||||
|   // Wrap the FileEntry in a FileExplorerEntry to keep track for more metadata | ||||
|   let flattenedData: FileExplorerEntry[] = [] | ||||
| @ -131,8 +187,12 @@ export const FileExplorer = ({ | ||||
|   if (parentProject && parentProject.children) { | ||||
|     // moves all folders up and files down, files are sorted within folders | ||||
|     const sortedData = sortFilesAndDirectories(parentProject.children) | ||||
|     console.log(sortedData) | ||||
|     // pre order traversal of the tree | ||||
|     flattenedData = flattenProject(sortedData, parentProject.name) | ||||
|  | ||||
|     // insert fake row if one is present | ||||
|     // insertFakeRowAtFirstPositionUnderParentAfterFolder(flattenedData, fakeRow) | ||||
|   } | ||||
|  | ||||
|   const [rowsToRender, setRowsToRender] = useState<FileExplorerRow[]>([]) | ||||
| @ -180,13 +240,14 @@ export const FileExplorer = ({ | ||||
|           rowClicked: () => { | ||||
|             onRowClickCallback(child) | ||||
|           }, | ||||
|           isFake: false | ||||
|         } | ||||
|  | ||||
|         return row | ||||
|       }) || [] | ||||
|  | ||||
|     setRowsToRender(requestedRowsToRender) | ||||
|   }, [parentProject, openedRows]) | ||||
|   }, [parentProject, openedRows, fakeRow]) | ||||
|  | ||||
|   // Local state for selection and what is opened | ||||
|   // diff this against new Project value that comes in | ||||
| @ -212,12 +273,12 @@ export const FileExplorerRow = ({ | ||||
|   row, | ||||
|   selectedRow, | ||||
| }: { | ||||
|   row: any | ||||
|   selectedRow: any | ||||
|   row: FileExplorerRow | ||||
|   selectedRow: FileExplorerEntry | ||||
| }) => { | ||||
|   return ( | ||||
|     <div | ||||
|       className={`h-6 flex flex-row items-center text-xs ${row.name === selectedRow?.name ? 'bg-red-200' : ''}`} | ||||
|       className={`h-6 flex flex-row items-center text-xs ${row.name === selectedRow?.name && row.parentPath === selectedRow?.parentPath ? 'bg-red-200' : ''}`} | ||||
|       onClick={() => { | ||||
|         row.rowClicked() | ||||
|       }} | ||||
|  | ||||
| @ -6,10 +6,8 @@ import { | ||||
| import type { FileExplorerEntry } from '@src/components/Explorer/FileExplorer' | ||||
| import { FileExplorerHeaderActions } from '@src/components/Explorer/FileExplorerHeaderActions' | ||||
| import { useState } from 'react' | ||||
| import { | ||||
|   systemIOActor, | ||||
| } from '@src/lib/singletons' | ||||
| import {SystemIOMachineEvents} from "@src/machines/systemIO/utils" | ||||
| import { systemIOActor } from '@src/lib/singletons' | ||||
| import { SystemIOMachineEvents } from '@src/machines/systemIO/utils' | ||||
|  | ||||
| /** | ||||
|  * Wrap the header and the tree into a single component | ||||
| @ -29,7 +27,11 @@ export const ProjectExplorer = ({ | ||||
|   // cache the state of opened rows to allow nested rows to be opened if a parent one is closed | ||||
|   // when the parent opens the children will already be opened | ||||
|   const [openedRows, setOpenedRows] = useState<{ [key: string]: boolean }>({}) | ||||
|   const [selectedRow, setSelectedRow] = useState<FileEntry | null>(null) | ||||
|   const [selectedRow, setSelectedRow] = useState<FileExplorerEntry | null>(null) | ||||
|  | ||||
|   // fake row is used for new files or folders | ||||
|   // you should not be able to have multiple fake rows for creation | ||||
|   const [fakeRow, setFakeRow] = useState<{path: string, isFile: boolean} | null>(null) | ||||
|  | ||||
|   const onRowClickCallback = (file: FileExplorerEntry) => { | ||||
|     const newOpenedRows = { ...openedRows } | ||||
| @ -40,6 +42,7 @@ export const ProjectExplorer = ({ | ||||
|     const value = openedRows[key] | ||||
|     newOpenedRows[key] = !value | ||||
|     setOpenedRows(newOpenedRows) | ||||
|     console.log(file) | ||||
|     setSelectedRow(file) | ||||
|   } | ||||
|  | ||||
| @ -50,7 +53,12 @@ export const ProjectExplorer = ({ | ||||
|         <div className="h-6 flex flex-row gap-1"> | ||||
|           <FileExplorerHeaderActions | ||||
|             onCreateFile={() => { | ||||
|               console.log('onCreateFile TODO') | ||||
|               // Use the selected level within the file tree or the root level of the project | ||||
|               const folderPath = selectedRow?.parentPath ? constructPath({parentPath: selectedRow?.parentPath, name: selectedRow.name}) : null | ||||
|               const parentPath = selectedRow?.parentPath | ||||
|               const isFile = selectedRow?.children === null | ||||
|               const path = (isFile ? parentPath : folderPath) || project.name | ||||
|               setFakeRow({path, isFile}) | ||||
|             }} | ||||
|             onCreateFolder={() => { | ||||
|               console.log('onCreateFolder TODO') | ||||
| @ -75,6 +83,7 @@ export const ProjectExplorer = ({ | ||||
|             openedRows={openedRows} | ||||
|             selectedRow={selectedRow} | ||||
|             onRowClickCallback={onRowClickCallback} | ||||
|             fakeRow={fakeRow} | ||||
|           ></FileExplorer> | ||||
|         )} | ||||
|       </div> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user