Catch import scene selection on transforms and point to the feature tree (#6674)

* Catch import scene selection on transforms and point to the feature tree
Fixes #6667

* Add test for toast on clone, bringing back forgotten test
This commit is contained in:
Pierre Jacquier
2025-05-02 17:25:33 -04:00
committed by GitHub
parent 4fe8741ea7
commit c327c73087
3 changed files with 114 additions and 60 deletions

View File

@ -800,25 +800,26 @@ foreign
} }
) )
// TODO: bring back in https://github.com/KittyCAD/modeling-app/issues/6570 test(
test.fixme( `Point-and-click clone`,
'Point-and-click Clone on assembly parts',
{ tag: ['@electron'] }, { tag: ['@electron'] },
async ({ async ({
context, context,
page, page,
homePage, homePage,
scene, scene,
editor,
toolbar, toolbar,
cmdBar, cmdBar,
tronApp, tronApp,
editor,
}) => { }) => {
if (!tronApp) { if (!tronApp) {
fail() fail()
} }
const projectName = 'assembly' const projectName = 'assembly'
const midPoint = { x: 500, y: 250 }
const [clickMidPoint] = scene.makeMouseHelpers(midPoint.x, midPoint.y)
await test.step('Setup parts and expect imported model', async () => { await test.step('Setup parts and expect imported model', async () => {
await context.folderSetupFn(async (dir) => { await context.folderSetupFn(async (dir) => {
@ -855,6 +856,50 @@ washer
await toolbar.closePane('code') await toolbar.closePane('code')
}) })
await test.step('Try to clone from scene selection and expect error', async () => {
await cmdBar.openCmdBar()
await cmdBar.chooseCommand('Clone a solid')
await cmdBar.expectState({
stage: 'arguments',
currentArgKey: 'selection',
currentArgValue: '',
headerArguments: {
Selection: '',
VariableName: '',
},
highlightedHeaderArg: 'selection',
commandName: 'Clone',
})
await clickMidPoint()
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'arguments',
currentArgKey: 'variableName',
currentArgValue: '',
headerArguments: {
Selection: '1 path',
VariableName: '',
},
highlightedHeaderArg: 'variableName',
commandName: 'Clone',
})
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Selection: '1 path',
VariableName: 'clone001',
},
commandName: 'Clone',
})
await cmdBar.progressCmdBar()
await expect(
page.getByText(
"Couldn't retrieve selection. If you're trying to transform an import, use the feature tree."
)
).toBeVisible()
})
await test.step('Clone the part using the feature tree', async () => { await test.step('Clone the part using the feature tree', async () => {
await toolbar.openPane('feature-tree') await toolbar.openPane('feature-tree')
const op = await toolbar.getFeatureTreeOperation('washer', 0) const op = await toolbar.getFeatureTreeOperation('washer', 0)

View File

@ -9,6 +9,7 @@ import {
} from '@src/lang/create' } from '@src/lang/create'
import { getNodeFromPath } from '@src/lang/queryAst' import { getNodeFromPath } from '@src/lang/queryAst'
import type { import type {
ArtifactGraph,
CallExpressionKw, CallExpressionKw,
Expr, Expr,
ExpressionStatement, ExpressionStatement,
@ -18,6 +19,11 @@ import type {
VariableDeclarator, VariableDeclarator,
} from '@src/lang/wasm' } from '@src/lang/wasm'
import { err } from '@src/lib/trap' import { err } from '@src/lib/trap'
import {
findAllChildrenAndOrderByPlaceInCode,
getLastVariable,
} from '@src/lang/modifyAst/boolean'
import type { Selections } from '@src/lib/selections'
export function setTranslate({ export function setTranslate({
modifiedAst, modifiedAst,
@ -153,3 +159,34 @@ export function insertExpressionNode(ast: Node<Program>, alias: string) {
] ]
return pathToNode return pathToNode
} }
export function retrievePathToNodeFromTransformSelection(
selection: Selections,
artifactGraph: ArtifactGraph,
ast: Node<Program>
): PathToNode | Error {
const error = new Error(
"Couldn't retrieve selection. If you're trying to transform an import, use the feature tree."
)
const hasPathToNode = !!selection.graphSelections[0].codeRef.pathToNode.length
const artifact = selection.graphSelections[0].artifact
let pathToNode: PathToNode | undefined
if (hasPathToNode && artifact) {
const children = findAllChildrenAndOrderByPlaceInCode(
artifact,
artifactGraph
)
const variable = getLastVariable(children, ast)
if (!variable) {
return error
}
pathToNode = variable.pathToNode
} else if (hasPathToNode) {
pathToNode = selection.graphSelections[0].codeRef.pathToNode
} else {
return error
}
return pathToNode
}

View File

@ -73,8 +73,6 @@ import {
applyIntersectFromTargetOperatorSelections, applyIntersectFromTargetOperatorSelections,
applySubtractFromTargetOperatorSelections, applySubtractFromTargetOperatorSelections,
applyUnionFromTargetOperatorSelections, applyUnionFromTargetOperatorSelections,
findAllChildrenAndOrderByPlaceInCode,
getLastVariable,
} from '@src/lang/modifyAst/boolean' } from '@src/lang/modifyAst/boolean'
import { import {
deleteSelectionPromise, deleteSelectionPromise,
@ -85,6 +83,7 @@ import {
setTranslate, setTranslate,
setRotate, setRotate,
insertExpressionNode, insertExpressionNode,
retrievePathToNodeFromTransformSelection,
} from '@src/lang/modifyAst/setTransform' } from '@src/lang/modifyAst/setTransform'
import { import {
getNodeFromPath, getNodeFromPath,
@ -2769,25 +2768,16 @@ export const modelingMachine = setup({
const { x, y, z, nodeToEdit, selection } = input const { x, y, z, nodeToEdit, selection } = input
let pathToNode = nodeToEdit let pathToNode = nodeToEdit
if (!(pathToNode && typeof pathToNode[1][0] === 'number')) { if (!(pathToNode && typeof pathToNode[1][0] === 'number')) {
if (selection?.graphSelections[0].artifact) { const result = retrievePathToNodeFromTransformSelection(
const children = findAllChildrenAndOrderByPlaceInCode( selection,
selection?.graphSelections[0].artifact, kclManager.artifactGraph,
kclManager.artifactGraph ast
) )
const variable = getLastVariable(children, modifiedAst) if (err(result)) {
if (!variable) { return Promise.reject(result)
return Promise.reject(
new Error("Couldn't find corresponding path to node")
)
}
pathToNode = variable.pathToNode
} else if (selection?.graphSelections[0].codeRef.pathToNode) {
pathToNode = selection?.graphSelections[0].codeRef.pathToNode
} else {
return Promise.reject(
new Error("Couldn't find corresponding path to node")
)
} }
pathToNode = result
} }
// Look for the last pipe with the import alias and a call to translate, with a fallback to rotate. // Look for the last pipe with the import alias and a call to translate, with a fallback to rotate.
@ -2856,25 +2846,16 @@ export const modelingMachine = setup({
const { roll, pitch, yaw, nodeToEdit, selection } = input const { roll, pitch, yaw, nodeToEdit, selection } = input
let pathToNode = nodeToEdit let pathToNode = nodeToEdit
if (!(pathToNode && typeof pathToNode[1][0] === 'number')) { if (!(pathToNode && typeof pathToNode[1][0] === 'number')) {
if (selection?.graphSelections[0].artifact) { const result = retrievePathToNodeFromTransformSelection(
const children = findAllChildrenAndOrderByPlaceInCode( selection,
selection?.graphSelections[0].artifact, kclManager.artifactGraph,
kclManager.artifactGraph ast
) )
const variable = getLastVariable(children, modifiedAst) if (err(result)) {
if (!variable) { return Promise.reject(result)
return Promise.reject(
new Error("Couldn't find corresponding path to node")
)
}
pathToNode = variable.pathToNode
} else if (selection?.graphSelections[0].codeRef.pathToNode) {
pathToNode = selection?.graphSelections[0].codeRef.pathToNode
} else {
return Promise.reject(
new Error("Couldn't find corresponding path to node")
)
} }
pathToNode = result
} }
// Look for the last pipe with the import alias and a call to rotate, with a fallback to translate. // Look for the last pipe with the import alias and a call to rotate, with a fallback to translate.
@ -2942,25 +2923,16 @@ export const modelingMachine = setup({
const { nodeToEdit, selection, variableName } = input const { nodeToEdit, selection, variableName } = input
let pathToNode = nodeToEdit let pathToNode = nodeToEdit
if (!(pathToNode && typeof pathToNode[1][0] === 'number')) { if (!(pathToNode && typeof pathToNode[1][0] === 'number')) {
if (selection?.graphSelections[0].artifact) { const result = retrievePathToNodeFromTransformSelection(
const children = findAllChildrenAndOrderByPlaceInCode( selection,
selection?.graphSelections[0].artifact, kclManager.artifactGraph,
kclManager.artifactGraph ast
) )
const variable = getLastVariable(children, ast) if (err(result)) {
if (!variable) { return Promise.reject(result)
return Promise.reject(
new Error("Couldn't find corresponding path to node")
)
}
pathToNode = variable.pathToNode
} else if (selection?.graphSelections[0].codeRef.pathToNode) {
pathToNode = selection?.graphSelections[0].codeRef.pathToNode
} else {
return Promise.reject(
new Error("Couldn't find corresponding path to node")
)
} }
pathToNode = result
} }
const returnEarly = true const returnEarly = true