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:
@ -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)
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
Reference in New Issue
Block a user