chore: first attempt of purging projects context provider

This commit is contained in:
Kevin Nadro
2025-04-15 10:30:52 -06:00
parent 5ac504d000
commit 0a2e668ee4
9 changed files with 110 additions and 88 deletions

View File

@ -2,7 +2,6 @@ import { AppStateProvider } from '@src/AppState'
import LspProvider from '@src/components/LspProvider'
import { MachineManagerProvider } from '@src/components/MachineManagerProvider'
import { OpenInDesktopAppHandler } from '@src/components/OpenInDesktopAppHandler'
import { ProjectsContextProvider } from '@src/components/ProjectsContextProvider'
import { SystemIOMachineLogicListener } from '@src/components/Providers/SystemIOProviderDesktop'
import { RouteProvider } from '@src/components/RouteProvider'
import { KclContextProvider } from '@src/lang/KclProvider'
@ -17,24 +16,20 @@ function RootLayout() {
}
}, [])
return (
<div>
<OpenInDesktopAppHandler>
<RouteProvider>
<LspProvider>
<ProjectsContextProvider>
<KclContextProvider>
<AppStateProvider>
<MachineManagerProvider>
<SystemIOMachineLogicListener />
<Outlet />
</MachineManagerProvider>
</AppStateProvider>
</KclContextProvider>
</ProjectsContextProvider>
</LspProvider>
</RouteProvider>
</OpenInDesktopAppHandler>
</div>
<OpenInDesktopAppHandler>
<RouteProvider>
<LspProvider>
<KclContextProvider>
<AppStateProvider>
<MachineManagerProvider>
<SystemIOMachineLogicListener />
<Outlet />
</MachineManagerProvider>
</AppStateProvider>
</KclContextProvider>
</LspProvider>
</RouteProvider>
</OpenInDesktopAppHandler>
)
}

View File

