From fbf94aaba97eb46ee983598843a38b5b40a92883 Mon Sep 17 00:00:00 2001 From: Kevin Nadro Date: Mon, 21 Apr 2025 12:58:12 -0500 Subject: [PATCH] chore: implementing import file from url which is not actually that? --- .../Providers/SystemIOProviderWeb.tsx | 24 +++++ src/hooks/useCreateFileLinkQueryWatcher.ts | 1 + .../projectsCommandConfig.ts | 91 ++++++++++++++++++- src/lib/settings/settingsUtils.ts | 2 +- src/machines/systemIO/systemIOMachine.ts | 8 +- .../systemIO/systemIOMachineDesktop.ts | 6 ++ src/machines/systemIO/systemIOMachineWeb.ts | 30 +++++- 7 files changed, 158 insertions(+), 4 deletions(-) diff --git a/src/components/Providers/SystemIOProviderWeb.tsx b/src/components/Providers/SystemIOProviderWeb.tsx index 3a3580e9a..2bd1190c2 100644 --- a/src/components/Providers/SystemIOProviderWeb.tsx +++ b/src/components/Providers/SystemIOProviderWeb.tsx @@ -1,3 +1,27 @@ +import { useEffect } from 'react' +import { commandBarActor } from '@src/machines/commandBarMachine' +import { importFileFromURL } from '@src/lib/commandBarConfigs/projectsCommandConfig' export function SystemIOMachineLogicListenerWeb() { + const useAddProjectCommandsToCommandBar = () => { + const commands = [importFileFromURL] + useEffect(() => { + commandBarActor.send({ + type: 'Add commands', + data: { + commands: commands, + }, + }) + return () => { + commandBarActor.send({ + type: 'Remove commands', + data: { + commands: commands, + }, + }) + } + }, []) + } + + useAddProjectCommandsToCommandBar() return null } diff --git a/src/hooks/useCreateFileLinkQueryWatcher.ts b/src/hooks/useCreateFileLinkQueryWatcher.ts index 1a0f8cdb0..d7e812f1b 100644 --- a/src/hooks/useCreateFileLinkQueryWatcher.ts +++ b/src/hooks/useCreateFileLinkQueryWatcher.ts @@ -63,6 +63,7 @@ export function useCreateFileLinkQuery( method: isDesktop() ? undefined : 'existingProject', } + console.log('nice callback?') callback(argDefaultValues) } }, [searchParams, immediateState]) diff --git a/src/lib/commandBarConfigs/projectsCommandConfig.ts b/src/lib/commandBarConfigs/projectsCommandConfig.ts index 0f4e8c3e9..d43e17330 100644 --- a/src/lib/commandBarConfigs/projectsCommandConfig.ts +++ b/src/lib/commandBarConfigs/projectsCommandConfig.ts @@ -320,11 +320,100 @@ export const renameProjectCommand: Command = { }, }, } -// export const importFileFromURL: Command = {} + +export const importFileFromURL: Command = { + name: 'Import file from URL', + groupId: 'projects', + icon: 'file', + description: 'Create a file', + needsReview: true, + onSubmit: (record) => { + console.log('RECORD!', record) + if (record) { + systemIOActor.send({ + type: SystemIOMachineEvents.createKCLFile, + data: { + requestedProjectName: record.projectName, + requestedCode: record.code, + requestedFileName: record.name, + }, + }) + } + }, + args: { + method: { + inputType: 'options', + required: true, + skip: true, + options: isDesktop() + ? [ + { name: 'New project', value: 'newProject' }, + { name: 'Existing project', value: 'existingProject' }, + ] + : [{ name: 'Overwrite', value: 'existingProject' }], + valueSummary(value) { + return isDesktop() + ? value === 'newProject' + ? 'New project' + : 'Existing project' + : 'Overwrite' + }, + }, + // TODO: We can't get the currently-opened project to auto-populate here because + // it's not available on projectMachine, but lower in fileMachine. Unify these. + projectName: { + inputType: 'options', + required: (commandsContext) => + isDesktop() && + commandsContext.argumentsToSubmit.method === 'existingProject', + skip: true, + options: (_, context) => { + const folders = folderSnapshot() + const options: CommandArgumentOption[] = [] + folders.forEach((folder) => { + options.push({ + name: folder.name, + value: folder.name, + isCurrent: false, + }) + }) + return options + }, + }, + name: { + inputType: 'string', + required: isDesktop(), + skip: true, + }, + code: { + inputType: 'text', + required: true, + skip: true, + valueSummary(value) { + const lineCount = value?.trim().split('\n').length + return `${lineCount} line${lineCount === 1 ? '' : 's'}` + }, + }, + }, + reviewMessage(commandBarContext) { + return isDesktop() + ? `Will add the contents from URL to a new ${ + commandBarContext.argumentsToSubmit.method === 'newProject' + ? 'project with file main.kcl' + : `file within the project "${commandBarContext.argumentsToSubmit.projectName}"` + } named "${ + commandBarContext.argumentsToSubmit.name + }", and set default units to "${ + commandBarContext.argumentsToSubmit.units + }".` + : `Will overwrite the contents of the current file with the contents from the URL.` + }, +} export const projectCommands = [ openProjectCommand, createProjectCommand, deleteProjectCommand, renameProjectCommand, + importFileFromURL, ] diff --git a/src/lib/settings/settingsUtils.ts b/src/lib/settings/settingsUtils.ts index fe78ff1bb..72306eb6b 100644 --- a/src/lib/settings/settingsUtils.ts +++ b/src/lib/settings/settingsUtils.ts @@ -191,7 +191,7 @@ export function readLocalStorageAppSettingsFile(): } } -function readLocalStorageProjectSettingsFile(): +export function readLocalStorageProjectSettingsFile(): | DeepPartial | Error { // TODO: Remove backwards compatibility after a few releases. diff --git a/src/machines/systemIO/systemIOMachine.ts b/src/machines/systemIO/systemIOMachine.ts index 1836400b1..c3415ca05 100644 --- a/src/machines/systemIO/systemIOMachine.ts +++ b/src/machines/systemIO/systemIOMachine.ts @@ -183,7 +183,13 @@ export const systemIOMachine = setup({ requestedFileName: string requestedCode: string } - }) => {} + }): Promise<{ + message: string + fileName: string + projectName: string + }> => { + return { message: '', fileName: '', projectName: '' } + } ), [SystemIOMachineActors.checkReadWrite]: fromPromise( async ({ diff --git a/src/machines/systemIO/systemIOMachineDesktop.ts b/src/machines/systemIO/systemIOMachineDesktop.ts index 47692e48f..f06c77000 100644 --- a/src/machines/systemIO/systemIOMachineDesktop.ts +++ b/src/machines/systemIO/systemIOMachineDesktop.ts @@ -193,6 +193,12 @@ export const systemIOMachineDesktop = systemIOMachine.provide({ configuration, newFileName ) + + return { + message: 'File created successfully', + fileName: input.requestedFileName, + projectName: requestedProjectName, + } } ), [SystemIOMachineActors.checkReadWrite]: fromPromise( diff --git a/src/machines/systemIO/systemIOMachineWeb.ts b/src/machines/systemIO/systemIOMachineWeb.ts index 9466a4de2..b61f7b179 100644 --- a/src/machines/systemIO/systemIOMachineWeb.ts +++ b/src/machines/systemIO/systemIOMachineWeb.ts @@ -2,6 +2,11 @@ import { systemIOMachine } from '@src/machines/systemIO/systemIOMachine' import type { SystemIOContext } from '@src/machines/systemIO/utils' import { SystemIOMachineActors } from '@src/machines/systemIO/utils' import { fromPromise } from 'xstate' +import { newKclFile } from '@src/lang/project' +import { readLocalStorageProjectSettingsFile } from '@src/lib/settings/settingsUtils' +import { err } from '@src/lib/trap' +import { DEFAULT_DEFAULT_LENGTH_UNIT } from '@src/lib/constants' +import { codeManager, kclManager } from '@src/lib/singletons' export const systemIOMachineWeb = systemIOMachine.provide({ actors: { @@ -15,7 +20,30 @@ export const systemIOMachineWeb = systemIOMachine.provide({ requestedFileName: string requestedCode: string } - }) => {} + }) => { + // Browser version doesn't navigate, just overwrites the current file + // clearImportSearchParams() + const projectSettings = readLocalStorageProjectSettingsFile() + if (err(projectSettings)) { + return Promise.reject( + 'Unable to read project settings from local storage' + ) + } + const codeToWrite = newKclFile( + input.requestedCode, + projectSettings?.settings?.modeling?.base_unit || + DEFAULT_DEFAULT_LENGTH_UNIT + ) + if (err(codeToWrite)) return Promise.reject(codeToWrite) + codeManager.updateCodeStateEditor(codeToWrite) + await codeManager.writeToFile() + await kclManager.executeCode() + return { + message: 'File overwritten successfully', + fileName: input.requestedFileName, + projectName: '', + } + } ), }, })