fix: clear internal state across projects switching

This commit is contained in:
Kevin
2025-06-20 11:26:22 -05:00
parent 9fbcd1c758
commit e12f5ce2e0
3 changed files with 84 additions and 104 deletions

View File

@ -1,62 +0,0 @@
import { PATHS } from '@src/lib/paths'
import type { IndexLoaderData } from '@src/lib/types'
import { useRouteLoaderData } from 'react-router-dom'
import { addPlaceHoldersForNewFileAndFolder } from '@src/components/Explorer/utils'
import { ProjectExplorer } from '@src/components/Explorer/ProjectExplorer'
import { useFolders } from '@src/machines/systemIO/hooks'
import { useState, useEffect } from 'react'
import type { Project } from '@src/lib/project'
export const ModelingProjectExplorer = ({
createFilePressed,
createFolderPressed,
refreshExplorerPressed,
collapsePressed
}:{
createFilePressed:number
createFolderPressed: number
refreshExplorerPressed: number
collapsePressed: number
}) => {
const projects = useFolders()
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
const [theProject, setTheProject] = useState<Project | null>(null)
const { project } = loaderData
useEffect(() => {
// Have no idea why the project loader data doesn't have the children from the ls on disk
// That means it is a different object or cached incorrectly?
if (!project) {
return
}
// You need to find the real project in the storage from the loader information since the loader Project is not hydrated
const theProject = projects.find((p) => {
return p.name === project.name
})
if (!theProject) {
return
}
// Duplicate the state to not edit the raw data
const duplicated = JSON.parse(JSON.stringify(theProject))
addPlaceHoldersForNewFileAndFolder(duplicated.children, theProject.path)
setTheProject(duplicated)
}, [projects])
return (
<>
{theProject ? (
<ProjectExplorer
project={theProject}
createFilePressed={createFilePressed}
createFolderPressed={createFolderPressed}
refreshExplorerPressed={refreshExplorerPressed}
collapsePressed={collapsePressed}
></ProjectExplorer>
) : (
<div></div>
)}
</>
)
}

View File

