diff --git a/e2e/playwright/sketch-tests.spec.ts b/e2e/playwright/sketch-tests.spec.ts index 642d2e9e2..98dae2028 100644 --- a/e2e/playwright/sketch-tests.spec.ts +++ b/e2e/playwright/sketch-tests.spec.ts @@ -187,6 +187,68 @@ sketch001 = startProfile(sketch002, at = [12.34, -12.34]) page.getByRole('button', { name: 'Start Sketch' }) ).toBeVisible() }) + + test('Can select planes in Feature Tree after Start Sketch', async ({ + page, + homePage, + toolbar, + editor, + }) => { + // Load the app with empty code + await page.addInitScript(async () => { + localStorage.setItem( + 'persistCode', + `plane001 = offsetPlane(XZ, offset = 5)` + ) + }) + + await page.setBodyDimensions({ width: 1200, height: 500 }) + + await homePage.goToModelingScene() + + await test.step('Click Start Sketch button', async () => { + await page.getByRole('button', { name: 'Start Sketch' }).click() + await expect( + page.getByRole('button', { name: 'Exit Sketch' }) + ).toBeVisible() + await expect(page.getByText('select a plane or face')).toBeVisible() + }) + + await test.step('Open feature tree and select Front plane (XZ)', async () => { + await toolbar.openFeatureTreePane() + + await page.getByRole('button', { name: 'Front plane' }).click() + + await page.waitForTimeout(600) + + await expect(toolbar.lineBtn).toBeEnabled() + await editor.expectEditor.toContain('startSketchOn(XZ)') + + await page.getByRole('button', { name: 'Exit Sketch' }).click() + await expect( + page.getByRole('button', { name: 'Start Sketch' }) + ).toBeVisible() + }) + + await test.step('Click Start Sketch button again', async () => { + await page.getByRole('button', { name: 'Start Sketch' }).click() + await expect( + page.getByRole('button', { name: 'Exit Sketch' }) + ).toBeVisible() + }) + + await test.step('Select the offset plane', async () => { + await toolbar.openFeatureTreePane() + + await page.getByRole('button', { name: 'Offset plane' }).click() + + await page.waitForTimeout(600) + + await expect(toolbar.lineBtn).toBeEnabled() + await editor.expectEditor.toContain('startSketchOn(plane001)') + }) + }) + test('Can edit segments by dragging their handles', () => { const doEditSegmentsByDraggingHandle = async ( page: Page, diff --git a/src/components/ModelingSidebar/ModelingPanes/FeatureTreePane.tsx b/src/components/ModelingSidebar/ModelingPanes/FeatureTreePane.tsx index 8bfd22297..1311fcdb8 100644 --- a/src/components/ModelingSidebar/ModelingPanes/FeatureTreePane.tsx +++ b/src/components/ModelingSidebar/ModelingPanes/FeatureTreePane.tsx @@ -24,7 +24,12 @@ import { getOperationVariableName, stdLibMap, } from '@src/lib/operations' -import { editorManager, kclManager, rustContext } from '@src/lib/singletons' +import { + editorManager, + kclManager, + rustContext, + sceneInfra, +} from '@src/lib/singletons' import { featureTreeMachine, featureTreeMachineDefaultContext, @@ -34,11 +39,20 @@ import { kclEditorActor, selectionEventSelector, } from '@src/machines/kclEditorMachine' +import type { Plane } from '@rust/kcl-lib/bindings/Artifact' +import { + selectDefaultSketchPlane, + selectOffsetSketchPlane, +} from '@src/lib/selections' +import type { DefaultPlaneStr } from '@src/lib/planes' export const FeatureTreePane = () => { const isEditorMounted = useSelector(kclEditorActor, editorIsMountedSelector) const lastSelectionEvent = useSelector(kclEditorActor, selectionEventSelector) const { send: modelingSend, state: modelingState } = useModelingContext() + + const sketchNoFace = modelingState.matches('Sketch no face') + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_featureTreeState, featureTreeSend] = useMachine( featureTreeMachine.provide({ @@ -195,6 +209,7 @@ export const FeatureTreePane = () => { key={key} item={operation} send={featureTreeSend} + sketchNoFace={sketchNoFace} /> ) })} @@ -251,6 +266,7 @@ const OperationItemWrapper = ({ customSuffix, className, selectable = true, + greyedOut = false, ...props }: React.HTMLAttributes & { icon: CustomIconName @@ -262,18 +278,19 @@ const OperationItemWrapper = ({ menuItems?: ComponentProps['items'] errors?: Diagnostic[] selectable?: boolean + greyedOut?: boolean }) => { const menuRef = useRef(null) return (