Enable optional arguments in point-and-click Sweep (#7580)
* Enable optional arguments in point-and-click Sweep Fixes #7578 * Fix bug and add e2e test step * Fix review not triggering bug and e2e test
This commit is contained in:
@ -1954,6 +1954,7 @@ profile002 = startProfile(sketch002, at = [0, 0])
|
||||
sketch001 = startSketchOn(XZ)
|
||||
profile001 = ${circleCode}`
|
||||
const sweepDeclaration = 'sweep001 = sweep(profile001, path = helix001)'
|
||||
const editedSweepDeclaration = `sweep001 = sweep(profile001, path = helix001, relativeTo = 'sketchPlane')`
|
||||
|
||||
await context.addInitScript((initialCode) => {
|
||||
localStorage.setItem('persistCode', initialCode)
|
||||
@ -2015,11 +2016,43 @@ profile001 = ${circleCode}`
|
||||
await editor.expectEditor.toContain(sweepDeclaration)
|
||||
})
|
||||
|
||||
await test.step('Go through the edit flow via feature tree', async () => {
|
||||
await toolbar.openPane('feature-tree')
|
||||
const op = await toolbar.getFeatureTreeOperation('Sweep', 0)
|
||||
await op.dblclick()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {},
|
||||
commandName: 'Sweep',
|
||||
})
|
||||
await cmdBar.clickOptionalArgument('relativeTo')
|
||||
await cmdBar.expectState({
|
||||
stage: 'arguments',
|
||||
currentArgKey: 'relativeTo',
|
||||
currentArgValue: '',
|
||||
headerArguments: {
|
||||
RelativeTo: '',
|
||||
},
|
||||
highlightedHeaderArg: 'relativeTo',
|
||||
commandName: 'Sweep',
|
||||
})
|
||||
await cmdBar.selectOption({ name: 'sketchPlane' }).click()
|
||||
await cmdBar.expectState({
|
||||
stage: 'review',
|
||||
headerArguments: {
|
||||
RelativeTo: 'sketchPlane',
|
||||
},
|
||||
commandName: 'Sweep',
|
||||
})
|
||||
await cmdBar.submit()
|
||||
await editor.expectEditor.toContain(editedSweepDeclaration)
|
||||
})
|
||||
|
||||
await test.step('Delete sweep via feature tree selection', async () => {
|
||||
const sweep = await toolbar.getFeatureTreeOperation('Sweep', 0)
|
||||
await sweep.click()
|
||||
await page.keyboard.press('Delete')
|
||||
await editor.expectEditor.not.toContain(sweepDeclaration)
|
||||
await editor.expectEditor.not.toContain(editedSweepDeclaration)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -148,12 +148,14 @@ export function addSweep({
|
||||
sketches,
|
||||
path,
|
||||
sectional,
|
||||
relativeTo,
|
||||
nodeToEdit,
|
||||
}: {
|
||||
ast: Node<Program>
|
||||
sketches: Selections
|
||||
path: Selections
|
||||
sectional?: boolean
|
||||
relativeTo?: string
|
||||
nodeToEdit?: PathToNode
|
||||
}):
|
||||
| {
|
||||
@ -190,11 +192,15 @@ export function addSweep({
|
||||
const sectionalExpr = sectional
|
||||
? [createLabeledArg('sectional', createLiteral(sectional))]
|
||||
: []
|
||||
const relativeToExpr = relativeTo
|
||||
? [createLabeledArg('relativeTo', createLiteral(relativeTo))]
|
||||
: []
|
||||
|
||||
const sketchesExpr = createSketchExpression(sketchesExprList)
|
||||
const call = createCallExpressionStdLibKw('sweep', sketchesExpr, [
|
||||
createLabeledArg('path', pathExpr),
|
||||
...sectionalExpr,
|
||||
...relativeToExpr,
|
||||
])
|
||||
|
||||
// 3. If edit, we assign the new function call declaration to the existing node,
|
||||
|
@ -86,6 +86,7 @@ export type ModelingCommandSchema = {
|
||||
sketches: Selections
|
||||
path: Selections
|
||||
sectional?: boolean
|
||||
relativeTo?: string
|
||||
}
|
||||
Loft: {
|
||||
sketches: Selections
|
||||
@ -455,13 +456,19 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
||||
},
|
||||
sectional: {
|
||||
inputType: 'options',
|
||||
skip: true,
|
||||
required: false,
|
||||
options: [
|
||||
{ name: 'False', value: false },
|
||||
{ name: 'True', value: true },
|
||||
],
|
||||
// No validation possible here until we have rollback
|
||||
},
|
||||
relativeTo: {
|
||||
inputType: 'options',
|
||||
required: false,
|
||||
options: [
|
||||
{ name: 'sketchPlane', value: 'sketchPlane' },
|
||||
{ name: 'trajectoryCurve', value: 'trajectoryCurve' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -518,32 +518,45 @@ const prepareToEditSweep: PrepareToEditCallback = async ({ operation }) => {
|
||||
|
||||
// 2. Prepare labeled arguments
|
||||
// Same roundabout but twice for 'path' aka trajectory: sketch -> path -> segment
|
||||
if (operation.labeledArgs.path?.value.type !== 'Sketch') {
|
||||
return { reason: "Couldn't retrieve trajectory argument" }
|
||||
if (
|
||||
operation.labeledArgs.path?.value.type !== 'Sketch' &&
|
||||
operation.labeledArgs.path?.value.type !== 'Helix'
|
||||
) {
|
||||
return { reason: "Couldn't retrieve path argument" }
|
||||
}
|
||||
|
||||
const trajectoryPathArtifact = getArtifactOfTypes(
|
||||
{
|
||||
key: operation.labeledArgs.path.value.value.artifactId,
|
||||
types: ['path'],
|
||||
types: ['path', 'helix'],
|
||||
},
|
||||
kclManager.artifactGraph
|
||||
)
|
||||
|
||||
if (err(trajectoryPathArtifact) || trajectoryPathArtifact.type !== 'path') {
|
||||
if (
|
||||
err(trajectoryPathArtifact) ||
|
||||
(trajectoryPathArtifact.type !== 'path' &&
|
||||
trajectoryPathArtifact.type !== 'helix')
|
||||
) {
|
||||
return { reason: "Couldn't retrieve trajectory path artifact" }
|
||||
}
|
||||
|
||||
const trajectoryArtifact = getArtifactOfTypes(
|
||||
const trajectoryArtifact =
|
||||
trajectoryPathArtifact.type === 'path'
|
||||
? getArtifactOfTypes(
|
||||
{
|
||||
key: trajectoryPathArtifact.segIds[0],
|
||||
types: ['segment'],
|
||||
},
|
||||
kclManager.artifactGraph
|
||||
)
|
||||
: trajectoryPathArtifact
|
||||
|
||||
if (err(trajectoryArtifact) || trajectoryArtifact.type !== 'segment') {
|
||||
console.log(trajectoryArtifact)
|
||||
if (
|
||||
err(trajectoryArtifact) ||
|
||||
(trajectoryArtifact.type !== 'segment' &&
|
||||
trajectoryArtifact.type !== 'helix')
|
||||
) {
|
||||
return { reason: "Couldn't retrieve trajectory artifact" }
|
||||
}
|
||||
|
||||
@ -557,7 +570,7 @@ const prepareToEditSweep: PrepareToEditCallback = async ({ operation }) => {
|
||||
otherSelections: [],
|
||||
}
|
||||
|
||||
// sectional argument from a string to a KCL expression
|
||||
// optional arguments
|
||||
let sectional: boolean | undefined
|
||||
if ('sectional' in operation.labeledArgs && operation.labeledArgs.sectional) {
|
||||
sectional =
|
||||
@ -567,6 +580,17 @@ const prepareToEditSweep: PrepareToEditCallback = async ({ operation }) => {
|
||||
) === 'true'
|
||||
}
|
||||
|
||||
let relativeTo: string | undefined
|
||||
if (
|
||||
'relativeTo' in operation.labeledArgs &&
|
||||
operation.labeledArgs.relativeTo
|
||||
) {
|
||||
relativeTo = codeManager.code.slice(
|
||||
operation.labeledArgs.relativeTo.sourceRange[0],
|
||||
operation.labeledArgs.relativeTo.sourceRange[1]
|
||||
)
|
||||
}
|
||||
|
||||
// 3. Assemble the default argument values for the command,
|
||||
// with `nodeToEdit` set, which will let the actor know
|
||||
// to edit the node that corresponds to the StdLibCall.
|
||||
@ -574,6 +598,7 @@ const prepareToEditSweep: PrepareToEditCallback = async ({ operation }) => {
|
||||
sketches,
|
||||
path,
|
||||
sectional,
|
||||
relativeTo,
|
||||
nodeToEdit: pathToNodeFromRustNodePath(operation.nodePath),
|
||||
}
|
||||
return {
|
||||
|
@ -288,7 +288,10 @@ export const commandBarMachine = setup({
|
||||
argConfig.skip ||
|
||||
(typeof argConfig.hidden === 'function'
|
||||
? argConfig.hidden(context)
|
||||
: argConfig.hidden)
|
||||
: argConfig.hidden) ||
|
||||
(typeof argConfig.required === 'function'
|
||||
? !argConfig.required(context)
|
||||
: !argConfig.required)
|
||||
)
|
||||
},
|
||||
'Has selected command': ({ context }) => !!context.selectedCommand,
|
||||
|
@ -2482,14 +2482,10 @@ export const modelingMachine = setup({
|
||||
return Promise.reject(new Error(NO_INPUT_PROVIDED_MESSAGE))
|
||||
}
|
||||
|
||||
const { nodeToEdit, sketches, path, sectional } = input
|
||||
const { ast } = kclManager
|
||||
const astResult = addSweep({
|
||||
...input,
|
||||
ast,
|
||||
sketches,
|
||||
path,
|
||||
sectional,
|
||||
nodeToEdit,
|
||||
})
|
||||
if (err(astResult)) {
|
||||
return Promise.reject(astResult)
|
||||
|
Reference in New Issue
Block a user