@ -49,7 +49,7 @@ export const ProjectExplorer = ({
createFilePressed,
createFolderPressed,
refreshExplorerPressed,
collapsePressed
collapsePressed,
}: {
project: Project
createFilePressed: number
@ -75,7 +75,7 @@ export const ProjectExplorer = ({
const activeIndexRef = useRef(activeIndex)
const selectedRowRef = useRef(selectedRow)
const isRenamingRef = useRef(isRenaming)
const previousProject = useRef(project)
// 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<{
@ -87,13 +87,12 @@ export const ProjectExplorer = ({
* External state handlers since the callback logic lives here.
* If code wants to externall trigger creating a file pass in a new timestamp.
*/
useEffect(()=>{
useEffect(() => {
if (createFilePressed <= 0) {
return
}
const row =
rowsToRenderRef.current[activeIndexRef.current] || null
const row = rowsToRenderRef.current[activeIndexRef.current] || null
setFakeRow({ entry: row, isFile: true })
if (row?.key) {
// If the file tree had the folder opened make the new one open.
@ -101,24 +100,23 @@ export const ProjectExplorer = ({
newOpenedRows[row?.key] = true
setOpenedRows(newOpenedRows)
}
},[createFilePressed])
}, [createFilePressed])
useEffect(()=>{
useEffect(() => {
if (createFolderPressed <= 0) {
return
}
const row =
rowsToRenderRef.current[activeIndexRef.current] || null
setFakeRow({ entry: row, isFile: false })
if (row?.key) {
// If the file tree had the folder opened make the new one open.
const newOpenedRows = { ...openedRowsRef.current }
newOpenedRows[row?.key] = true
setOpenedRows(newOpenedRows)
}
const row = rowsToRenderRef.current[activeIndexRef.current] || null
setFakeRow({ entry: row, isFile: false })
if (row?.key) {
// If the file tree had the folder opened make the new one open.
const newOpenedRows = { ...openedRowsRef.current }
newOpenedRows[row?.key] = true
setOpenedRows(newOpenedRows)
}
}, [createFolderPressed])
useEffect(()=>{
useEffect(() => {
if (refreshExplorerPressed <= 0) {
return
}
@ -127,18 +125,14 @@ export const ProjectExplorer = ({
systemIOActor.send({
type: SystemIOMachineEvents.readFoldersFromProjectDirectory,
})
},[
refreshExplorerPressed
])
}, [refreshExplorerPressed])
useEffect(()=>{
if (collapsePressed <= 0) {
useEffect(() => {
if (collapsePressed <= 0) {
return
}
setOpenedRows({})
},[
collapsePressed
])
setOpenedRows({})
}, [collapsePressed])
const setSelectedRowWrapper = (row: FileExplorerEntry | null) => {
setSelectedRow(row)
@ -159,11 +153,18 @@ export const ProjectExplorer = ({
setActiveIndex(domIndex)
}
useEffect(() => {
// TODO What to do when a different project comes in? Clear old state.
// Clear openedRows
// Clear rowsToRender
// Clear selected information
useEffect(() => {
/**
* You are loading a new project, clear the internal state!
*/
if (previousProject.current.name !== project.name) {
setOpenedRows({})
setSelectedRow(null)
setActiveIndex(NOTHING_IS_SELECTED)
setRowsToRender([])
setContextMenuRow(null)
setIsRenaming(false)
}
// gotcha: sync state
openedRowsRef.current = openedRows
@ -404,6 +405,7 @@ export const ProjectExplorer = ({
setRowsToRender(requestedRowsToRender)
rowsToRenderRef.current = requestedRowsToRender
previousProject.current = project
}, [project, openedRows, fakeRow, activeIndex])
// Handle clicks and keyboard presses within the global DOM level

View File

@ -18,10 +18,18 @@ import type { useKclContext } from '@src/lang/KclProvider'
import { kclErrorsByFilename } from '@src/lang/errors'
import { editorManager } from '@src/lib/singletons'
import type { settingsMachine } from '@src/machines/settingsMachine'
import { ProjectExplorer} from '@src/components/Explorer/ProjectExplorer'
import { ModelingProjectExplorer } from '@src/components/Explorer/ModelingProjectExplorer'
import { ProjectExplorer } from '@src/components/Explorer/ProjectExplorer'
import { FileExplorerHeaderActions } from '@src/components/Explorer/FileExplorerHeaderActions'
import { PATHS } from '@src/lib/paths'
import type { IndexLoaderData } from '@src/lib/types'
import { useRouteLoaderData } from 'react-router-dom'
import { addPlaceHoldersForNewFileAndFolder } from '@src/components/Explorer/utils'
import { ProjectExplorer } from '@src/components/Explorer/ProjectExplorer'
import { useFolders } from '@src/machines/systemIO/hooks'
import { useState, useEffect } from 'react'
import type { Project } from '@src/lib/project'
export type SidebarType =
| 'code'
| 'debug'
@ -130,9 +138,36 @@ export const sidebarPanes: SidebarPane[] = [
icon: 'folder',
sidebarName: 'Project Files',
Content: (props: { id: SidebarType; onClose: () => void }) => {
const projects = useFolders()
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
const [theProject, setTheProject] = useState<Project | null>(null)
const { project } = loaderData
useEffect(() => {
// Have no idea why the project loader data doesn't have the children from the ls on disk
// That means it is a different object or cached incorrectly?
if (!project) {
return
}
// You need to find the real project in the storage from the loader information since the loader Project is not hydrated
const theProject = projects.find((p) => {
return p.name === project.name
})
if (!theProject) {
return
}
// Duplicate the state to not edit the raw data
const duplicated = JSON.parse(JSON.stringify(theProject))
addPlaceHoldersForNewFileAndFolder(duplicated.children, theProject.path)
setTheProject(duplicated)
}, [projects, loaderData])
const [createFilePressed, setCreateFilePressed] = useState<number>(0)
const [createFolderPressed, setCreateFolderPressed] = useState<number>(0)
const [refreshFolderPressed, setRefresFolderPressed] = useState<number>(0)
const [refreshExplorerPressed, setRefresFolderPressed] = useState<number>(0)
const [collapsePressed, setCollapsedPressed] = useState<number>(0)
return (
@ -140,7 +175,7 @@ export const sidebarPanes: SidebarPane[] = [
<ModelingPaneHeader
id={props.id}
icon="folder"
title={'huh'}
title={`${theProject?.name || ''}`}
Menu={
<FileExplorerHeaderActions
onCreateFile={() => {
@ -152,19 +187,24 @@ export const sidebarPanes: SidebarPane[] = [
onRefreshExplorer={() => {
setRefresFolderPressed(performance.now())
}}
onCollapseExplorer={() => {
onCollapseExplorer={() => {
setCollapsedPressed(performance.now())
}}
></FileExplorerHeaderActions>
}
onClose={props.onClose}
/>
<ModelingProjectExplorer
createFilePressed={createFilePressed}
createFolderPressed={createFolderPressed}
refreshExplorerPressed={refreshFolderPressed}
collapsePressed={collapsePressed}
/>
{theProject ? (
<ProjectExplorer
project={theProject}
createFilePressed={createFilePressed}
createFolderPressed={createFolderPressed}
refreshExplorerPressed={refreshExplorerPressed}
collapsePressed={collapsePressed}
></ProjectExplorer>
) : (
<div></div>
)}
</>
)
},