Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
347e635
Right click a feature on the model to center the code pane on it #7447
rajgandhi1 Jul 2, 2025
4aa6aa6
bug fixes
rajgandhi1 Jul 2, 2025
4915eb7
Merge branch 'KittyCAD:main' into view_kcl_code
rajgandhi1 Jul 3, 2025
bb6c9f7
Merge branch 'KittyCAD:main' into view_kcl_code
rajgandhi1 Jul 4, 2025
2279aa2
[Bug fix]: Do not store token in window! (#7671)
nadr0 Jul 4, 2025
5e5d421
* Add ability to pick default plane in feature tree in 'Sketch no fac…
andrewvarga Jul 4, 2025
a4c1258
Right click a feature on the model to center the code pane on it #7447
rajgandhi1 Jul 2, 2025
c1c4684
bug fixes
rajgandhi1 Jul 2, 2025
a0b9880
Merge branch 'main' into view_kcl_code
rajgandhi1 Jul 7, 2025
4a11eb2
Merge branch 'KittyCAD:main' into view_kcl_code
rajgandhi1 Jul 9, 2025
cba6ab9
Merge branch 'KittyCAD:main' into view_kcl_code
rajgandhi1 Jul 12, 2025
ee2e394
Merge branch 'KittyCAD:main' into view_kcl_code
rajgandhi1 Jul 16, 2025
039d7b3
removed duplicate code.
rajgandhi1 Jul 16, 2025
4549789
added basic playwright test
rajgandhi1 Jul 16, 2025
037cf6d
Merge branch 'main' into view_kcl_code
rajgandhi1 Jul 18, 2025
7746ff3
Merge branch 'main' into rajgandhi1/view_kcl_code
pierremtb Jul 24, 2025
68a2155
Merge branch 'main' into rajgandhi1/view_kcl_code
pierremtb Jul 24, 2025
a1cf11c
Merge branch 'main' into rajgandhi1/view_kcl_code
pierremtb Jul 24, 2025
e847fce
Merge branch 'main' into rajgandhi1/view_kcl_code
pierremtb Jul 24, 2025
680dbab
Unify repeated logic and move test to testing-selections spec file
pierremtb Jul 24, 2025
833b922
Merge branch 'main' into rajgandhi1/view_kcl_code
pierremtb Aug 7, 2025
8159f75
Merge branch 'main' into rajgandhi1/view_kcl_code
pierremtb Aug 13, 2025
d233e48
Merge branch 'main' into rajgandhi1/view_kcl_code
pierremtb Aug 22, 2025
2457714
Merge branch 'main' into rajgandhi1/view_kcl_code
pierremtb Aug 25, 2025
08b404f
Add test case for succesful right click to code
pierremtb Aug 25, 2025
b79bcf9
Remove TODO and clean up useMemo deps
pierremtb Aug 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions e2e/playwright/fixtures/sceneFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { expect } from '@e2e/playwright/zoo-test'
type MouseParams = {
pixelDiff?: number
shouldDbClick?: boolean
shouldRightClick?: boolean
delay?: number
}
type MouseDragToParams = MouseParams & {
Expand Down Expand Up @@ -137,19 +138,29 @@ export class SceneFixture {
? this.page.mouse.dblclick(resolvedPoint.x, resolvedPoint.y, {
delay: clickParams?.delay || 0,
})
: this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
delay: clickParams?.delay || 0,
}),
: clickParams?.shouldRightClick
? this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
button: 'right',
delay: clickParams?.delay || 0,
})
: this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
delay: clickParams?.delay || 0,
}),
clickParams.pixelDiff
)
}
return clickParams?.shouldDbClick
? this.page.mouse.dblclick(resolvedPoint.x, resolvedPoint.y, {
delay: clickParams?.delay || 0,
})
: this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
delay: clickParams?.delay || 0,
})
: clickParams?.shouldRightClick
? this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
button: 'right',
delay: clickParams?.delay || 0,
})
: this.page.mouse.click(resolvedPoint.x, resolvedPoint.y, {
delay: clickParams?.delay || 0,
})
},
async (moveParams?: MouseParams) => {
const resolvedPoint = await this.convertPagePositionToStream(
Expand Down
53 changes: 53 additions & 0 deletions e2e/playwright/testing-selections.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
import { getUtils } from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { bracket } from '@e2e/playwright/fixtures/bracket'

test.describe('Testing selections', () => {
test('parent Solid should be select and deletable and uses custom planes to position children', async ({
Expand Down Expand Up @@ -400,4 +401,56 @@ profile001 = startProfile(sketch001, at = [7.49, 9.96])
)
previousCodeContent = await page.locator('.cm-content').innerText()
})

test('"View KCL source code" right click menu in scene', async ({
page,
homePage,
scene,
cmdBar,
}) => {
await page.setBodyDimensions({ width: 1200, height: 500 })
const [clickCenter] = scene.makeMouseHelpers(0.45, 0.45, {
format: 'ratio',
})
const [clickTowardsBottom] = scene.makeMouseHelpers(0.5, 0.9, {
format: 'ratio',
})
await page.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
}, bracket)

await homePage.goToModelingScene()
await scene.settled(cmdBar)

const line = page.getByText(
'xLine(length = -shelfMountLength, tag = $seg03)'
)
const menuItems = page.locator('[data-testid="view-controls-menu"] button')
const viewKclSourceCodeOption = menuItems.filter({
hasText: 'View KCL source code',
})

await test.step('Empty scene should have disabled "View KCL source code"', async () => {
await clickTowardsBottom({ shouldRightClick: true })

// Verify context menu appears
await expect(page.getByTestId('view-controls-menu')).toBeVisible()

// "View KCL source code" should be disabled in empty scene
await expect(viewKclSourceCodeOption).toBeVisible()
await expect(viewKclSourceCodeOption).toBeDisabled()
await page.keyboard.press('Escape')
})

await test.step('Right click on bracket sample leads to the right place in code', async () => {
await expect(line).not.toBeVisible()
await clickCenter()
await expect(page.getByText('1 face')).toBeVisible()
await clickCenter({ shouldRightClick: true })
await expect(viewKclSourceCodeOption).toBeVisible()
await expect(viewKclSourceCodeOption).toBeEnabled()
await viewKclSourceCodeOption.click()
await expect(line).toBeVisible()
})
})
})
58 changes: 57 additions & 1 deletion src/components/ViewControlMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
selectOffsetSketchPlane,
} from '@src/lib/selections'
import { getSelectedPlaneId } from '@src/lang/queryAst'
import toast from 'react-hot-toast'

