Skip to content

Commit

Permalink
Update selections after constraint is applied [equal length, parallel…
Browse files Browse the repository at this point in the history
…, snap to x or y] (#2543)

* migrate one constraint

* typo

* update snap to y, snap to x, horz align, vert align, equal length

* add some e2e tests

* add e2e test for snap to axis contsraits

* remove works for now
  • Loading branch information
Irev-Dev authored May 30, 2024
1 parent e6641e6 commit 4b676d4
Show file tree
Hide file tree
Showing 6 changed files with 407 additions and 112 deletions.
152 changes: 152 additions & 0 deletions e2e/playwright/flow-tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2439,6 +2439,158 @@ test('Extrude from command bar selects extrude line after', async ({
)
})

test.describe('Testing constraints', () => {
test.describe('Two segment - no modal constraints', () => {
const cases = [
{
codeAfter: `|> angledLine([83, segLen('seg01', %)], %)`,
constraintName: 'Equal Length',
},
{
codeAfter: `|> angledLine([segAng('seg01', %), 78.33], %)`,
constraintName: 'Parallel',
},
{
codeAfter: `|> lineTo([segEndX('seg01', %), 61.34], %)`,
constraintName: 'Vertically Align',
},
{
codeAfter: `|> lineTo([154.9, segEndY('seg01', %)], %)`,
constraintName: 'Horizontally Align',
},
] as const
for (const { codeAfter, constraintName } of cases) {
test(`${constraintName}`, async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const yo = 5
const part001 = startSketchOn('XZ')
|> startProfileAt([-7.54, -26.74], %)
|> line([74.36, 130.4], %)
|> line([78.92, -120.11], %)
|> line([9.16, 77.79], %)
const part002 = startSketchOn('XZ')
|> startProfileAt([299.05, 231.45], %)
|> xLine(-425.34, %, 'seg-what')
|> yLine(-264.06, %)
|> xLine(segLen('seg-what', %), %)
|> lineTo([profileStartX(%), profileStartY(%)], %)`
)
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()

await page.getByText('line([74.36, 130.4], %)').click()
await page.getByRole('button', { name: 'Edit Sketch' }).click()

const line1 = await u.getBoundingBox(`[data-overlay-index="${0}"]`)
const line3 = await u.getBoundingBox(`[data-overlay-index="${2}"]`)

// select two segments by holding down shift
await page.mouse.click(line1.x - 20, line1.y + 20)
await page.keyboard.down('Shift')
await page.mouse.click(line3.x - 3, line3.y + 20)
await page.keyboard.up('Shift')
const constraintMenuButton = page.getByRole('button', {
name: 'Constrain',
})
const constraintButton = page.getByRole('button', {
name: constraintName,
})

// apply the constraint
await constraintMenuButton.click()
await constraintButton.click()

await expect(page.locator('.cm-content')).toContainText(codeAfter)
// expect the string 'seg01' to appear twice in '.cm-content' the tag segment and referencing the tag
const content = await page.locator('.cm-content').innerText()
await expect(content.match(/seg01/g)).toHaveLength(2)
// check there are still 2 cursors (they should stay on the same lines as before constraint was applied)
await expect(page.locator('.cm-cursor')).toHaveCount(2)
// check actives lines
const activeLinesContent = await page.locator('.cm-activeLine').all()
await expect(activeLinesContent).toHaveLength(2)

// check both cursors are where they should be after constraint is applied
await expect(activeLinesContent[0]).toHaveText(
"|> line([74.36, 130.4], %, 'seg01')"
)
await expect(activeLinesContent[1]).toHaveText(codeAfter)
})
}
})
test.describe('Axis & segment - no modal constraints', () => {
const cases = [
{
codeAfter: `|> lineTo([154.9, ZERO], %)`,
axisClick: { x: 950, y: 250 },
constraintName: 'Snap To X',
},
{
codeAfter: `|> lineTo([ZERO, 61.34], %)`,
axisClick: { x: 600, y: 150 },
constraintName: 'Snap To Y',
},
] as const
for (const { codeAfter, constraintName, axisClick } of cases) {
test(`${constraintName}`, async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const yo = 5
const part001 = startSketchOn('XZ')
|> startProfileAt([-7.54, -26.74], %)
|> line([74.36, 130.4], %)
|> line([78.92, -120.11], %)
|> line([9.16, 77.79], %)
const part002 = startSketchOn('XZ')
|> startProfileAt([299.05, 231.45], %)
|> xLine(-425.34, %, 'seg-what')
|> yLine(-264.06, %)
|> xLine(segLen('seg-what', %), %)
|> lineTo([profileStartX(%), profileStartY(%)], %)`
)
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()

await page.getByText('line([74.36, 130.4], %)').click()
await page.getByRole('button', { name: 'Edit Sketch' }).click()

const line3 = await u.getBoundingBox(`[data-overlay-index="${2}"]`)

// select segment and axis by holding down shift
await page.mouse.click(line3.x - 3, line3.y + 20)
await page.keyboard.down('Shift')
await page.waitForTimeout(100)
await page.mouse.click(axisClick.x, axisClick.y)
await page.keyboard.up('Shift')
const constraintMenuButton = page.getByRole('button', {
name: 'Constrain',
})
const constraintButton = page.getByRole('button', {
name: constraintName,
})

// apply the constraint
await constraintMenuButton.click()
await expect(constraintButton).toBeVisible()
await constraintButton.click()

// check the cursor is where is should be after constraint is applied
await expect(page.locator('.cm-content')).toContainText(codeAfter)
await expect(page.locator('.cm-activeLine')).toHaveText(codeAfter)
})
}
})
})

