chore: first attempt of purging projects context provider
This commit is contained in:
33
src/Root.tsx
33
src/Root.tsx
@ -2,7 +2,6 @@ import { AppStateProvider } from '@src/AppState'
|
|||||||
import LspProvider from '@src/components/LspProvider'
|
import LspProvider from '@src/components/LspProvider'
|
||||||
import { MachineManagerProvider } from '@src/components/MachineManagerProvider'
|
import { MachineManagerProvider } from '@src/components/MachineManagerProvider'
|
||||||
import { OpenInDesktopAppHandler } from '@src/components/OpenInDesktopAppHandler'
|
import { OpenInDesktopAppHandler } from '@src/components/OpenInDesktopAppHandler'
|
||||||
import { ProjectsContextProvider } from '@src/components/ProjectsContextProvider'
|
|
||||||
import { SystemIOMachineLogicListener } from '@src/components/Providers/SystemIOProviderDesktop'
|
import { SystemIOMachineLogicListener } from '@src/components/Providers/SystemIOProviderDesktop'
|
||||||
import { RouteProvider } from '@src/components/RouteProvider'
|
import { RouteProvider } from '@src/components/RouteProvider'
|
||||||
import { KclContextProvider } from '@src/lang/KclProvider'
|
import { KclContextProvider } from '@src/lang/KclProvider'
|
||||||
@ -17,24 +16,20 @@ function RootLayout() {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
<div>
|
<OpenInDesktopAppHandler>
|
||||||
<OpenInDesktopAppHandler>
|
<RouteProvider>
|
||||||
<RouteProvider>
|
<LspProvider>
|
||||||
<LspProvider>
|
<KclContextProvider>
|
||||||
<ProjectsContextProvider>
|
<AppStateProvider>
|
||||||
<KclContextProvider>
|
<MachineManagerProvider>
|
||||||
<AppStateProvider>
|
<SystemIOMachineLogicListener />
|
||||||
<MachineManagerProvider>
|
<Outlet />
|
||||||
<SystemIOMachineLogicListener />
|
</MachineManagerProvider>
|
||||||
<Outlet />
|
</AppStateProvider>
|
||||||
</MachineManagerProvider>
|
</KclContextProvider>
|
||||||
</AppStateProvider>
|
</LspProvider>
|
||||||
</KclContextProvider>
|
</RouteProvider>
|
||||||
</ProjectsContextProvider>
|
</OpenInDesktopAppHandler>
|
||||||
</LspProvider>
|
|
||||||
</RouteProvider>
|
|
||||||
</OpenInDesktopAppHandler>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ const createRouter = isDesktop() ? createHashRouter : createBrowserRouter
|
|||||||
const router = createRouter([
|
const router = createRouter([
|
||||||
{
|
{
|
||||||
id: PATHS.INDEX,
|
id: PATHS.INDEX,
|
||||||
element: <RootLayout />,
|
element: <RootLayout/>,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: PATHS.INDEX,
|
path: PATHS.INDEX,
|
||||||
|
@ -1,20 +1,24 @@
|
|||||||
import { PATHS } from '@src/lib/paths'
|
import { PATHS } from '@src/lib/paths'
|
||||||
import { systemIOActor } from '@src/machines/appMachine'
|
import { systemIOActor, useSettings } from '@src/machines/appMachine'
|
||||||
import { useSelector } from '@xstate/react'
|
import {
|
||||||
|
useProjectDirectoryPath,
|
||||||
|
useRequestedFileName,
|
||||||
|
useRequestedProjectName,
|
||||||
|
useState as useSystemIOState,
|
||||||
|
} from '@src/machines/systemIO/hooks'
|
||||||
|
import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
export const useRequestedProjectName = () =>
|
import { projectsCommandBarConfig } from '@src/lib/commandBarConfigs/projectsCommandConfig'
|
||||||
useSelector(systemIOActor, (state) => state.context.requestedProjectName)
|
import useStateMachineCommands from '@src/hooks/useStateMachineCommands'
|
||||||
export const useRequestedFileName = () =>
|
|
||||||
useSelector(systemIOActor, (state) => state.context.requestedFileName)
|
|
||||||
export const useProjectDirectoryPath = () =>
|
|
||||||
useSelector(systemIOActor, (state) => state.context.projectDirectoryPath)
|
|
||||||
|
|
||||||
export function SystemIOMachineLogicListener() {
|
export function SystemIOMachineLogicListener() {
|
||||||
const requestedProjectName = useRequestedProjectName()
|
const requestedProjectName = useRequestedProjectName()
|
||||||
const requestedFileName = useRequestedFileName()
|
const requestedFileName = useRequestedFileName()
|
||||||
const projectDirectoryPath = useProjectDirectoryPath()
|
const projectDirectoryPath = useProjectDirectoryPath()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const settings = useSettings()
|
||||||
|
const state = useSystemIOState()
|
||||||
|
|
||||||
// Handle global project name navigation
|
// Handle global project name navigation
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -46,5 +50,27 @@ export function SystemIOMachineLogicListener() {
|
|||||||
navigate(requestedPath)
|
navigate(requestedPath)
|
||||||
}, [requestedFileName])
|
}, [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
|
return null
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { useSelector } from '@xstate/react'
|
import { useSelector } from '@xstate/react'
|
||||||
import { createActor, setup, spawnChild } from 'xstate'
|
import { createActor, setup, spawnChild } from 'xstate'
|
||||||
|
|
||||||
import { readAppSettingsFile } from '@src/lib/desktop'
|
|
||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
import { createSettings } from '@src/lib/settings/initialSettings'
|
import { createSettings } from '@src/lib/settings/initialSettings'
|
||||||
import { reportRejection } from '@src/lib/trap'
|
|
||||||
import { authMachine } from '@src/machines/authMachine'
|
import { authMachine } from '@src/machines/authMachine'
|
||||||
import type { EngineStreamActor } from '@src/machines/engineStreamMachine'
|
import type { EngineStreamActor } from '@src/machines/engineStreamMachine'
|
||||||
import {
|
import {
|
||||||
@ -15,7 +13,6 @@ import { ACTOR_IDS } from '@src/machines/machineConstants'
|
|||||||
import { settingsMachine } from '@src/machines/settingsMachine'
|
import { settingsMachine } from '@src/machines/settingsMachine'
|
||||||
import { systemIOMachineDesktop } from '@src/machines/systemIO/systemIOMachineDesktop'
|
import { systemIOMachineDesktop } from '@src/machines/systemIO/systemIOMachineDesktop'
|
||||||
import { systemIOMachineWeb } from '@src/machines/systemIO/systemIOMachineWeb'
|
import { systemIOMachineWeb } from '@src/machines/systemIO/systemIOMachineWeb'
|
||||||
import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
|
|
||||||
const { AUTH, SETTINGS, SYSTEM_IO, ENGINE_STREAM } = ACTOR_IDS
|
const { AUTH, SETTINGS, SYSTEM_IO, ENGINE_STREAM } = ACTOR_IDS
|
||||||
const appMachineActors = {
|
const appMachineActors = {
|
||||||
[AUTH]: authMachine,
|
[AUTH]: authMachine,
|
||||||
@ -85,24 +82,6 @@ export const useSettings = () =>
|
|||||||
// TODO: Debugging
|
// TODO: Debugging
|
||||||
export const systemIOActor = appActor.getSnapshot().children.systemIO!
|
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
|
window.systemIOActor = systemIOActor
|
||||||
export const engineStreamActor = appActor.system.get(
|
export const engineStreamActor = appActor.system.get(
|
||||||
ENGINE_STREAM
|
ENGINE_STREAM
|
||||||
|
11
src/machines/systemIO/hooks.ts
Normal file
11
src/machines/systemIO/hooks.ts
Normal 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)
|
@ -62,5 +62,17 @@ describe('systemIOMachine - XState', () => {
|
|||||||
expect(context.projectDirectoryPath).toBe(kclSamplesPath)
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -58,6 +58,10 @@ export const systemIOMachine = setup({
|
|||||||
requestedFileName: string
|
requestedFileName: string
|
||||||
requestedCode: string
|
requestedCode: string
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: SystemIOMachineEvents.setDefaultProjectFolderName
|
||||||
|
data: { requestedDefaultProjectFolderName: string }
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
@ -91,6 +95,12 @@ export const systemIOMachine = setup({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
[SystemIOMachineActions.setDefaultProjectFolderName]: assign({
|
||||||
|
defaultProjectFolderName: ({ event }) => {
|
||||||
|
assertEvent(event, SystemIOMachineEvents.setDefaultProjectFolderName)
|
||||||
|
return event.data.requestedDefaultProjectFolderName
|
||||||
|
},
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
actors: {
|
actors: {
|
||||||
[SystemIOMachineActors.readFoldersFromProjectDirectory]: fromPromise(
|
[SystemIOMachineActors.readFoldersFromProjectDirectory]: fromPromise(
|
||||||
@ -133,7 +143,8 @@ export const systemIOMachine = setup({
|
|||||||
requestedProjectName: string
|
requestedProjectName: string
|
||||||
requestedFileName: string
|
requestedFileName: string
|
||||||
requestedCode: string
|
requestedCode: string
|
||||||
}
|
|
||||||
|
}
|
||||||
}) => {}
|
}) => {}
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -182,6 +193,9 @@ export const systemIOMachine = setup({
|
|||||||
[SystemIOMachineEvents.createKCLFile]: {
|
[SystemIOMachineEvents.createKCLFile]: {
|
||||||
target: SystemIOMachineStates.creatingKCLFile,
|
target: SystemIOMachineStates.creatingKCLFile,
|
||||||
},
|
},
|
||||||
|
[SystemIOMachineEvents.setDefaultProjectFolderName]: {
|
||||||
|
actions: [SystemIOMachineActions.setDefaultProjectFolderName],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[SystemIOMachineStates.readingFolders]: {
|
[SystemIOMachineStates.readingFolders]: {
|
||||||
|
@ -32,6 +32,7 @@ export enum SystemIOMachineEvents {
|
|||||||
renameProject = 'rename project',
|
renameProject = 'rename project',
|
||||||
deleteProject = 'delete project',
|
deleteProject = 'delete project',
|
||||||
createKCLFile = 'create kcl file',
|
createKCLFile = 'create kcl file',
|
||||||
|
setDefaultProjectFolderName = 'set default project folder name',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SystemIOMachineActions {
|
export enum SystemIOMachineActions {
|
||||||
@ -39,6 +40,7 @@ export enum SystemIOMachineActions {
|
|||||||
setProjectDirectoryPath = 'set project directory path',
|
setProjectDirectoryPath = 'set project directory path',
|
||||||
setRequestedProjectName = 'set requested project name',
|
setRequestedProjectName = 'set requested project name',
|
||||||
setRequestedFileName = 'set requested file name',
|
setRequestedFileName = 'set requested file name',
|
||||||
|
setDefaultProjectFolderName = 'set default project folder name',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NO_PROJECT_DIRECTORY = ''
|
export const NO_PROJECT_DIRECTORY = ''
|
||||||
|
@ -15,7 +15,6 @@ import {
|
|||||||
} from '@src/components/ProjectSearchBar'
|
} from '@src/components/ProjectSearchBar'
|
||||||
import { useCreateFileLinkQuery } from '@src/hooks/useCreateFileLinkQueryWatcher'
|
import { useCreateFileLinkQuery } from '@src/hooks/useCreateFileLinkQueryWatcher'
|
||||||
import { useMenuListener } from '@src/hooks/useMenu'
|
import { useMenuListener } from '@src/hooks/useMenu'
|
||||||
import { useProjectsContext } from '@src/hooks/useProjectsContext'
|
|
||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
import { PATHS } from '@src/lib/paths'
|
import { PATHS } from '@src/lib/paths'
|
||||||
import { markOnce } from '@src/lib/performance'
|
import { markOnce } from '@src/lib/performance'
|
||||||
@ -27,14 +26,22 @@ import {
|
|||||||
getSortIcon,
|
getSortIcon,
|
||||||
} from '@src/lib/sorting'
|
} from '@src/lib/sorting'
|
||||||
import { reportRejection } from '@src/lib/trap'
|
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 { 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'
|
import type { WebContentSendPayload } from '@src/menu/channels'
|
||||||
|
|
||||||
// This route only opens in the desktop context for now,
|
// This route only opens in the desktop context for now,
|
||||||
// as defined in Router.tsx, so we can use the desktop APIs and types.
|
// as defined in Router.tsx, so we can use the desktop APIs and types.
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
const { state, send } = useProjectsContext()
|
const state = useSystemIOState()
|
||||||
const [readWriteProjectDir, setReadWriteProjectDir] = useState<{
|
const [readWriteProjectDir, setReadWriteProjectDir] = useState<{
|
||||||
value: boolean
|
value: boolean
|
||||||
error: unknown
|
error: unknown
|
||||||
@ -156,40 +163,13 @@ const Home = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
|
const projects = useFolders()
|
||||||
const projects = state?.context.projects ?? []
|
|
||||||
const [searchParams, setSearchParams] = useSearchParams()
|
const [searchParams, setSearchParams] = useSearchParams()
|
||||||
const { searchResults, query, setQuery } = useProjectSearch(projects)
|
const { searchResults, query, setQuery } = useProjectSearch(projects)
|
||||||
const sort = searchParams.get('sort_by') ?? 'modified:desc'
|
const sort = searchParams.get('sort_by') ?? 'modified:desc'
|
||||||
|
|
||||||
const isSortByModified = sort?.includes('modified') || !sort || sort === null
|
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(
|
async function handleRenameProject(
|
||||||
e: FormEvent<HTMLFormElement>,
|
e: FormEvent<HTMLFormElement>,
|
||||||
project: Project
|
project: Project
|
||||||
@ -204,17 +184,20 @@ const Home = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newProjectName !== project.name) {
|
if (newProjectName !== project.name) {
|
||||||
send({
|
systemIOActor.send({
|
||||||
type: 'Rename project',
|
type: SystemIOMachineEvents.renameProject,
|
||||||
data: { oldName: project.name, newName: newProjectName as string },
|
data: {
|
||||||
|
requestedProjectName: String(newProjectName),
|
||||||
|
projectName: project.name,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleDeleteProject(project: Project) {
|
async function handleDeleteProject(project: Project) {
|
||||||
send({
|
systemIOActor.send({
|
||||||
type: 'Delete project',
|
type: SystemIOMachineEvents.deleteProject,
|
||||||
data: { name: project.name || '' },
|
data: { requestedProjectName: project.name },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/** Type narrowing function of unknown error to a string */
|
/** Type narrowing function of unknown error to a string */
|
||||||
@ -345,7 +328,7 @@ const Home = () => {
|
|||||||
data-testid="home-section"
|
data-testid="home-section"
|
||||||
className="flex-1 overflow-y-auto pr-2 pb-24"
|
className="flex-1 overflow-y-auto pr-2 pb-24"
|
||||||
>
|
>
|
||||||
{state?.matches('Reading projects') ? (
|
{state?.matches(SystemIOMachineStates.readingFolders) ? (
|
||||||
<Loading>Loading your Projects...</Loading>
|
<Loading>Loading your Projects...</Loading>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
Reference in New Issue
Block a user