fix: new structure for web vs desktop vs react machine provider code

This commit is contained in:
Kevin Nadro
2025-04-07 13:27:34 -05:00
parent 9d673d1903
commit 5d0530257c
8 changed files with 194 additions and 3 deletions

View File

@ -5,13 +5,16 @@ import { createSettings } from '@src/lib/settings/initialSettings'
import { authMachine } from '@src/machines/authMachine' import { authMachine } from '@src/machines/authMachine'
import { ACTOR_IDS } from '@src/machines/machineConstants' import { ACTOR_IDS } from '@src/machines/machineConstants'
import { settingsMachine } from '@src/machines/settingsMachine' import { settingsMachine } from '@src/machines/settingsMachine'
import { systemIOMachine, SystemIOMachineEvents } from "@src/machines/systemIOMachine" import { SystemIOMachineEvents } from "@src/machines/systemIO/utils"
import { systemIOMachineWeb} from "@src/machines/systemIO/systemIOMachineWeb"
import { systemIOMachineDesktop} from "@src/machines/systemIO/systemIOMachineDesktop"
import { systemIOMachine} from "@src/machines/systemIO/systemIOMachine"
const { AUTH, SETTINGS, SYSTEM_IO } = ACTOR_IDS const { AUTH, SETTINGS, SYSTEM_IO } = ACTOR_IDS
const appMachineActors = { const appMachineActors = {
[AUTH]: authMachine, [AUTH]: authMachine,
[SETTINGS]: settingsMachine, [SETTINGS]: settingsMachine,
[SYSTEM_IO]: systemIOMachine [SYSTEM_IO]: systemIOMachineDesktop
} as const } as const
const appMachine = setup({ const appMachine = setup({

View File

@ -0,0 +1,87 @@
import { setup, fromPromise, assign, assertEvent} from 'xstate'
import { DEFAULT_PROJECT_NAME } from "@src/lib/constants"
import type { Project } from '@src/lib/project'
import {SystemIOMachineEvents, SystemIOMachineActions, SystemIOMachineActors, SystemIOMachineStates, NO_PROJECT_DIRECTORY, SystemIOContext} from "@src/machines/systemIO/utils"
/**
* Handles any system level I/O for folders and files
* This machine will be initializes once within the applications runtime
* and exist for the entire life cycle of the application and able to be access
* at a global level.
*/
export const systemIOMachine = setup({
types: {
context: {} as SystemIOContext,
events: {} as
| { type: SystemIOMachineEvents.readFoldersFromProjectDirectory; data: {} }
| { type: SystemIOMachineEvents.done_readFoldersFromProjectDirectory; data: {}, output: Project[] }
| { type: SystemIOMachineEvents.setProjectDirectoryPath; data: {requestedProjectDirectoryPath: string}}
},
actions: {
[SystemIOMachineActions.setFolders]: assign({
folders:({event})=>{
assertEvent(event, SystemIOMachineEvents.done_readFoldersFromProjectDirectory)
return event.output
}
}),
[SystemIOMachineActions.setProjectDirectoryPath]: assign({
projectDirectoryPath:({event})=>{
assertEvent(event, SystemIOMachineEvents.setProjectDirectoryPath)
return event.data.requestedProjectDirectoryPath
}
})
},
actors: {
[SystemIOMachineActors.readFoldersFromProjectDirectory]: fromPromise(async ({input:context}:{input:SystemIOContext}) => {
return []
}),
}
}).createMachine({
initial:SystemIOMachineStates.idle,
// Remember, this machine and change its projectDirectory at any point
// '' will be no project directory, aka clear this machine out!
// To be the aboslute root of someones computer we should take the string of path.resolve() in node.js which is different for each OS
context: () => ({
folders: [],
defaultProjectFolderName: DEFAULT_PROJECT_NAME,
projectDirectoryPath: NO_PROJECT_DIRECTORY,
hasListedProjects: false
}),
states: {
[SystemIOMachineStates.idle]: {
on: {
// on can be an action
[SystemIOMachineEvents.readFoldersFromProjectDirectory]:SystemIOMachineStates.readingFolders,
[SystemIOMachineEvents.setProjectDirectoryPath]:{
target: SystemIOMachineStates.readingFolders,
actions: [
SystemIOMachineActions.setProjectDirectoryPath
]
}
}
},
[SystemIOMachineStates.readingFolders]: {
invoke: {
id: SystemIOMachineActors.readFoldersFromProjectDirectory,
src: SystemIOMachineActors.readFoldersFromProjectDirectory,
input: ({context}) => {
return context
},
onDone: {
target: SystemIOMachineStates.idle,
actions: [
SystemIOMachineActions.setFolders
]
},
onError: {
target: SystemIOMachineStates.idle,
}
}
},
}
})
// Watcher handler
// look at projectDirectory useEffect then send this event if it changes or if we need to do this?
// The handler needs to live somewhere... aka the provider?

View File

@ -0,0 +1,47 @@
import { SystemIOMachineEvents, SystemIOMachineActors, SystemIOContext, NO_PROJECT_DIRECTORY} from "@src/machines/systemIO/utils"
import { systemIOMachine} from "@src/machines/systemIO/systemIOMachine"
import { setup, fromPromise, assign, assertEvent} from 'xstate'
import { mkdirOrNOOP, getProjectInfo } from "@src/lib/desktop"
import type { Project } from '@src/lib/project'
export const systemIOMachineDesktop = systemIOMachine.provide({
actors: {
[SystemIOMachineActors.readFoldersFromProjectDirectory]: fromPromise(async ({input:context}:{input:SystemIOContext}) => {
const projects = []
const projectDirectoryPath = context.projectDirectoryPath
if (projectDirectoryPath === NO_PROJECT_DIRECTORY) {
// TODO
return []
}
await mkdirOrNOOP(projectDirectoryPath)
// Gotcha: readdir will list all folders at this project directory even if you do not have readwrite access on the directory path
const entries = await window.electron.readdir(projectDirectoryPath)
const { value: canReadWriteProjectDirectory } = await window.electron.canReadWriteDirectory(projectDirectoryPath)
for (let entry of entries) {
// Skip directories that start with a dot
if (entry.startsWith('.')) {
continue
}
const projectPath = window.electron.path.join(projectDirectoryPath, entry)
// if it's not a directory ignore.
// Gotcha: statIsDirectory will work even if you do not have read write permissions on the project path
const isDirectory = await window.electron.statIsDirectory(projectPath)
if (!isDirectory) {
continue
}
const project : Project = await getProjectInfo(projectPath)
if (
project.kcl_file_count === 0 &&
project.readWriteAccess &&
canReadWriteProjectDirectory
) {
continue
}
projects.push(project)
}
return projects
})
}
})

View File

@ -0,0 +1,14 @@
import { SystemIOMachineEvents, SystemIOMachineActors, SystemIOContext} from "@src/machines/systemIO/utils"
import { systemIOMachine} from "@src/machines/systemIO/systemIOMachine"
import { setup, fromPromise, assign, assertEvent} from 'xstate'
import type { Project } from '@src/lib/project'
export const systemIOMachineWeb = systemIOMachine.provide({
actors: {
[SystemIOMachineActors.readFoldersFromProjectDirectory]: fromPromise(async ({input:context}:{input:SystemIOContext}) => {
const projects: Project[] = []
console.log('nothing!')
return projects
})
}
})

View File

@ -0,0 +1,40 @@
import type { Project } from '@src/lib/project'
export enum SystemIOMachineActors {
readFoldersFromProjectDirectory = "read folders from project directory",
setProjectDirectoryPath = "set project directory path"
}
export enum SystemIOMachineStates {
idle = "idle",
readingFolders = "readingFolders",
settingProjectDirectoryPath = "settingProjectDirectoryPath"
}
const donePrefix = 'xstate.done.actor.'
export enum SystemIOMachineEvents {
readFoldersFromProjectDirectory = "read folders from project directory",
done_readFoldersFromProjectDirectory = donePrefix + "read folders from project directory",
setProjectDirectoryPath = "set project directory path",
}
export enum SystemIOMachineActions {
setFolders = "set folders",
setProjectDirectoryPath = "set project directory path"
}
export const NO_PROJECT_DIRECTORY = ''
export type SystemIOContext = {
// Only store folders under the projectDirectory, do not maintain folders outside this directory
folders: Project[],
// For this machines runtime, this is the default string when creating a project
// A project is defined by creating a folder at the one level below the working project directory
defaultProjectFolderName:string,
// working project directory that stores all the project folders
projectDirectoryPath: string,
// has the application gone through the initialiation of systemIOMachine at least once.
// this is required to prevent chokidar from spamming invalid events during initialization.
hasListedProjects: boolean
}

View File

@ -29,7 +29,7 @@ export enum SystemIOMachineActions {
const NO_PROJECT_DIRECTORY = '' const NO_PROJECT_DIRECTORY = ''
type SystemIOContext = { export type SystemIOContext = {
// Only store folders under the projectDirectory, do not maintain folders outside this directory // Only store folders under the projectDirectory, do not maintain folders outside this directory
folders: Project[], folders: Project[],
// For this machines runtime, this is the default string when creating a project // For this machines runtime, this is the default string when creating a project