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)
|
sketch001 = startSketchOn(XZ)
|
||||||
profile001 = ${circleCode}`
|
profile001 = ${circleCode}`
|
||||||
const sweepDeclaration = 'sweep001 = sweep(profile001, path = helix001)'
|
const sweepDeclaration = 'sweep001 = sweep(profile001, path = helix001)'
|
||||||
|
const editedSweepDeclaration = `sweep001 = sweep(profile001, path = helix001, relativeTo = 'sketchPlane')`
|
||||||
|
|
||||||
await context.addInitScript((initialCode) => {
|
await context.addInitScript((initialCode) => {
|
||||||
localStorage.setItem('persistCode', initialCode)
|
localStorage.setItem('persistCode', initialCode)
|
||||||
@ -2015,11 +2016,43 @@ profile001 = ${circleCode}`
|
|||||||
await editor.expectEditor.toContain(sweepDeclaration)
|
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 () => {
|
await test.step('Delete sweep via feature tree selection', async () => {
|
||||||
const sweep = await toolbar.getFeatureTreeOperation('Sweep', 0)
|
const sweep = await toolbar.getFeatureTreeOperation('Sweep', 0)
|
||||||
await sweep.click()
|
await sweep.click()
|
||||||
await page.keyboard.press('Delete')
|
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,
|
sketches,
|
||||||
path,
|
path,
|
||||||
sectional,
|
sectional,
|
||||||
|
relativeTo,
|
||||||
nodeToEdit,
|
nodeToEdit,
|
||||||
}: {
|
}: {
|
||||||
ast: Node<Program>
|
ast: Node<Program>
|
||||||
sketches: Selections
|
sketches: Selections
|
||||||
path: Selections
|
path: Selections
|
||||||
sectional?: boolean
|
sectional?: boolean
|
||||||
|
relativeTo?: string
|
||||||
nodeToEdit?: PathToNode
|
nodeToEdit?: PathToNode
|
||||||
}):
|
}):
|
||||||
| {
|
| {
|
||||||
@ -190,11 +192,15 @@ export function addSweep({
|
|||||||
const sectionalExpr = sectional
|
const sectionalExpr = sectional
|
||||||
? [createLabeledArg('sectional', createLiteral(sectional))]
|
? [createLabeledArg('sectional', createLiteral(sectional))]
|
||||||
: []
|
: []
|
||||||
|
const relativeToExpr = relativeTo
|
||||||
|
? [createLabeledArg('relativeTo', createLiteral(relativeTo))]
|
||||||
|
: []
|
||||||
|
|
||||||
const sketchesExpr = createSketchExpression(sketchesExprList)
|
const sketchesExpr = createSketchExpression(sketchesExprList)
|
||||||
const call = createCallExpressionStdLibKw('sweep', sketchesExpr, [
|
const call = createCallExpressionStdLibKw('sweep', sketchesExpr, [
|
||||||
createLabeledArg('path', pathExpr),
|
createLabeledArg('path', pathExpr),
|
||||||
...sectionalExpr,
|
...sectionalExpr,
|
||||||
|
...relativeToExpr,
|
||||||
])
|
])
|
||||||
|
|
||||||
// 3. If edit, we assign the new function call declaration to the existing node,
|
// 3. If edit, we assign the new function call declaration to the existing node,
|
||||||
|
@ -86,6 +86,7 @@ export type ModelingCommandSchema = {
|
|||||||
sketches: Selections
|
sketches: Selections
|
||||||
path: Selections
|
path: Selections
|
||||||
sectional?: boolean
|
sectional?: boolean
|
||||||
|
relativeTo?: string
|
||||||
}
|
}
|
||||||
Loft: {
|
Loft: {
|
||||||
sketches: Selections
|
sketches: Selections
|
||||||
@ -455,13 +456,19 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
sectional: {
|
sectional: {
|
||||||
inputType: 'options',
|
inputType: 'options',
|
||||||
skip: true,
|
|
||||||
required: false,
|
required: false,
|
||||||
options: [
|
options: [
|
||||||
{ name: 'False', value: false },
|
{ name: 'False', value: false },
|
||||||
{ name: 'True', value: true },
|
{ 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
|
// 2. Prepare labeled arguments
|
||||||
// Same roundabout but twice for 'path' aka trajectory: sketch -> path -> segment
|
// Same roundabout but twice for 'path' aka trajectory: sketch -> path -> segment
|
||||||
if (operation.labeledArgs.path?.value.type !== 'Sketch') {
|
if (
|
||||||
return { reason: "Couldn't retrieve trajectory argument" }
|
operation.labeledArgs.path?.value.type !== 'Sketch' &&
|
||||||
|
operation.labeledArgs.path?.value.type !== 'Helix'
|
||||||
|
) {
|
||||||
|
return { reason: "Couldn't retrieve path argument" }
|
||||||
}
|
}
|
||||||
|
|
||||||
const trajectoryPathArtifact = getArtifactOfTypes(
|
const trajectoryPathArtifact = getArtifactOfTypes(
|
||||||
{
|
{
|
||||||
key: operation.labeledArgs.path.value.value.artifactId,
|
key: operation.labeledArgs.path.value.value.artifactId,
|
||||||
types: ['path'],
|
types: ['path', 'helix'],
|
||||||
},
|
},
|
||||||
kclManager.artifactGraph
|
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" }
|
return { reason: "Couldn't retrieve trajectory path artifact" }
|
||||||
}
|
}
|
||||||
|
|
||||||
const trajectoryArtifact = getArtifactOfTypes(
|
const trajectoryArtifact =
|
||||||
{
|
trajectoryPathArtifact.type === 'path'
|
||||||
key: trajectoryPathArtifact.segIds[0],
|
? getArtifactOfTypes(
|
||||||
types: ['segment'],
|
{
|
||||||
},
|
key: trajectoryPathArtifact.segIds[0],
|
||||||
kclManager.artifactGraph
|
types: ['segment'],
|
||||||
)
|
},
|
||||||
|
kclManager.artifactGraph
|
||||||
|
)
|
||||||
|
: trajectoryPathArtifact
|
||||||
|
|
||||||
if (err(trajectoryArtifact) || trajectoryArtifact.type !== 'segment') {
|
if (
|
||||||
console.log(trajectoryArtifact)
|
err(trajectoryArtifact) ||
|
||||||
|
(trajectoryArtifact.type !== 'segment' &&
|
||||||
|
trajectoryArtifact.type !== 'helix')
|
||||||
|
) {
|
||||||
return { reason: "Couldn't retrieve trajectory artifact" }
|
return { reason: "Couldn't retrieve trajectory artifact" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,7 +570,7 @@ const prepareToEditSweep: PrepareToEditCallback = async ({ operation }) => {
|
|||||||
otherSelections: [],
|
otherSelections: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
// sectional argument from a string to a KCL expression
|
// optional arguments
|
||||||
let sectional: boolean | undefined
|
let sectional: boolean | undefined
|
||||||
if ('sectional' in operation.labeledArgs && operation.labeledArgs.sectional) {
|
if ('sectional' in operation.labeledArgs && operation.labeledArgs.sectional) {
|
||||||
sectional =
|
sectional =
|
||||||
@ -567,6 +580,17 @@ const prepareToEditSweep: PrepareToEditCallback = async ({ operation }) => {
|
|||||||
) === 'true'
|
) === '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,
|
// 3. Assemble the default argument values for the command,
|
||||||
// with `nodeToEdit` set, which will let the actor know
|
// with `nodeToEdit` set, which will let the actor know
|
||||||
// to edit the node that corresponds to the StdLibCall.
|
// to edit the node that corresponds to the StdLibCall.
|
||||||
@ -574,6 +598,7 @@ const prepareToEditSweep: PrepareToEditCallback = async ({ operation }) => {
|
|||||||
sketches,
|
sketches,
|
||||||
path,
|
path,
|
||||||
sectional,
|
sectional,
|
||||||
|
relativeTo,
|
||||||
nodeToEdit: pathToNodeFromRustNodePath(operation.nodePath),
|
nodeToEdit: pathToNodeFromRustNodePath(operation.nodePath),
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -288,7 +288,10 @@ export const commandBarMachine = setup({
|
|||||||
argConfig.skip ||
|
argConfig.skip ||
|
||||||
(typeof argConfig.hidden === 'function'
|
(typeof argConfig.hidden === 'function'
|
||||||
? argConfig.hidden(context)
|
? argConfig.hidden(context)
|
||||||
: argConfig.hidden)
|
: argConfig.hidden) ||
|
||||||
|
(typeof argConfig.required === 'function'
|
||||||
|
? !argConfig.required(context)
|
||||||
|
: !argConfig.required)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
'Has selected command': ({ context }) => !!context.selectedCommand,
|
'Has selected command': ({ context }) => !!context.selectedCommand,
|
||||||
|
@ -2482,14 +2482,10 @@ export const modelingMachine = setup({
|
|||||||
return Promise.reject(new Error(NO_INPUT_PROVIDED_MESSAGE))
|
return Promise.reject(new Error(NO_INPUT_PROVIDED_MESSAGE))
|
||||||
}
|
}
|
||||||
|
|
||||||
const { nodeToEdit, sketches, path, sectional } = input
|
|
||||||
const { ast } = kclManager
|
const { ast } = kclManager
|
||||||
const astResult = addSweep({
|
const astResult = addSweep({
|
||||||
|
...input,
|
||||||
ast,
|
ast,
|
||||||
sketches,
|
|
||||||
path,
|
|
||||||
sectional,
|
|
||||||
nodeToEdit,
|
|
||||||
})
|
})
|
||||||
if (err(astResult)) {
|
if (err(astResult)) {
|
||||||
return Promise.reject(astResult)
|
return Promise.reject(astResult)
|
||||||
|
Reference in New Issue
Block a user