export function useViewControlMenuItems() {
const { state: modelingState, send: modelingSend } = useModelingContext()
Expand All @@ -30,6 +31,20 @@
const shouldLockView =
modelingState.matches('Sketch') &&
!settings.app.allowOrbitInSketchMode.current

// Check if there's a valid selection with source range for "View KCL source code"
const firstValidSelection = useMemo(() => {
return modelingState.context.selectionRanges.graphSelections.find(
(selection) => {
return (
selection.codeRef?.range &&
selection.codeRef.range[0] !== undefined &&
selection.codeRef.range[1] !== undefined
)
}
)
}, [modelingState.context.selectionRanges.graphSelections])

const menuItems = useMemo(
() => [
...Object.entries(VIEW_NAMES_SEMANTIC).map(([axisName, axisSemantic]) => (
Expand Down Expand Up @@ -64,6 +79,41 @@
>
Center view on selection
</ContextMenuItem>,
<ContextMenuItem
onClick={() => {
if (firstValidSelection?.codeRef?.range) {
// First, open the code pane if it's not already open
if (!modelingState.context.store.openPanes.includes('code')) {
modelingSend({
type: 'Set context',
data: {
openPanes: [...modelingState.context.store.openPanes, 'code'],
},
})
}

// Navigate to the source code location
modelingSend({
type: 'Set selection',
data: {
selectionType: 'singleCodeCursor',
selection: {
artifact: firstValidSelection.artifact,
codeRef: firstValidSelection.codeRef,
},
scrollIntoView: true,
},
})
} else {
toast.error(
'No valid selection with source range found. Please select a valid element.'
)
}
}}
disabled={!firstValidSelection}
>
View KCL source code
</ContextMenuItem>,

Check warning on line 116 in src/components/ViewControlMenu.tsx

View workflow job for this annotation

GitHub Actions / semgrep-oss/scan

jsx-not-internationalized

JSX element not internationalized View KCL source code . You should support different languages in your website or app with internationalization. Instead use packages such as i18next in order to internationalize your elements.
<ContextMenuDivider />,
<ContextMenuItem
onClick={() => {
Expand Down Expand Up @@ -94,7 +144,13 @@
<ContextMenuItemRefresh />,
],
// eslint-disable-next-line react-hooks/exhaustive-deps -- TODO: blanket-ignored fix me!
[VIEW_NAMES_SEMANTIC, shouldLockView, selectedPlaneId]
[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this depdendency list could be fixed, while we're here, looks easy to remove VIEW_NAMES_SEMANTIC and add modelingSend.
But no need to block this PR for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice thanks for noticing this! Fixed at b79bcf9

VIEW_NAMES_SEMANTIC,
shouldLockView,
selectedPlaneId,
firstValidSelection,
modelingState.context.store.openPanes,
]
)
return menuItems
}
Expand Down
Loading