Add edit flow for named constants / parameters (#5911)
* Add support for forcing kcl input create variable * Command palette padding tweak * Make traverse function work for ExpressionStatements * Add utilities for getting earliest safe index in AST * Fix the insertIndex logic to not be based on the selection anymore * Add workflow to create a named constant * Fix bug with nameEndInDigits matcher * Tweak command config * Add a three-dot menu to feature tree pane to create parameters * Add E2E test for create parameter flow * Remove edit flow oops * Fix tsc error * Fix E2E test * Update named constant position in edit flow test * Add tags into consideration for safe insert index Per @Irev-dev's helpful feedback, with unit tests! * Fix tsc by removing a generic type * Remove unused imports * Fix lints * A snapshot a day keeps the bugs away! 📷🐛 * Add utilities for working with variable declarations * Add "edit parameter" user flow * Add edit flow config * WIP working on de-bloating useCalculateKclExpreesion * Add the ability to specify a `displayName` for an arg * Add utility to type check on SourceRanges * Review step design tweak fixes * Refactor useCalculateKclExpression to take a sourceRange * Make option arg validation work for objects and arrays Using an admittedly dumb stringification approach * Make edit flow never move the constant to be edited * Add E2E test section * Fix lints * Remove lying comment, tiny CSS tweak * A snapshot a day keeps the bugs away! 📷🐛 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
@ -54,7 +54,7 @@ function ArgumentInput({
|
||||
return (
|
||||
<CommandArgOptionInput
|
||||
arg={arg}
|
||||
argName={arg.name}
|
||||
argName={arg.displayName || arg.name}
|
||||
stepBack={stepBack}
|
||||
onSubmit={onSubmit}
|
||||
placeholder="Select an option"
|
||||
@ -71,7 +71,7 @@ function ArgumentInput({
|
||||
{ name: 'Off', value: false },
|
||||
],
|
||||
}}
|
||||
argName={arg.name}
|
||||
argName={arg.displayName || arg.name}
|
||||
stepBack={stepBack}
|
||||
onSubmit={onSubmit}
|
||||
placeholder="Select an option"
|
||||
|
@ -38,7 +38,7 @@ function CommandBarBasicInput({
|
||||
className="flex items-center mx-4 my-4"
|
||||
>
|
||||
<span className="capitalize px-2 py-1 rounded-l bg-chalkboard-100 dark:bg-chalkboard-80 text-chalkboard-10 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80">
|
||||
{arg.name}
|
||||
{arg.displayName || arg.name}
|
||||
</span>
|
||||
<input
|
||||
data-testid="cmd-bar-arg-value"
|
||||
|
@ -130,7 +130,7 @@ function CommandBarHeader({ children }: React.PropsWithChildren<{}>) {
|
||||
data-test-name="arg-name"
|
||||
className="capitalize"
|
||||
>
|
||||
{argName}
|
||||
{arg.displayName || argName}
|
||||
</span>
|
||||
<span className="sr-only">: </span>
|
||||
<span data-testid="header-arg-value">
|
||||
|
@ -21,10 +21,16 @@ import { useSelector } from '@xstate/react'
|
||||
import { commandBarActor, useCommandBarState } from 'machines/commandBarMachine'
|
||||
import { useSettings } from 'machines/appMachine'
|
||||
import toast from 'react-hot-toast'
|
||||
import { AnyStateMachine, SnapshotFrom } from 'xstate'
|
||||
import { kclManager } from 'lib/singletons'
|
||||
import { getNodeFromPath } from 'lang/queryAst'
|
||||
import { isPathToNode, SourceRange, VariableDeclarator } from 'lang/wasm'
|
||||
import { Node } from '@rust/kcl-lib/bindings/Node'
|
||||
import { err } from 'lib/trap'
|
||||
|
||||
const machineContextSelector = (snapshot?: {
|
||||
context: Record<string, unknown>
|
||||
}) => snapshot?.context
|
||||
// TODO: remove the need for this selector once we decouple all actors from React
|
||||
const machineContextSelector = (snapshot?: SnapshotFrom<AnyStateMachine>) =>
|
||||
snapshot?.context
|
||||
|
||||
function CommandBarKclInput({
|
||||
arg,
|
||||
@ -47,6 +53,16 @@ function CommandBarKclInput({
|
||||
arg.machineActor,
|
||||
machineContextSelector
|
||||
)
|
||||
const sourceRangeForPrevVariables = useMemo<SourceRange | undefined>(() => {
|
||||
const nodeToEdit = commandBarState.context.argumentsToSubmit.nodeToEdit
|
||||
const pathToNode = isPathToNode(nodeToEdit) ? nodeToEdit : undefined
|
||||
const node = pathToNode
|
||||
? getNodeFromPath<Node<VariableDeclarator>>(kclManager.ast, pathToNode)
|
||||
: undefined
|
||||
return !err(node) && node && node.node.type === 'VariableDeclarator'
|
||||
? [node.node.start, node.node.end, node.node.moduleId]
|
||||
: undefined
|
||||
}, [kclManager.ast, commandBarState.context.argumentsToSubmit.nodeToEdit])
|
||||
const defaultValue = useMemo(
|
||||
() =>
|
||||
arg.defaultValue
|
||||
@ -90,21 +106,22 @@ function CommandBarKclInput({
|
||||
const editorRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const {
|
||||
prevVariables,
|
||||
calcResult,
|
||||
newVariableInsertIndex,
|
||||
valueNode,
|
||||
newVariableName,
|
||||
setNewVariableName,
|
||||
isNewVariableNameUnique,
|
||||
prevVariables,
|
||||
} = useCalculateKclExpression({
|
||||
value,
|
||||
initialVariableName,
|
||||
sourceRange: sourceRangeForPrevVariables,
|
||||
})
|
||||
|
||||
const varMentionData: Completion[] = prevVariables.map((v) => ({
|
||||
label: v.key,
|
||||
detail: String(roundOff(v.value as number)),
|
||||
detail: String(roundOff(Number(v.value))),
|
||||
}))
|
||||
const varMentionsExtension = varMentions(varMentionData)
|
||||
|
||||
@ -219,13 +236,18 @@ function CommandBarKclInput({
|
||||
}
|
||||
|
||||
return (
|
||||
<form id="arg-form" onSubmit={handleSubmit} data-can-submit={canSubmit}>
|
||||
<form
|
||||
id="arg-form"
|
||||
className="mb-2"
|
||||
onSubmit={handleSubmit}
|
||||
data-can-submit={canSubmit}
|
||||
>
|
||||
<label className="flex gap-4 items-center mx-4 my-4 border-solid border-b border-chalkboard-50">
|
||||
<span
|
||||
data-testid="cmd-bar-arg-name"
|
||||
className="capitalize text-chalkboard-80 dark:text-chalkboard-20"
|
||||
>
|
||||
{arg.name}
|
||||
{arg.displayName || arg.name}
|
||||
</span>
|
||||
<div
|
||||
data-testid="cmd-bar-arg-value"
|
||||
@ -249,7 +271,7 @@ function CommandBarKclInput({
|
||||
</span>
|
||||
</label>
|
||||
{createNewVariable ? (
|
||||
<div className="flex mb-2 items-baseline gap-4 mx-4 border-solid border-0 border-b border-chalkboard-50">
|
||||
<div className="flex items-baseline gap-4 mx-4 border-solid border-0 border-b border-chalkboard-50">
|
||||
<label
|
||||
htmlFor="variable-name"
|
||||
className="text-base text-chalkboard-80 dark:text-chalkboard-20"
|
||||
|
@ -58,7 +58,7 @@ function CommandBarReview({ stepBack }: { stepBack: () => void }) {
|
||||
|
||||
return (
|
||||
<CommandBarHeader>
|
||||
<p className="px-4">
|
||||
<p className="px-4 pb-2">
|
||||
{selectedCommand?.reviewMessage ? (
|
||||
selectedCommand.reviewMessage instanceof Function ? (
|
||||
selectedCommand.reviewMessage(commandBarState.context)
|
||||
@ -66,7 +66,7 @@ function CommandBarReview({ stepBack }: { stepBack: () => void }) {
|
||||
selectedCommand.reviewMessage
|
||||
)
|
||||
) : (
|
||||
<>Confirm {selectedCommand?.name}</>
|
||||
<>Confirm {selectedCommand?.displayName || selectedCommand?.name}</>
|
||||
)}
|
||||
</p>
|
||||
<form
|
||||
|
@ -40,7 +40,7 @@ function CommandBarTextareaInput({
|
||||
data-testid="cmd-bar-arg-name"
|
||||
className="capitalize px-2 py-1 rounded-br bg-chalkboard-100 dark:bg-chalkboard-80 text-chalkboard-10 border-b border-b-chalkboard-100 dark:border-b-chalkboard-80"
|
||||
>
|
||||
{arg.name}
|
||||
{arg.displayName || arg.name}
|
||||
</span>
|
||||
<textarea
|
||||
data-testid="cmd-bar-arg-value"
|
||||
|
Reference in New Issue
Block a user