@ -48,7 +48,7 @@ const createRouter = isDesktop() ? createHashRouter : createBrowserRouter
const router = createRouter([
{
id: PATHS.INDEX,
element: <RootLayout />,
element: <RootLayout/>,
children: [
{
path: PATHS.INDEX,

View File

@ -1,20 +1,24 @@
import { PATHS } from '@src/lib/paths'
import { systemIOActor } from '@src/machines/appMachine'
import { useSelector } from '@xstate/react'
import { systemIOActor, useSettings } from '@src/machines/appMachine'
import {
useProjectDirectoryPath,
useRequestedFileName,
useRequestedProjectName,
useState as useSystemIOState,
} from '@src/machines/systemIO/hooks'
import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
export const useRequestedProjectName = () =>
useSelector(systemIOActor, (state) => state.context.requestedProjectName)
export const useRequestedFileName = () =>
useSelector(systemIOActor, (state) => state.context.requestedFileName)
export const useProjectDirectoryPath = () =>
useSelector(systemIOActor, (state) => state.context.projectDirectoryPath)
import { projectsCommandBarConfig } from '@src/lib/commandBarConfigs/projectsCommandConfig'
import useStateMachineCommands from '@src/hooks/useStateMachineCommands'
export function SystemIOMachineLogicListener() {
const requestedProjectName = useRequestedProjectName()
const requestedFileName = useRequestedFileName()
const projectDirectoryPath = useProjectDirectoryPath()
const navigate = useNavigate()
const settings = useSettings()
const state = useSystemIOState()
// Handle global project name navigation
useEffect(() => {
@ -46,5 +50,27 @@ export function SystemIOMachineLogicListener() {
navigate(requestedPath)
}, [requestedFileName])
// Reload all folders when the project directory path changes
useEffect(() => {
systemIOActor.send({
type: SystemIOMachineEvents.setProjectDirectoryPath,
data: {
requestedProjectDirectoryPath:
settings.app.projectDirectory.current || '',
},
})
}, [settings.app.projectDirectory.current])
// Implement setting the default project folder name
useEffect(() => {
systemIOActor.send({
type: SystemIOMachineEvents.setDefaultProjectFolderName,
data: {
requestedDefaultProjectFolderName:
settings.projects.defaultProjectName.current || '',
},
})
}, [settings.projects.defaultProjectName.current])
return null
}

View File

@ -1,10 +1,8 @@
import { useSelector } from '@xstate/react'
import { createActor, setup, spawnChild } from 'xstate'
import { readAppSettingsFile } from '@src/lib/desktop'
import { isDesktop } from '@src/lib/isDesktop'
import { createSettings } from '@src/lib/settings/initialSettings'
import { reportRejection } from '@src/lib/trap'
import { authMachine } from '@src/machines/authMachine'
import type { EngineStreamActor } from '@src/machines/engineStreamMachine'
import {
@ -15,7 +13,6 @@ import { ACTOR_IDS } from '@src/machines/machineConstants'
import { settingsMachine } from '@src/machines/settingsMachine'
import { systemIOMachineDesktop } from '@src/machines/systemIO/systemIOMachineDesktop'
import { systemIOMachineWeb } from '@src/machines/systemIO/systemIOMachineWeb'
import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
const { AUTH, SETTINGS, SYSTEM_IO, ENGINE_STREAM } = ACTOR_IDS
const appMachineActors = {
[AUTH]: authMachine,
@ -85,24 +82,6 @@ export const useSettings = () =>
// TODO: Debugging
export const systemIOActor = appActor.getSnapshot().children.systemIO!
async function initializeActors() {
if (isDesktop()) {
const appSettings = await readAppSettingsFile()
const projectDirectorySettting = appSettings.settings?.project?.directory
systemIOActor.send({
type: SystemIOMachineEvents.setProjectDirectoryPath,
data: {
requestedProjectDirectoryPath: projectDirectorySettting || '',
},
})
systemIOActor.send({
type: SystemIOMachineEvents.readFoldersFromProjectDirectory,
})
}
}
initializeActors().catch(reportRejection)
window.systemIOActor = systemIOActor
export const engineStreamActor = appActor.system.get(
ENGINE_STREAM

View File

@ -0,0 +1,11 @@
import { systemIOActor } from '@src/machines/appMachine'
import { useSelector } from '@xstate/react'
export const useRequestedProjectName = () =>
useSelector(systemIOActor, (state) => state.context.requestedProjectName)
export const useRequestedFileName = () =>
useSelector(systemIOActor, (state) => state.context.requestedFileName)
export const useProjectDirectoryPath = () =>
useSelector(systemIOActor, (state) => state.context.projectDirectoryPath)
export const useFolders = () =>
useSelector(systemIOActor, (state) => state.context.folders)
export const useState = () => useSelector(systemIOActor, (state) => state)

View File

@ -62,5 +62,17 @@ describe('systemIOMachine - XState', () => {
expect(context.projectDirectoryPath).toBe(kclSamplesPath)
})
})
describe('when setting default project folder name', () => {
it('should set a new default project folder name', async () => {
const expected = 'coolcoolcoolProjectName'
const actor = createActor(systemIOMachineDesktop).start()
actor.send({
type: SystemIOMachineEvents.setDefaultProjectFolderName,
data: { requestedDefaultProjectFolderName: expected },
})
let context = actor.getSnapshot().context
expect(context.defaultProjectFolderName).toBe(expected)
})
})
})
})

View File

@ -58,6 +58,10 @@ export const systemIOMachine = setup({
requestedFileName: string
requestedCode: string
}
}
| {
type: SystemIOMachineEvents.setDefaultProjectFolderName
data: { requestedDefaultProjectFolderName: string }
},
},
actions: {
@ -91,6 +95,12 @@ export const systemIOMachine = setup({
}
},
}),
[SystemIOMachineActions.setDefaultProjectFolderName]: assign({
defaultProjectFolderName: ({ event }) => {
assertEvent(event, SystemIOMachineEvents.setDefaultProjectFolderName)
return event.data.requestedDefaultProjectFolderName
},
}),
},
actors: {
[SystemIOMachineActors.readFoldersFromProjectDirectory]: fromPromise(
@ -133,7 +143,8 @@ export const systemIOMachine = setup({
requestedProjectName: string
requestedFileName: string
requestedCode: string
}
}
}) => {}
),
},
@ -182,6 +193,9 @@ export const systemIOMachine = setup({
[SystemIOMachineEvents.createKCLFile]: {
target: SystemIOMachineStates.creatingKCLFile,
},
[SystemIOMachineEvents.setDefaultProjectFolderName]: {
actions: [SystemIOMachineActions.setDefaultProjectFolderName],
},
},
},
[SystemIOMachineStates.readingFolders]: {

View File

@ -32,6 +32,7 @@ export enum SystemIOMachineEvents {
renameProject = 'rename project',
deleteProject = 'delete project',
createKCLFile = 'create kcl file',
setDefaultProjectFolderName = 'set default project folder name',
}
export enum SystemIOMachineActions {
@ -39,6 +40,7 @@ export enum SystemIOMachineActions {
setProjectDirectoryPath = 'set project directory path',
setRequestedProjectName = 'set requested project name',
setRequestedFileName = 'set requested file name',
setDefaultProjectFolderName = 'set default project folder name',
}
export const NO_PROJECT_DIRECTORY = ''

View File

@ -15,7 +15,6 @@ import {
} from '@src/components/ProjectSearchBar'
import { useCreateFileLinkQuery } from '@src/hooks/useCreateFileLinkQueryWatcher'
import { useMenuListener } from '@src/hooks/useMenu'
import { useProjectsContext } from '@src/hooks/useProjectsContext'
import { isDesktop } from '@src/lib/isDesktop'
import { PATHS } from '@src/lib/paths'
import { markOnce } from '@src/lib/performance'
@ -27,14 +26,22 @@ import {
getSortIcon,
} from '@src/lib/sorting'
import { reportRejection } from '@src/lib/trap'
import { authActor, useSettings } from '@src/machines/appMachine'
import { authActor, systemIOActor, useSettings } from '@src/machines/appMachine'
import { commandBarActor } from '@src/machines/commandBarMachine'
import {
useFolders,
useState as useSystemIOState,
} from '@src/machines/systemIO/hooks'
import {
SystemIOMachineEvents,
SystemIOMachineStates,
} from '@src/machines/systemIO/utils'
import type { WebContentSendPayload } from '@src/menu/channels'
// This route only opens in the desktop context for now,
// as defined in Router.tsx, so we can use the desktop APIs and types.
const Home = () => {
const { state, send } = useProjectsContext()
const state = useSystemIOState()
const [readWriteProjectDir, setReadWriteProjectDir] = useState<{
value: boolean
error: unknown
@ -156,40 +163,13 @@ const Home = () => {
}
)
const ref = useRef<HTMLDivElement>(null)
const projects = state?.context.projects ?? []
const projects = useFolders()
const [searchParams, setSearchParams] = useSearchParams()
const { searchResults, query, setQuery } = useProjectSearch(projects)
const sort = searchParams.get('sort_by') ?? 'modified:desc'
const isSortByModified = sort?.includes('modified') || !sort || sort === null
// Update the default project name and directory in the home machine
// when the settings change
useEffect(() => {
send({
type: 'assign',
data: {
defaultProjectName: settings.projects.defaultProjectName.current,
defaultDirectory: settings.app.projectDirectory.current,
},
})
// Must be a truthy string, not '' or null or undefined
if (settings.app.projectDirectory.current) {
window.electron
.canReadWriteDirectory(settings.app.projectDirectory.current)
.then((res) => {
setReadWriteProjectDir(res)
})
.catch(reportRejection)
}
}, [
settings.app.projectDirectory.current,
settings.projects.defaultProjectName.current,
send,
])
async function handleRenameProject(
e: FormEvent<HTMLFormElement>,
project: Project
@ -204,17 +184,20 @@ const Home = () => {
}
if (newProjectName !== project.name) {
send({
type: 'Rename project',
data: { oldName: project.name, newName: newProjectName as string },
systemIOActor.send({
type: SystemIOMachineEvents.renameProject,
data: {
requestedProjectName: String(newProjectName),
projectName: project.name,
},
})
}
}
async function handleDeleteProject(project: Project) {
send({
type: 'Delete project',
data: { name: project.name || '' },
systemIOActor.send({
type: SystemIOMachineEvents.deleteProject,
data: { requestedProjectName: project.name },
})
}
/** Type narrowing function of unknown error to a string */
@ -345,7 +328,7 @@ const Home = () => {
data-testid="home-section"
className="flex-1 overflow-y-auto pr-2 pb-24"
>
{state?.matches('Reading projects') ? (
{state?.matches(SystemIOMachineStates.readingFolders) ? (
<Loading>Loading your Projects...</Loading>
) : (
<>