Skip to content

Commit 0746fd1

Browse files
pierremtbrajgandhi1nadr0andrewvarga
authored
Right click a feature on the model to center the code pane on it (#7890)
* Right click a feature on the model to center the code pane on it #7447 * bug fixes * [Bug fix]: Do not store token in window! (#7671) * fix: we really cannot do this * fix: limiting footprint * * Add ability to pick default plane in feature tree in 'Sketch no face' mode * add ability to select deoffset plane where starting a new sketch * use selectDefaultSketchPlane * refactor: remove some duplication * warning cleanups * feature tree items selectable depedngin on no face sketch mode * lint * fix small jump because of border:none when going into and back from 'No face sketch' mode * grey out items other than offset planes in 'No face sketch' mode * start sketching on plane in context menu * sketch on offset plane with context menu * add ability to right click on default plane and start sketch on it * default planes in feature tree should be selectable because of right click context menu * add right click Start sketch option for selected plane on the canvas * selectDefaultSketchPlane returns error now * circular deps * move select functions to lib/selections.ts to avoid circular deps * add test for clicking on feature tree after starting a new sketch * graphite suggestion * fix bug of not being able to create offset plane using another offset plane with command bar * add ability to select default plane on feature when going through the Offset plane command bar flow * Right click a feature on the model to center the code pane on it #7447 * bug fixes * removed duplicate code. * added basic playwright test * Unify repeated logic and move test to testing-selections spec file * Add test case for succesful right click to code * Remove TODO and clean up useMemo deps --------- Co-authored-by: rajgandhi1 <[email protected]> Co-authored-by: Kevin Nadro <[email protected]> Co-authored-by: Andrew Varga <[email protected]>
1 parent 199d5a3 commit 0746fd1

File tree

3 files changed

+127
-8
lines changed

3 files changed

+127
-8
lines changed

e2e/playwright/fixtures/sceneFixture.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { expect } from '@e2e/playwright/zoo-test'
1616
type MouseParams = {
1717
pixelDiff?: number
1818
shouldDbClick?: boolean
19+
shouldRightClick?: boolean
1920
delay?: number
2021
}
2122
type MouseDragToParams = MouseParams & {
@@ -137,19 +138,29 @@ export class SceneFixture {
137138
? this.page.mouse.dblclick(resolvedPoint.x, resolvedPoint.y, {
138139
delay: clickParams?.delay || 0,
139140
})
140-
: this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
141-
delay: clickParams?.delay || 0,
142-
}),
141+
: clickParams?.shouldRightClick
142+
? this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
143+
button: 'right',
144+
delay: clickParams?.delay || 0,
145+
})
146+
: this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
147+
delay: clickParams?.delay || 0,
148+
}),
143149
clickParams.pixelDiff
144150
)
145151
}
146152
return clickParams?.shouldDbClick
147153
? this.page.mouse.dblclick(resolvedPoint.x, resolvedPoint.y, {
148154
delay: clickParams?.delay || 0,
149155
})
150-
: this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
151-
delay: clickParams?.delay || 0,
152-
})
156+
: clickParams?.shouldRightClick
157+
? this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
158+
button: 'right',
159+
delay: clickParams?.delay || 0,
160+
})
161+
: this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
162+
delay: clickParams?.delay || 0,
163+
})
153164
},
154165
async (moveParams?: MouseParams) => {
155166
const resolvedPoint = await this.convertPagePositionToStream(

e2e/playwright/testing-selections.spec.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
22
import { getUtils } from '@e2e/playwright/test-utils'
33
import { expect, test } from '@e2e/playwright/zoo-test'
4+
import { bracket } from '@e2e/playwright/fixtures/bracket'
45

56
test.describe('Testing selections', () => {
67
test('parent Solid should be select and deletable and uses custom planes to position children', async ({
@@ -400,4 +401,56 @@ profile001 = startProfile(sketch001, at = [7.49, 9.96])
400401
)
401402
previousCodeContent = await page.locator('.cm-content').innerText()
402403
})
404+
405+
test('"View KCL source code" right click menu in scene', async ({
406+
page,
407+
homePage,
408+
scene,
409+
cmdBar,
410+
}) => {
411+
await page.setBodyDimensions({ width: 1200, height: 500 })
412+
const [clickCenter] = scene.makeMouseHelpers(0.45, 0.45, {
413+
format: 'ratio',
414+
})
415+
const [clickTowardsBottom] = scene.makeMouseHelpers(0.5, 0.9, {
416+
format: 'ratio',
417+
})
418+
await page.addInitScript((initialCode) => {
419+
localStorage.setItem('persistCode', initialCode)
420+
}, bracket)
421+
422+
await homePage.goToModelingScene()
423+
await scene.settled(cmdBar)
424+
425+
const line = page.getByText(
426+
'xLine(length = -shelfMountLength, tag = $seg03)'
427+
)
428+
const menuItems = page.locator('[data-testid="view-controls-menu"] button')
429+
const viewKclSourceCodeOption = menuItems.filter({
430+
hasText: 'View KCL source code',
431+
})
432+
433+
await test.step('Empty scene should have disabled "View KCL source code"', async () => {
434+
await clickTowardsBottom({ shouldRightClick: true })
435+
436+
// Verify context menu appears
437+
await expect(page.getByTestId('view-controls-menu')).toBeVisible()
438+
439+
// "View KCL source code" should be disabled in empty scene
440+
await expect(viewKclSourceCodeOption).toBeVisible()
441+
await expect(viewKclSourceCodeOption).toBeDisabled()
442+
await page.keyboard.press('Escape')
443+
})
444+
445+
await test.step('Right click on bracket sample leads to the right place in code', async () => {
446+
await expect(line).not.toBeVisible()
447+
await clickCenter()
448+
await expect(page.getByText('1 face')).toBeVisible()
449+
await clickCenter({ shouldRightClick: true })
450+
await expect(viewKclSourceCodeOption).toBeVisible()
451+
await expect(viewKclSourceCodeOption).toBeEnabled()
452+
await viewKclSourceCodeOption.click()
453+
await expect(line).toBeVisible()
454+
})
455+
})
403456
})

src/components/ViewControlMenu.tsx

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
selectOffsetSketchPlane,
2020
} from '@src/lib/selections'
2121
import { getSelectedPlaneId } from '@src/lang/queryAst'
22+
import toast from 'react-hot-toast'
2223

2324
export function useViewControlMenuItems() {
2425
const { state: modelingState, send: modelingSend } = useModelingContext()
@@ -30,6 +31,20 @@ export function useViewControlMenuItems() {
3031
const shouldLockView =
3132
modelingState.matches('Sketch') &&
3233
!settings.app.allowOrbitInSketchMode.current
34+
35+
// Check if there's a valid selection with source range for "View KCL source code"
36+
const firstValidSelection = useMemo(() => {
37+
return modelingState.context.selectionRanges.graphSelections.find(
38+
(selection) => {
39+
return (
40+
selection.codeRef?.range &&
41+
selection.codeRef.range[0] !== undefined &&
42+
selection.codeRef.range[1] !== undefined
43+
)
44+
}
45+
)
46+
}, [modelingState.context.selectionRanges.graphSelections])
47+
3348
const menuItems = useMemo(
3449
() => [
3550
...Object.entries(VIEW_NAMES_SEMANTIC).map(([axisName, axisSemantic]) => (
@@ -64,6 +79,41 @@ export function useViewControlMenuItems() {
6479
>
6580
Center view on selection
6681
</ContextMenuItem>,
82+
<ContextMenuItem
83+
onClick={() => {
84+
if (firstValidSelection?.codeRef?.range) {
85+
// First, open the code pane if it's not already open
86+
if (!modelingState.context.store.openPanes.includes('code')) {
87+
modelingSend({
88+
type: 'Set context',
89+
data: {
90+
openPanes: [...modelingState.context.store.openPanes, 'code'],
91+
},
92+
})
93+
}
94+
95+
// Navigate to the source code location
96+
modelingSend({
97+
type: 'Set selection',
98+
data: {
99+
selectionType: 'singleCodeCursor',
100+
selection: {
101+
artifact: firstValidSelection.artifact,
102+
codeRef: firstValidSelection.codeRef,
103+
},
104+
scrollIntoView: true,
105+
},
106+
})
107+
} else {
108+
toast.error(
109+
'No valid selection with source range found. Please select a valid element.'
110+
)
111+
}
112+
}}
113+
disabled={!firstValidSelection}
114+
>
115+
View KCL source code
116+
</ContextMenuItem>,
67117
<ContextMenuDivider />,
68118
<ContextMenuItem
69119
onClick={() => {
@@ -93,8 +143,13 @@ export function useViewControlMenuItems() {
93143
<ContextMenuDivider />,
94144
<ContextMenuItemRefresh />,
95145
],
96-
// eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: blanket-ignored fix me!
97-
[VIEW_NAMES_SEMANTIC, shouldLockView, selectedPlaneId]
146+
[
147+
shouldLockView,
148+
selectedPlaneId,
149+
firstValidSelection,
150+
modelingSend,
151+
modelingState.context.store.openPanes,
152+
]
98153
)
99154
return menuItems
100155
}

0 commit comments

Comments
 (0)