Assemblies: UX improvements around foreign file imports (#6159)
* 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 * Add default value for local name alias * Aligning tests * Fix tests * Add padding for filenames starting with a digit --------- Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useSelector } from '@xstate/react'
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
|
||||
import type { CommandArgument } from '@src/lib/commandTypes'
|
||||
@ -6,6 +7,11 @@ import {
|
||||
commandBarActor,
|
||||
useCommandBarState,
|
||||
} from '@src/machines/commandBarMachine'
|
||||
import type { AnyStateMachine, SnapshotFrom } from 'xstate'
|
||||
|
||||
// TODO: remove the need for this selector once we decouple all actors from React
|
||||
const machineContextSelector = (snapshot?: SnapshotFrom<AnyStateMachine>) =>
|
||||
snapshot?.context
|
||||
|
||||
function CommandBarBasicInput({
|
||||
arg,
|
||||
@ -22,6 +28,19 @@ function CommandBarBasicInput({
|
||||
const commandBarState = useCommandBarState()
|
||||
useHotkeys('mod + k, mod + /', () => commandBarActor.send({ type: 'Close' }))
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const argMachineContext = useSelector(
|
||||
arg.machineActor,
|
||||
machineContextSelector
|
||||
)
|
||||
const defaultValue = useMemo(
|
||||
() =>
|
||||
arg.defaultValue
|
||||
? arg.defaultValue instanceof Function
|
||||
? arg.defaultValue(commandBarState.context, argMachineContext)
|
||||
: arg.defaultValue
|
||||
: '',
|
||||
[arg.defaultValue, commandBarState.context, argMachineContext]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRef.current) {
|
||||
@ -53,11 +72,7 @@ function CommandBarBasicInput({
|
||||
required
|
||||
className="flex-grow px-2 py-1 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80 !bg-transparent focus:outline-none"
|
||||
placeholder="Enter a value"
|
||||
defaultValue={
|
||||
(commandBarState.context.argumentsToSubmit[arg.name] as
|
||||
| string
|
||||
| undefined) || (arg.defaultValue as string)
|
||||
}
|
||||
defaultValue={defaultValue}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Backspace' && event.shiftKey) {
|
||||
stepBack()
|
||||
|
@ -19,7 +19,7 @@ import { useKclContext } from '@src/lang/KclProvider'
|
||||
import type { KCLError } from '@src/lang/errors'
|
||||
import { kclErrorsByFilename } from '@src/lang/errors'
|
||||
import { normalizeLineEndings } from '@src/lib/codeEditor'
|
||||
import { FILE_EXT } from '@src/lib/constants'
|
||||
import { FILE_EXT, INSERT_FOREIGN_TOAST_ID } from '@src/lib/constants'
|
||||
import { sortFilesAndDirectories } from '@src/lib/desktopFS'
|
||||
import useHotkeyWrapper from '@src/lib/hotkeyWrapper'
|
||||
import { PATHS } from '@src/lib/paths'
|
||||
@ -28,6 +28,9 @@ import { codeManager, kclManager } from '@src/lib/singletons'
|
||||
import { reportRejection } from '@src/lib/trap'
|
||||
import type { IndexLoaderData } from '@src/lib/types'
|
||||
|
||||
import { ToastInsert } from '@src/components/ToastInsert'
|
||||
import { commandBarActor } from '@src/machines/commandBarMachine'
|
||||
import toast from 'react-hot-toast'
|
||||
import styles from './FileTree.module.css'
|
||||
|
||||
function getIndentationCSS(level: number) {
|
||||
@ -264,16 +267,26 @@ const FileTreeItem = ({
|
||||
if (fileOrDir.children !== null) return // Don't open directories
|
||||
|
||||
if (fileOrDir.name?.endsWith(FILE_EXT) === false && project?.path) {
|
||||
// Import non-kcl files
|
||||
// We want to update both the state and editor here.
|
||||
codeManager.updateCodeStateEditor(
|
||||
`import("${fileOrDir.path.replace(project.path, '.')}")\n` +
|
||||
codeManager.code
|
||||
toast.custom(
|
||||
ToastInsert({
|
||||
onInsert: () => {
|
||||
const relativeFilePath = fileOrDir.path.replace(
|
||||
project.path + window.electron.sep,
|
||||
''
|
||||
)
|
||||
commandBarActor.send({
|
||||
type: 'Find and select command',
|
||||
data: {
|
||||
name: 'Insert',
|
||||
groupId: 'code',
|
||||
argDefaultValues: { path: relativeFilePath },
|
||||
},
|
||||
})
|
||||
toast.dismiss(INSERT_FOREIGN_TOAST_ID)
|
||||
},
|
||||
}),
|
||||
{ duration: 30000, id: INSERT_FOREIGN_TOAST_ID }
|
||||
)
|
||||
await codeManager.writeToFile()
|
||||
|
||||
// Prevent seeing the model built one piece at a time when changing files
|
||||
await kclManager.executeCode()
|
||||
} else {
|
||||
// Let the lsp servers know we closed a file.
|
||||
onFileClose(currentFile?.path || null, project?.path || null)
|
||||
|
40
src/components/ToastInsert.tsx
Normal file
40
src/components/ToastInsert.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { ActionButton } from '@src/components/ActionButton'
|
||||
|
||||
export function ToastInsert({ onInsert }: { onInsert: () => void }) {
|
||||
return (
|
||||
<div className="inset-0 z-50 grid place-content-center rounded bg-chalkboard-110/50 shadow-md">
|
||||
<div className="max-w-3xl min-w-[35rem] p-8 rounded bg-chalkboard-10 dark:bg-chalkboard-90">
|
||||
<p className="text-md">
|
||||
Non-KCL files aren't editable here in Zoo Studio, but you may insert
|
||||
them using the button below or the Insert command.
|
||||
</p>
|
||||
<div className="mt-4 flex justify-between gap-8">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
iconStart={{
|
||||
icon: 'checkmark',
|
||||
}}
|
||||
name="insert"
|
||||
onClick={onInsert}
|
||||
>
|
||||
Insert into my current file
|
||||
</ActionButton>
|
||||
<ActionButton
|
||||
Element="button"
|
||||
iconStart={{
|
||||
icon: 'close',
|
||||
}}
|
||||
name="dismiss"
|
||||
onClick={() => {
|
||||
toast.dismiss()
|
||||
}}
|
||||
>
|
||||
Dismiss
|
||||
</ActionButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user