diff --git a/src/Root.tsx b/src/Root.tsx index 249f7bd37..a538dfb80 100644 --- a/src/Root.tsx +++ b/src/Root.tsx @@ -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 ( -
- - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + ) } diff --git a/src/Router.tsx b/src/Router.tsx index c2836581d..b97a50b58 100644 --- a/src/Router.tsx +++ b/src/Router.tsx @@ -48,7 +48,7 @@ const createRouter = isDesktop() ? createHashRouter : createBrowserRouter const router = createRouter([ { id: PATHS.INDEX, - element: , + element: , children: [ { path: PATHS.INDEX, diff --git a/src/components/Providers/SystemIOProviderDesktop.tsx b/src/components/Providers/SystemIOProviderDesktop.tsx index 3cca036e3..42148b0a8 100644 --- a/src/components/Providers/SystemIOProviderDesktop.tsx +++ b/src/components/Providers/SystemIOProviderDesktop.tsx @@ -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 } diff --git a/src/machines/appMachine.ts b/src/machines/appMachine.ts index 61b4932cc..31d8aa616 100644 --- a/src/machines/appMachine.ts +++ b/src/machines/appMachine.ts @@ -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 diff --git a/src/machines/systemIO/hooks.ts b/src/machines/systemIO/hooks.ts new file mode 100644 index 000000000..99c67d7c1 --- /dev/null +++ b/src/machines/systemIO/hooks.ts @@ -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) diff --git a/src/machines/systemIO/systemIOMachine.test.ts b/src/machines/systemIO/systemIOMachine.test.ts index c00ebdb1c..36add501d 100644 --- a/src/machines/systemIO/systemIOMachine.test.ts +++ b/src/machines/systemIO/systemIOMachine.test.ts @@ -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) + }) + }) }) }) diff --git a/src/machines/systemIO/systemIOMachine.ts b/src/machines/systemIO/systemIOMachine.ts index 2ecd36f44..cf8433232 100644 --- a/src/machines/systemIO/systemIOMachine.ts +++ b/src/machines/systemIO/systemIOMachine.ts @@ -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]: { diff --git a/src/machines/systemIO/utils.ts b/src/machines/systemIO/utils.ts index 23d394217..8baaee263 100644 --- a/src/machines/systemIO/utils.ts +++ b/src/machines/systemIO/utils.ts @@ -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 = '' diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index 385251f7f..d0104e7ba 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -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(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, 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 your Projects... ) : ( <>