Files
modeling-app/src/machines/systemIO/systemIOMachineDesktop.ts
Kevin Nadro 941eacd559 [BUG]: split('/') caused bug on windows (#6697)
* fix: trying to figure out this pathing issue

* fix: found the bug

* fix: adding linter rule

* fix: rule for join('/') as well

* fix: removing useless string template

* fix: removing useless string template

* fix: ???? What ????

* fix: remove unused import

* fix: circular dep was added when I cleaned up the path logic, fixed the circular dep by passing args from the parent function
2025-05-06 16:48:45 +00:00

260 lines
7.9 KiB
TypeScript

import {
createNewProjectDirectory,
getProjectInfo,
mkdirOrNOOP,
readAppSettingsFile,
renameProjectDirectory,
} from '@src/lib/desktop'
import {
doesProjectNameNeedInterpolated,
getNextFileName,
getNextProjectIndex,
getUniqueProjectName,
interpolateProjectNameWithIndex,
} from '@src/lib/desktopFS'
import type { Project } from '@src/lib/project'
import { systemIOMachine } from '@src/machines/systemIO/systemIOMachine'
import type { SystemIOContext } from '@src/machines/systemIO/utils'
import {
NO_PROJECT_DIRECTORY,
SystemIOMachineActors,
} from '@src/machines/systemIO/utils'
import { fromPromise } from 'xstate'
import type { AppMachineContext } from '@src/lib/types'
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) {
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
}
),
[SystemIOMachineActors.createProject]: fromPromise(
async ({
input,
}: {
input: { context: SystemIOContext; requestedProjectName: string }
}) => {
const folders = input.context.folders
const requestedProjectName = input.requestedProjectName
const uniqueName = getUniqueProjectName(requestedProjectName, folders)
await createNewProjectDirectory(uniqueName)
return {
message: `Successfully created "${uniqueName}"`,
name: uniqueName,
}
}
),
[SystemIOMachineActors.renameProject]: fromPromise(
async ({
input,
}: {
input: {
context: SystemIOContext
requestedProjectName: string
projectName: string
}
}) => {
const folders = input.context.folders
const requestedProjectName = input.requestedProjectName
const projectName = input.projectName
let newProjectName: string = requestedProjectName
if (doesProjectNameNeedInterpolated(requestedProjectName)) {
const nextIndex = getNextProjectIndex(requestedProjectName, folders)
newProjectName = interpolateProjectNameWithIndex(
requestedProjectName,
nextIndex
)
}
// Toast an error if the project name is taken
if (folders.find((p) => p.name === newProjectName)) {
return Promise.reject(
new Error(`Project with name "${newProjectName}" already exists`)
)
}
await renameProjectDirectory(
window.electron.path.join(
input.context.projectDirectoryPath,
projectName
),
newProjectName
)
return {
message: `Successfully renamed "${projectName}" to "${newProjectName}"`,
oldName: projectName,
newName: newProjectName,
}
}
),
[SystemIOMachineActors.deleteProject]: fromPromise(
async ({
input,
}: {
input: { context: SystemIOContext; requestedProjectName: string }
}) => {
await window.electron.rm(
window.electron.path.join(
input.context.projectDirectoryPath,
input.requestedProjectName
),
{
recursive: true,
}
)
return {
message: `Successfully deleted "${input.requestedProjectName}"`,
name: input.requestedProjectName,
}
}
),
[SystemIOMachineActors.createKCLFile]: fromPromise(
async ({
input,
}: {
input: {
context: SystemIOContext
requestedProjectName: string
requestedFileNameWithExtension: string
requestedCode: string
rootContext: AppMachineContext
requestedSubRoute?: string
}
}) => {
const requestedProjectName = input.requestedProjectName
const requestedFileNameWithExtension =
input.requestedFileNameWithExtension
const requestedCode = input.requestedCode
const folders = input.context.folders
let newProjectName = requestedProjectName
if (!newProjectName) {
newProjectName = getUniqueProjectName(
input.context.defaultProjectFolderName,
input.context.folders
)
}
const needsInterpolated =
doesProjectNameNeedInterpolated(newProjectName)
if (needsInterpolated) {
const nextIndex = getNextProjectIndex(newProjectName, folders)
newProjectName = interpolateProjectNameWithIndex(
newProjectName,
nextIndex
)
}
const baseDir = window.electron.join(
input.context.projectDirectoryPath,
newProjectName
)
const { name: newFileName } = getNextFileName({
entryName: requestedFileNameWithExtension,
baseDir,
})
const configuration = await readAppSettingsFile()
// Create the project around the file if newProject
await createNewProjectDirectory(
newProjectName,
requestedCode,
configuration,
newFileName
)
return {
message: 'File created successfully',
fileName: newFileName,
projectName: newProjectName,
subRoute: input.requestedSubRoute || '',
}
}
),
[SystemIOMachineActors.checkReadWrite]: fromPromise(
async ({
input,
}: {
input: {
context: SystemIOContext
requestedProjectDirectoryPath: string
}
}) => {
const requestProjectDirectoryPath = input.requestedProjectDirectoryPath
if (!requestProjectDirectoryPath) {
return { value: true, error: undefined }
}
const result = await window.electron.canReadWriteDirectory(
requestProjectDirectoryPath
)
return result
}
),
[SystemIOMachineActors.deleteKCLFile]: fromPromise(
async ({
input,
}: {
input: {
context: SystemIOContext
requestedProjectName: string
requestedFileName: string
}
}) => {
const path = window.electron.path.join(
input.context.projectDirectoryPath,
input.requestedProjectName,
input.requestedFileName
)
await window.electron.rm(path)
return {
message: 'File deleted successfully',
projectName: input.requestedProjectName,
fileName: input.requestedFileName,
}
}
),
},
})