test.describe('Testing segment overlays', () => {
test.describe('Hover over a segment should show its overlay, hovering over the input overlays should show its popover, clicking the input overlay should constrain/unconstrain it:\nfor the following segments', () => {
/**
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default defineConfig({
/* Retry on CI only */
retries: process.env.CI ? 3 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 2 : 1,
workers: process.env.CI ? 1 : 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
Expand Down
16 changes: 10 additions & 6 deletions src/components/ModelingMachineProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
handleSelectionBatch,
isSelectionLastLine,
isSketchPipe,
updateSelections,

Check warning on line 37 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (macos-14)

'updateSelections' is defined but never used

Check warning on line 37 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (ubuntu-latest)

'updateSelections' is defined but never used

Check warning on line 37 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (windows-latest)

'updateSelections' is defined but never used

Check warning on line 37 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / playwright-ubuntu

'updateSelections' is defined but never used

Check warning on line 37 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / playwright-macos

'updateSelections' is defined but never used

Check warning on line 37 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (ubuntu-latest)

'updateSelections' is defined but never used

Check warning on line 37 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (windows-latest)

'updateSelections' is defined but never used

Check warning on line 37 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (macos-14)

'updateSelections' is defined but never used
} from 'lib/selections'
import { applyConstraintIntersect } from './Toolbar/Intersect'
import { applyConstraintAbsDistance } from './Toolbar/SetAbsDistance'
Expand All @@ -53,6 +54,7 @@ import {
} from 'lang/modifyAst'
import {
Program,
Value,

Check warning on line 57 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (macos-14)

'Value' is defined but never used

Check warning on line 57 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (ubuntu-latest)

'Value' is defined but never used

Check warning on line 57 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (windows-latest)

'Value' is defined but never used

Check warning on line 57 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / playwright-ubuntu

'Value' is defined but never used

Check warning on line 57 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / playwright-macos

'Value' is defined but never used

Check warning on line 57 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (ubuntu-latest)

'Value' is defined but never used

Check warning on line 57 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (windows-latest)

'Value' is defined but never used

Check warning on line 57 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (macos-14)

'Value' is defined but never used
VariableDeclaration,
coreDump,
parse,
Expand All @@ -73,10 +75,7 @@ import { useSearchParams } from 'react-router-dom'
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
import { getVarNameModal } from 'hooks/useToolbarGuards'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
import {
EngineConnectionState,
EngineConnectionStateType,
} from 'lang/std/engineConnection'
import { applyConstraintEqualAngle } from './Toolbar/EqualAngle'

Check warning on line 78 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (macos-14)

'applyConstraintEqualAngle' is defined but never used

Check warning on line 78 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (ubuntu-latest)

'applyConstraintEqualAngle' is defined but never used

Check warning on line 78 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (windows-latest)

'applyConstraintEqualAngle' is defined but never used

Check warning on line 78 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / playwright-ubuntu

'applyConstraintEqualAngle' is defined but never used

Check warning on line 78 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / playwright-macos

'applyConstraintEqualAngle' is defined but never used

Check warning on line 78 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (ubuntu-latest)

'applyConstraintEqualAngle' is defined but never used

Check warning on line 78 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (windows-latest)

'applyConstraintEqualAngle' is defined but never used

Check warning on line 78 in src/components/ModelingMachineProvider.tsx

View workflow job for this annotation

GitHub Actions / build-test-apps (macos-14)

'applyConstraintEqualAngle' is defined but never used

type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T>
Expand Down Expand Up @@ -223,8 +222,7 @@ export const ModelingMachineProvider = ({
: {}
),
'Set selection': assign(({ selectionRanges }, event) => {
if (event.type !== 'Set selection') return {} // this was needed for ts after adding 'Set selection' action to on done modal events
const setSelections = event.data
const setSelections = event.data as SetSelections // this was needed for ts after adding 'Set selection' action to on done modal events
if (!editorManager.editorView) return {}
const dispatchSelection = (selection?: EditorSelection) => {
if (!selection) return // TODO less of hack for the below please
Expand Down Expand Up @@ -311,6 +309,12 @@ export const ModelingMachineProvider = ({
selectionRanges: selections,
}
}
if (setSelections.selectionType === 'completeSelection') {
editorManager.selectRange(setSelections.selection)
return {
selectionRanges: setSelections.selection,
}
}

return {}
}),
Expand Down
2 changes: 1 addition & 1 deletion src/components/Toolbar/setAngleLength.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export async function applyConstraintAngleLength({
pathToNodeMap,
}
} catch (e) {
console.log('erorr', e)
console.log('error', e)
throw e
}
}
22 changes: 21 additions & 1 deletion src/lib/selections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
kclManager,
sceneEntitiesManager,
} from 'lib/singletons'
import { CallExpression, SourceRange, parse, recast } from 'lang/wasm'
import { CallExpression, SourceRange, Value, parse, recast } from 'lang/wasm'
import { ModelingMachineEvent } from 'machines/modelingMachine'
import { uuidv4 } from 'lib/utils'
import { EditorSelection } from '@codemirror/state'
Expand All @@ -27,6 +27,7 @@ import {
} from 'clientSideScene/sceneEntities'
import { Mesh, Object3D, Object3DEventMap } from 'three'
import { AXIS_GROUP, X_AXIS } from 'clientSideScene/sceneInfra'
import { PathToNodeMap } from 'lang/std/sketchcombos'

export const X_AXIS_UUID = 'ad792545-7fd3-482a-a602-a93924e3055b'
export const Y_AXIS_UUID = '680fd157-266f-4b8a-984f-cdf46b8bdf01'
Expand Down Expand Up @@ -564,3 +565,22 @@ export function sendSelectEventToEngine(
.then((res) => res.data.data)
return result
}

export function updateSelections(
pathToNodeMap: PathToNodeMap,
prevSelectionRanges: Selections,
ast: Program
): Selections {
return {
...prevSelectionRanges,
codeBasedSelections: Object.entries(pathToNodeMap).map(
([index, pathToNode]): Selection => {
const node = getNodeFromPath<Value>(ast, pathToNode).node
return {
range: [node.start, node.end],
type: prevSelectionRanges.codeBasedSelections[Number(index)]?.type,
}
}
),
}
}
Loading

0 comments on commit 4b676d4

Please sign in to comment.