Add edit flows for extrude and offset plane operations (#5045)

* Start implementing a "prepareToEdit" callback for extrude

* Start of generic edit flow for operations

* Actually invoking command bar send generically on double-click

* Refactor: break out non-React hook helper to calculate Kcl expression value

* Add unit tests, fmt

* Integrate helper to get calculated KclExpression

* Clean up unused imports, simplify use of `programMemoryFromVariables`

* Implement basic extrude editing

* Refactor: move DefaultPlanesStr to its own lib file

* Add support for editing offset planes

* Add Edit right-click menu option

* Turn off edit flow for sketch for now

* Add e2e tests for sketch and offset plane editing, fix bug found with offset plane editing

* Add failing e2e extrude edit test

* Remove action version of extrude AST mod

* Fix behavior when adding a constant while editing operation, fixing e2e test

* Patch in changes from 61b02b5703

* Remove shell's prepareToEdit

* Add other Surface types to `artifactIsPlaneWithPaths`

* refactor: rename `item` to `operation`

* Allow `prepareToEdit` to fail with a toast, signal sketch-on-offset is unimplemented

* Rework sketch e2e test to test several working and failing cases

* Fix tsc errors related to making `codeRef` optional

* Make basic error messages more friendly

* fmt

* Reset modifyAst.ts to main

* Fix broken artifactGraph unit test

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Remove unused import

* Look at this (photo)Graph *in the voice of Nickelback*

* Make the offset plane insert at the end, not one before

* Fix bug caught by e2e test failure with "Command needs review" logic

* Update src/machines/modelingMachine.ts

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>

* Remove console logs per @pierremtb

* Update src/components/CommandBar/CommandBarHeader.tsx

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

* Use better programMemory init thanks @jtran

* Fix tsc post merge of #5068

* Fix logic for `artifactIsPlaneWithPaths` post-merge

* Need to disable the sketch-on-face case now that artifactGraph is in Rust. Will active in a future PR (cc @jtran)

* Re-run CI after snapshots

* Update FeatureTreePane to not use `useCommandsContext`, missed during merge

* Fix merge issue, import location change on edited file

* fix click test step, which I believe is waiting for context scripts to load

* Convert toolbarFixture.exeIndicator to getter

We need to convert all these selectors on fixtures to getters, because
they can go stale if called on the fixture constructor.

* Missed a dumb little thing in toolbarFixture.ts

* Fix goof with merge

* fmt

* Another dumb missed thing during merge

I gotta get used to the LazyGit merge tool I'm not good at it yet

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Conver sceneFixture's exeIndicator to a getter

Locators on fixtures will be frozen from the time of the fixture's
initialization, I'm increasingly convinced

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* Post-kwargs E2E test cleanup

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
This commit is contained in:
Frank Noirot
2025-02-05 19:33:40 -05:00
committed by GitHub
parent eb4048cd16
commit 9008fb636f
28 changed files with 1054 additions and 318 deletions

View File

@ -70,7 +70,8 @@ import {
} from 'components/Toolbar/SetAbsDistance'
import { ModelingCommandSchema } from 'lib/commandBarConfigs/modelingCommandConfig'
import { err, reportRejection, trap } from 'lib/trap'
import { DefaultPlaneStr, getFaceDetails } from 'clientSideScene/sceneEntities'
import { getFaceDetails } from 'clientSideScene/sceneEntities'
import { DefaultPlaneStr } from 'lib/planes'
import { uuidv4 } from 'lib/utils'
import { Coords2d } from 'lang/std/sketch'
import { deleteSegment } from 'clientSideScene/ClientSideSceneComp'
@ -1452,24 +1453,49 @@ export const modelingMachine = setup({
unknown,
ModelingCommandSchema['Extrude'] | undefined
>(async ({ input }) => {
if (!input) return Promise.reject('No input provided')
const { selection, distance } = input
if (!input) return new Error('No input provided')
const { selection, distance, nodeToEdit } = input
const isEditing =
nodeToEdit !== undefined && typeof nodeToEdit[1][0] === 'number'
let ast = structuredClone(kclManager.ast)
let extrudeName: string | undefined = undefined
// If this is an edit flow, first we're going to remove the old extrusion
if (isEditing) {
// Extract the plane name from the node to edit
const extrudeNameNode = getNodeFromPath<VariableDeclaration>(
ast,
nodeToEdit,
'VariableDeclaration'
)
if (err(extrudeNameNode)) {
console.error('Error extracting plane name')
} else {
extrudeName = extrudeNameNode.node.declaration.id.name
}
// Removing the old extrusion statement
const newBody = [...ast.body]
newBody.splice(nodeToEdit[1][0] as number, 1)
ast.body = newBody
}
const pathToNode = getNodePathFromSourceRange(
ast,
selection.graphSelections[0]?.codeRef.range
)
// Add an extrude statement to the AST
const extrudeSketchRes = extrudeSketch(
ast,
const extrudeSketchRes = extrudeSketch({
node: ast,
pathToNode,
false,
'variableName' in distance
? distance.variableIdentifierAst
: distance.valueAst
)
if (err(extrudeSketchRes)) return Promise.reject(extrudeSketchRes)
shouldPipe: false,
distance:
'variableName' in distance
? distance.variableIdentifierAst
: distance.valueAst,
extrudeName,
})
if (err(extrudeSketchRes)) return extrudeSketchRes
const { modifiedAst, pathToExtrudeArg } = extrudeSketchRes
// Insert the distance variable if the user has provided a variable name
@ -1513,30 +1539,37 @@ export const modelingMachine = setup({
if (!input) return new Error('No input provided')
// Extract inputs
const ast = kclManager.ast
const { plane: selection, distance } = input
const { plane: selection, distance, nodeToEdit } = input
let insertIndex: number | undefined = undefined
let planeName: string | undefined = undefined
// If this is an edit flow, first we're going to remove the old plane
if (nodeToEdit && typeof nodeToEdit[1][0] === 'number') {
// Extract the plane name from the node to edit
const planeNameNode = getNodeFromPath<VariableDeclaration>(
ast,
nodeToEdit,
'VariableDeclaration'
)
if (err(planeNameNode)) {
console.error('Error extracting plane name')
} else {
planeName = planeNameNode.node.declaration.id.name
}
const newBody = [...ast.body]
newBody.splice(nodeToEdit[1][0], 1)
ast.body = newBody
insertIndex = nodeToEdit[1][0]
}
// Extract the default plane from selection
const plane = selection.otherSelections[0]
if (!(plane && plane instanceof Object && 'name' in plane))
return trap('No plane selected')
// Insert the distance variable if it exists
if (
'variableName' in distance &&
distance.variableName &&
distance.insertIndex !== undefined
) {
const newBody = [...ast.body]
newBody.splice(
distance.insertIndex,
0,
distance.variableDeclarationAst
)
ast.body = newBody
}
// Get the default plane name from the selection
const offsetPlaneResult = addOffsetPlane({
node: ast,
defaultPlane: plane.name,
@ -1544,8 +1577,27 @@ export const modelingMachine = setup({
'variableName' in distance
? distance.variableIdentifierAst
: distance.valueAst,
insertIndex,
planeName,
})
// Insert the distance variable if the user has provided a variable name
if (
'variableName' in distance &&
distance.variableName &&
typeof offsetPlaneResult.pathToNode[1][0] === 'number'
) {
const insertIndex = Math.min(
offsetPlaneResult.pathToNode[1][0],
distance.insertIndex
)
const newBody = [...offsetPlaneResult.modifiedAst.body]
newBody.splice(insertIndex, 0, distance.variableDeclarationAst)
offsetPlaneResult.modifiedAst.body = newBody
// Since we inserted a new variable, we need to update the path to the extrude argument
offsetPlaneResult.pathToNode[1][0]++
}
const updateAstResult = await kclManager.updateAst(
offsetPlaneResult.modifiedAst,
true,