Add a loading state to CommandBarKclInput while calculating (#6025)

* Add a loading state to CommandBarKclInput while calculating

This is so that we can more reliably await for the calculation to be
completed before advancing the command bar in Playwright E2E tests.

* Make sure the spinner shows on first frame, before `isExecuting` is set too
This commit is contained in:
Frank Noirot
2025-03-27 16:22:04 -04:00
committed by GitHub
parent 40b0cf5fd3
commit 4f35197a96
2 changed files with 22 additions and 5 deletions

View File

@ -27,6 +27,7 @@ import { getNodeFromPath } from 'lang/queryAst'
import { isPathToNode, SourceRange, VariableDeclarator } from 'lang/wasm' import { isPathToNode, SourceRange, VariableDeclarator } from 'lang/wasm'
import { Node } from '@rust/kcl-lib/bindings/Node' import { Node } from '@rust/kcl-lib/bindings/Node'
import { err } from 'lib/trap' import { err } from 'lib/trap'
import { Spinner } from 'components/Spinner'
// TODO: remove the need for this selector once we decouple all actors from React // TODO: remove the need for this selector once we decouple all actors from React
const machineContextSelector = (snapshot?: SnapshotFrom<AnyStateMachine>) => const machineContextSelector = (snapshot?: SnapshotFrom<AnyStateMachine>) =>
@ -115,6 +116,7 @@ function CommandBarKclInput({
setNewVariableName, setNewVariableName,
isNewVariableNameUnique, isNewVariableNameUnique,
prevVariables, prevVariables,
isExecuting,
} = useCalculateKclExpression({ } = useCalculateKclExpression({
value, value,
initialVariableName, initialVariableName,
@ -200,9 +202,11 @@ function CommandBarKclInput({
useEffect(() => { useEffect(() => {
setCanSubmit( setCanSubmit(
calcResult !== 'NAN' && (!createNewVariable || isNewVariableNameUnique) calcResult !== 'NAN' &&
(!createNewVariable || isNewVariableNameUnique) &&
!isExecuting
) )
}, [calcResult, createNewVariable, isNewVariableNameUnique]) }, [calcResult, createNewVariable, isNewVariableNameUnique, isExecuting])
function handleSubmit(e?: React.FormEvent<HTMLFormElement>) { function handleSubmit(e?: React.FormEvent<HTMLFormElement>) {
e?.preventDefault() e?.preventDefault()
@ -268,9 +272,13 @@ function CommandBarKclInput({
: 'text-succeed-80 dark:text-succeed-40' : 'text-succeed-80 dark:text-succeed-40'
} }
> >
{calcResult === 'NAN' {isExecuting === true || !calcResult ? (
? "Can't calculate" <Spinner className="text-inherit w-4 h-4" />
: roundOff(Number(calcResult), 4)} ) : calcResult === 'NAN' ? (
"Can't calculate"
) : (
roundOff(Number(calcResult), 4)
)}
</span> </span>
</label> </label>
{createNewVariable ? ( {createNewVariable ? (

View File

@ -35,7 +35,12 @@ export function useCalculateKclExpression({
isNewVariableNameUnique: boolean isNewVariableNameUnique: boolean
newVariableInsertIndex: number newVariableInsertIndex: number
setNewVariableName: (a: string) => void setNewVariableName: (a: string) => void
isExecuting: boolean
} { } {
// Executing the mini AST to calculate the expression value
// is asynchronous. Use this state variable to track if execution
// has completed
const [isExecuting, setIsExecuting] = useState(false)
const { variables, code } = useKclContext() const { variables, code } = useKclContext()
const { context } = useModelingContext() const { context } = useModelingContext()
// If there is no selection, use the end of the code // If there is no selection, use the end of the code
@ -110,6 +115,7 @@ export function useCalculateKclExpression({
useEffect(() => { useEffect(() => {
const execAstAndSetResult = async () => { const execAstAndSetResult = async () => {
const result = await getCalculatedKclExpressionValue(value) const result = await getCalculatedKclExpressionValue(value)
setIsExecuting(false)
if (result instanceof Error || 'errors' in result || !result.astNode) { if (result instanceof Error || 'errors' in result || !result.astNode) {
setCalcResult('NAN') setCalcResult('NAN')
setValueNode(null) setValueNode(null)
@ -121,8 +127,10 @@ export function useCalculateKclExpression({
result?.astNode && setValueNode(result.astNode) result?.astNode && setValueNode(result.astNode)
} }
if (!value) return if (!value) return
setIsExecuting(true)
execAstAndSetResult().catch(() => { execAstAndSetResult().catch(() => {
setCalcResult('NAN') setCalcResult('NAN')
setIsExecuting(false)
setValueNode(null) setValueNode(null)
}) })
}, [value, availableVarInfo, code, kclManager.variables]) }, [value, availableVarInfo, code, kclManager.variables])
@ -136,5 +144,6 @@ export function useCalculateKclExpression({
isNewVariableNameUnique, isNewVariableNameUnique,
setNewVariableName, setNewVariableName,
inputRef, inputRef,
isExecuting,
} }
} }