import type { Project } from '@src/lib/project' import type { ActorRefFrom } from 'xstate' import type { systemIOMachine } from '@src/machines/systemIO/systemIOMachine' export enum SystemIOMachineActors { readFoldersFromProjectDirectory = 'read folders from project directory', setProjectDirectoryPath = 'set project directory path', createProject = 'create project', renameProject = 'rename project', deleteProject = 'delete project', createKCLFile = 'create kcl file', checkReadWrite = 'check read write', /** TODO: rename this event to be more generic, like `createKCLFileAndNavigate` */ importFileFromURL = 'import file from URL', deleteKCLFile = 'delete kcl delete', bulkCreateKCLFiles = 'bulk create kcl files', bulkCreateKCLFilesAndNavigateToProject = 'bulk create kcl files and navigate to project', bulkCreateKCLFilesAndNavigateToFile = 'bulk create kcl files and navigate to file', } export enum SystemIOMachineStates { idle = 'idle', readingFolders = 'readingFolders', settingProjectDirectoryPath = 'settingProjectDirectoryPath', creatingProject = 'creatingProject', renamingProject = 'renamingProject', deletingProject = 'deletingProject', creatingKCLFile = 'creatingKCLFile', checkingReadWrite = 'checkingReadWrite', /** TODO: rename this event to be more generic, like `createKCLFileAndNavigate` */ importFileFromURL = 'importFileFromURL', deletingKCLFile = 'deletingKCLFile', bulkCreatingKCLFiles = 'bulkCreatingKCLFiles', bulkCreatingKCLFilesAndNavigateToProject = 'bulkCreatingKCLFilesAndNavigateToProject', bulkCreatingKCLFilesAndNavigateToFile = 'bulkCreatingKCLFilesAndNavigateToFile', } 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', navigateToProject = 'navigate to project', navigateToFile = 'navigate to file', createProject = 'create project', renameProject = 'rename project', deleteProject = 'delete project', done_deleteProject = donePrefix + 'delete project', createKCLFile = 'create kcl file', setDefaultProjectFolderName = 'set default project folder name', done_checkReadWrite = donePrefix + 'check read write', /** TODO: rename this event to be more generic, like `createKCLFileAndNavigate` */ importFileFromURL = 'import file from URL', done_importFileFromURL = donePrefix + 'import file from URL', generateTextToCAD = 'generate text to CAD', deleteKCLFile = 'delete kcl file', bulkCreateKCLFiles = 'bulk create kcl files', bulkCreateKCLFilesAndNavigateToProject = 'bulk create kcl files and navigate to project', bulkCreateKCLFilesAndNavigateToFile = 'bulk create kcl files and navigate to file', done_bulkCreateKCLFilesAndNavigateToFile = donePrefix + 'bulk create kcl files and navigate to file', } export enum SystemIOMachineActions { setFolders = 'set folders', setProjectDirectoryPath = 'set project directory path', setRequestedProjectName = 'set requested project name', setRequestedFileName = 'set requested file name', setDefaultProjectFolderName = 'set default project folder name', toastSuccess = 'toastSuccess', toastError = 'toastError', setReadWriteProjectDirectory = 'set read write project directory', setRequestedTextToCadGeneration = 'set requested text to cad generation', setLastProjectDeleteRequest = 'set last project delete request', } 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 initialization of systemIOMachine at least once. * this is required to prevent chokidar from spamming invalid events during initialization. */ hasListedProjects: boolean /** * We watch objects because we want to be able to navigate to itself * if we used a string the useEffect would not change */ requestedProjectName: { name: string; subRoute?: string } requestedFileName: { project: string; file: string; subRoute?: string } canReadWriteProjectDirectory: { value: boolean; error: unknown } clearURLParams: { value: boolean } requestedTextToCadGeneration: { requestedPrompt: string requestedProjectName: string isProjectNew: boolean } lastProjectDeleteRequest: { project: string } } export type RequestedKCLFile = { requestedProjectName: string requestedFileName: string requestedCode: string } export const waitForIdleState = async ({ systemIOActor, }: { systemIOActor: ActorRefFrom }) => { // Check if already idle before setting up subscription if (systemIOActor.getSnapshot().matches(SystemIOMachineStates.idle)) { return Promise.resolve() } const waitForIdlePromise = new Promise((resolve) => { const subscription = systemIOActor.subscribe((state) => { if (state.matches(SystemIOMachineStates.idle)) { subscription.unsubscribe() resolve(undefined) } }) }) return waitForIdlePromise }