Assemblies: Load outside files into project via point-and-click (#6217)

* WIP: Add point-and-click Import for geometry
Will eventually fix #6120
Right now the whole loop is there but the codemod doesn't work yet

* Better pathToNOde, log on non-working cm dispatch call

* Add workaround to updateModelingState not working

* Back to updateModelingState with a skip flag

* Better todo

* Change working from Import to Insert, cleanups

* Sister command in kclCommands to populate file options

* Improve path selector

* Unsure: move importAstMod to kclCommands onSubmit 😶

* Add e2e test

* Clean up for review

* Add native file menu entry and test

* No await yo lint said so

* WIP: UX improvements around foreign file imports
Fixes #6152

* @lrev-Dev's suggestion to remove a comment

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>

* Update to scene.settled(cmdBar)

* Add partNNN default name for alias

* Lint

* Lint

* Fix unit tests

* Add sad path insert test
Thanks @Irev-Dev for the suggestion

* Add step insert test

* Lint

* Add test for second foreign import thru file tree click

* WIP: Add point-and-click Load to copy files from outside the project into the project
Towards #6210

* Move Insert button to modeling toolbar, update menus and toolbars

* Add default value for local name alias

* Aligning tests

* Fix tests

* Add padding for filenames starting with a digit

* Lint

* Lint

* Update snapshots

* Merge branch 'main' into pierremtb/issue6210-Add-point-and-click-Load-to-copy-files-from-outside-the-project-into-the-project

* Add disabled transform subbutton

* Merge kcl-samples and local disk load into one 'Load external model' command

* Fix em tests

* Fix test

* Add test for file pick import, better input

* Fix non .kcl loading

* Lint

* Update snapshots

* Fix issue leading to test failure

* Fix clone test

* Add note

* Fix nested clone issue

* Clean up for review

* Add valueSummary for path

* Fix test after path change

* Clean up for review

* Update src/lib/kclCommands.ts

Thanks @franknoirot!

Co-authored-by: Frank Noirot <frank@zoo.dev>

* Improve path input arg

* Fix tests

* Merge branch 'main' into pierremtb/issue6210-Add-point-and-click-Load-to-copy-files-from-outside-the-project-into-the-project

* Fix path header not showing and improve tests

* Clean up

---------

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
Co-authored-by: Frank Noirot <frank@zoo.dev>
This commit is contained in:
Pierre Jacquier
2025-04-14 14:53:01 -04:00
committed by GitHub
parent 39af110ac1
commit add1b21503
44 changed files with 552 additions and 186 deletions

View File

@ -28,16 +28,17 @@ import type { CommandBarContext } from '@src/machines/commandBarMachine'
import { IS_NIGHTLY_OR_DEBUG } from '@src/routes/utils'
interface OnSubmitProps {
sampleName: string
code: string
sampleUnits?: UnitLength_type
name: string
content?: string
targetPathToClone?: string
method: 'overwrite' | 'newFile'
source: 'kcl-samples' | 'local'
}
interface KclCommandConfig {
// TODO: find a different approach that doesn't require
// special props for a single command
specialPropsForSampleCommand: {
specialPropsForLoadCommand: {
onSubmit: (p: OnSubmitProps) => Promise<void>
providedOptions: CommandArgumentOption<string>[]
}
@ -170,69 +171,108 @@ export function kclCommands(commandProps: KclCommandConfig): Command[] {
},
},
{
name: 'open-kcl-example',
displayName: 'Open sample',
description: 'Imports an example KCL program into the editor.',
name: 'load-external-model',
displayName: 'Load external model',
description:
'Loads a model from an external source into the current project.',
needsReview: true,
icon: 'code',
icon: 'importFile',
reviewMessage: ({ argumentsToSubmit }) =>
CommandBarOverwriteWarning({
heading:
'method' in argumentsToSubmit &&
argumentsToSubmit.method === 'newFile'
? 'Create a new file from sample?'
: 'Overwrite current file with sample?',
message:
'method' in argumentsToSubmit &&
argumentsToSubmit.method === 'newFile'
? 'This will create a new file in the current project and open it.'
: 'This will erase your current file and load the sample part.',
}),
argumentsToSubmit['method'] === 'overwrite'
? CommandBarOverwriteWarning({
heading: 'Overwrite current file with sample?',
message:
'This will erase your current file and load the sample part.',
})
: 'This will create a new file in the current project and open it.',
groupId: 'code',
onSubmit(data) {
if (!data?.sample) {
return
if (!data) {
return new Error('No input data')
}
const pathParts = data.sample.split('/')
const projectPathPart = pathParts[0]
const primaryKclFile = pathParts[1]
// local only
const sampleCodeUrl =
(isDesktop() ? '.' : '') +
`/kcl-samples/${encodeURIComponent(
projectPathPart
)}/${encodeURIComponent(primaryKclFile)}`
fetch(sampleCodeUrl)
.then(async (codeResponse): Promise<OnSubmitProps> => {
if (!codeResponse.ok) {
console.error(
'Failed to fetch sample code:',
codeResponse.statusText
)
return Promise.reject(new Error('Failed to fetch sample code'))
}
const code = await codeResponse.text()
return {
sampleName: data.sample.split('/')[0] + FILE_EXT,
code,
method: data.method,
}
})
.then((props) => {
if (props?.code) {
commandProps.specialPropsForSampleCommand
.onSubmit(props)
const { method, source, sample, path } = data
if (source === 'local' && path) {
commandProps.specialPropsForLoadCommand
.onSubmit({
name: '',
targetPathToClone: path,
method,
source,
})
.catch(reportError)
} else if (source === 'kcl-samples' && sample) {
const pathParts = sample.split('/')
const projectPathPart = pathParts[0]
const primaryKclFile = pathParts[1]
// local only
const sampleCodeUrl =
(isDesktop() ? '.' : '') +
`/kcl-samples/${encodeURIComponent(
projectPathPart
)}/${encodeURIComponent(primaryKclFile)}`
fetch(sampleCodeUrl)
.then(async (codeResponse) => {
if (!codeResponse.ok) {
console.error(
'Failed to fetch sample code:',
codeResponse.statusText
)
return Promise.reject(new Error('Failed to fetch sample code'))
}
const code = await codeResponse.text()
commandProps.specialPropsForLoadCommand
.onSubmit({
name: data.sample.split('/')[0] + FILE_EXT,
content: code,
source,
method,
})
.catch(reportError)
}
})
.catch(reportError)
})
.catch(reportError)
} else {
toast.error("The command couldn't be submitted, check the arguments.")
}
},
args: {
method: {
source: {
inputType: 'options',
required: true,
skip: false,
defaultValue: 'local',
hidden: !isDesktop(),
options() {
return [
{
value: 'kcl-samples',
name: 'KCL Samples',
isCurrent: true,
},
...(isDesktop()
? [
{
value: 'local',
name: 'Local Drive',
isCurrent: false,
},
]
: []),
]
},
},
method: {
inputType: 'options',
skip: true,
required: (commandContext) =>
!['local'].includes(
commandContext.argumentsToSubmit.source as string
),
hidden: (commandContext) =>
['local'].includes(
commandContext.argumentsToSubmit.source as string
),
defaultValue: isDesktop() ? 'newFile' : 'overwrite',
options() {
return [
@ -255,7 +295,14 @@ export function kclCommands(commandProps: KclCommandConfig): Command[] {
},
sample: {
inputType: 'options',
required: true,
required: (commandContext) =>
!['local'].includes(
commandContext.argumentsToSubmit.source as string
),
hidden: (commandContext) =>
['local'].includes(
commandContext.argumentsToSubmit.source as string
),
valueSummary(value) {
const MAX_LENGTH = 12
if (typeof value === 'string') {
@ -265,7 +312,15 @@ export function kclCommands(commandProps: KclCommandConfig): Command[] {
}
return value
},
options: commandProps.specialPropsForSampleCommand.providedOptions,
options: commandProps.specialPropsForLoadCommand.providedOptions,
},
path: {
inputType: 'path',
valueSummary: (value) => window.electron.path.basename(value),
required: (commandContext) =>
['local'].includes(
commandContext.argumentsToSubmit.source as string
),
},
},
},