Add menu item and hotkey to center view on current selection (#4068)
* tentatively adding this * Update src/components/ModelingMachineProvider.tsx Co-authored-by: Jonathan Tran <jonnytran@gmail.com> * Show shortcut in UI dialog * Move command into modelingMachine action * Add a menu item to the view menu * Switch gizmo tests to use "deprecated" test setup in prep for new fixture-based test * Add e2e test for center view to selection * Bump @kittycad/lib to latest and fix tsc * Bump @kittycad/lib to v2.0.7 to fix electron building * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) * A snapshot a day keeps the bugs away! 📷🐛 (OS: windows-latest) --------- Co-authored-by: Jonathan Tran <jonnytran@gmail.com> Co-authored-by: Frank Noirot <frank@kittycad.io> Co-authored-by: 49fl <ircsurfer33@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Frank Noirot <frank@zoo.dev>
This commit is contained in:
@ -13,6 +13,13 @@ type mouseParams = {
|
|||||||
pixelDiff: number
|
pixelDiff: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SceneSerialised = {
|
||||||
|
camera: {
|
||||||
|
position: [number, number, number]
|
||||||
|
target: [number, number, number]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class SceneFixture {
|
export class SceneFixture {
|
||||||
public page: Page
|
public page: Page
|
||||||
|
|
||||||
@ -22,6 +29,22 @@ export class SceneFixture {
|
|||||||
this.page = page
|
this.page = page
|
||||||
this.reConstruct(page)
|
this.reConstruct(page)
|
||||||
}
|
}
|
||||||
|
private _serialiseScene = async (): Promise<SceneSerialised> => {
|
||||||
|
const camera = await this.getCameraInfo()
|
||||||
|
|
||||||
|
return {
|
||||||
|
camera,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expectState = async (expected: SceneSerialised) => {
|
||||||
|
return expect
|
||||||
|
.poll(() => this._serialiseScene(), {
|
||||||
|
message: `Expected scene state to match`,
|
||||||
|
})
|
||||||
|
.toEqual(expected)
|
||||||
|
}
|
||||||
|
|
||||||
reConstruct = (page: Page) => {
|
reConstruct = (page: Page) => {
|
||||||
this.page = page
|
this.page = page
|
||||||
|
|
||||||
@ -31,7 +54,7 @@ export class SceneFixture {
|
|||||||
makeMouseHelpers = (
|
makeMouseHelpers = (
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
{ steps }: { steps: number } = { steps: 5000 }
|
{ steps }: { steps: number } = { steps: 20 }
|
||||||
) =>
|
) =>
|
||||||
[
|
[
|
||||||
(clickParams?: mouseParams) => {
|
(clickParams?: mouseParams) => {
|
||||||
@ -87,6 +110,36 @@ export class SceneFixture {
|
|||||||
)
|
)
|
||||||
await closeDebugPanel(this.page)
|
await closeDebugPanel(this.page)
|
||||||
}
|
}
|
||||||
|
/** Forces a refresh of the camera position and target displayed
|
||||||
|
* in the debug panel and then returns the values of the fields
|
||||||
|
*/
|
||||||
|
async getCameraInfo() {
|
||||||
|
await openAndClearDebugPanel(this.page)
|
||||||
|
await sendCustomCmd(this.page, {
|
||||||
|
type: 'modeling_cmd_req',
|
||||||
|
cmd_id: uuidv4(),
|
||||||
|
cmd: {
|
||||||
|
type: 'default_camera_get_settings',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await this.waitForExecutionDone()
|
||||||
|
const position = await Promise.all([
|
||||||
|
this.page.getByTestId('cam-x-position').inputValue().then(Number),
|
||||||
|
this.page.getByTestId('cam-y-position').inputValue().then(Number),
|
||||||
|
this.page.getByTestId('cam-z-position').inputValue().then(Number),
|
||||||
|
])
|
||||||
|
const target = await Promise.all([
|
||||||
|
this.page.getByTestId('cam-x-target').inputValue().then(Number),
|
||||||
|
this.page.getByTestId('cam-y-target').inputValue().then(Number),
|
||||||
|
this.page.getByTestId('cam-z-target').inputValue().then(Number),
|
||||||
|
])
|
||||||
|
await closeDebugPanel(this.page)
|
||||||
|
return {
|
||||||
|
position,
|
||||||
|
target,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
waitForExecutionDone = async () => {
|
waitForExecutionDone = async () => {
|
||||||
await expect(this.exeIndicator).toBeVisible()
|
await expect(this.exeIndicator).toBeVisible()
|
||||||
}
|
}
|
||||||
@ -114,4 +167,17 @@ export class SceneFixture {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get gizmo() {
|
||||||
|
return this.page.locator('[aria-label*=gizmo]')
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickGizmoMenuItem(name: string) {
|
||||||
|
await this.gizmo.click({ button: 'right' })
|
||||||
|
const buttonToTest = this.page.getByRole('button', {
|
||||||
|
name: name,
|
||||||
|
})
|
||||||
|
await expect(buttonToTest).toBeVisible()
|
||||||
|
await buttonToTest.click()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 58 KiB |
Binary file not shown.
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
@ -1,18 +1,18 @@
|
|||||||
import { test, expect } from '@playwright/test'
|
import { _test, _expect } from './playwright-deprecated'
|
||||||
|
import { test } from './fixtures/fixtureSetup'
|
||||||
import { getUtils, setup, tearDown } from './test-utils'
|
import { getUtils, setup, tearDown } from './test-utils'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
import { TEST_CODE_GIZMO } from './storageStates'
|
import { TEST_CODE_GIZMO } from './storageStates'
|
||||||
|
|
||||||
test.beforeEach(async ({ context, page }, testInfo) => {
|
_test.beforeEach(async ({ context, page }, testInfo) => {
|
||||||
await setup(context, page, testInfo)
|
await setup(context, page, testInfo)
|
||||||
})
|
})
|
||||||
|
|
||||||
test.afterEach(async ({ page }, testInfo) => {
|
_test.afterEach(async ({ page }, testInfo) => {
|
||||||
await tearDown(page, testInfo)
|
await tearDown(page, testInfo)
|
||||||
})
|
})
|
||||||
|
|
||||||
test.describe('Testing Gizmo', () => {
|
_test.describe('Testing Gizmo', () => {
|
||||||
const cases = [
|
const cases = [
|
||||||
{
|
{
|
||||||
testDescription: 'top view',
|
testDescription: 'top view',
|
||||||
@ -57,7 +57,7 @@ test.describe('Testing Gizmo', () => {
|
|||||||
expectedCameraTarget,
|
expectedCameraTarget,
|
||||||
testDescription,
|
testDescription,
|
||||||
} of cases) {
|
} of cases) {
|
||||||
test(`check ${testDescription}`, async ({ page, browserName }) => {
|
_test(`check ${testDescription}`, async ({ page, browserName }) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
await page.addInitScript((TEST_CODE_GIZMO) => {
|
await page.addInitScript((TEST_CODE_GIZMO) => {
|
||||||
localStorage.setItem('persistCode', TEST_CODE_GIZMO)
|
localStorage.setItem('persistCode', TEST_CODE_GIZMO)
|
||||||
@ -117,30 +117,30 @@ test.describe('Testing Gizmo', () => {
|
|||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
// position
|
// position
|
||||||
expect(page.getByTestId('cam-x-position')).toHaveValue(
|
_expect(page.getByTestId('cam-x-position')).toHaveValue(
|
||||||
expectedCameraPosition.x.toString()
|
expectedCameraPosition.x.toString()
|
||||||
),
|
),
|
||||||
expect(page.getByTestId('cam-y-position')).toHaveValue(
|
_expect(page.getByTestId('cam-y-position')).toHaveValue(
|
||||||
expectedCameraPosition.y.toString()
|
expectedCameraPosition.y.toString()
|
||||||
),
|
),
|
||||||
expect(page.getByTestId('cam-z-position')).toHaveValue(
|
_expect(page.getByTestId('cam-z-position')).toHaveValue(
|
||||||
expectedCameraPosition.z.toString()
|
expectedCameraPosition.z.toString()
|
||||||
),
|
),
|
||||||
// target
|
// target
|
||||||
expect(page.getByTestId('cam-x-target')).toHaveValue(
|
_expect(page.getByTestId('cam-x-target')).toHaveValue(
|
||||||
expectedCameraTarget.x.toString()
|
expectedCameraTarget.x.toString()
|
||||||
),
|
),
|
||||||
expect(page.getByTestId('cam-y-target')).toHaveValue(
|
_expect(page.getByTestId('cam-y-target')).toHaveValue(
|
||||||
expectedCameraTarget.y.toString()
|
expectedCameraTarget.y.toString()
|
||||||
),
|
),
|
||||||
expect(page.getByTestId('cam-z-target')).toHaveValue(
|
_expect(page.getByTestId('cam-z-target')).toHaveValue(
|
||||||
expectedCameraTarget.z.toString()
|
expectedCameraTarget.z.toString()
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
test('Context menu and popover menu', async ({ page }) => {
|
_test('Context menu and popover menu', async ({ page }) => {
|
||||||
const testCase = {
|
const testCase = {
|
||||||
testDescription: 'Right view',
|
testDescription: 'Right view',
|
||||||
expectedCameraPosition: { x: 5660.02, y: -152, z: 26 },
|
expectedCameraPosition: { x: 5660.02, y: -152, z: 26 },
|
||||||
@ -196,7 +196,7 @@ test.describe('Testing Gizmo', () => {
|
|||||||
const buttonToTest = page.getByRole('button', {
|
const buttonToTest = page.getByRole('button', {
|
||||||
name: testCase.testDescription,
|
name: testCase.testDescription,
|
||||||
})
|
})
|
||||||
await expect(buttonToTest).toBeVisible()
|
await _expect(buttonToTest).toBeVisible()
|
||||||
await buttonToTest.click()
|
await buttonToTest.click()
|
||||||
|
|
||||||
// Now assert we've moved to the correct view
|
// Now assert we've moved to the correct view
|
||||||
@ -215,23 +215,23 @@ test.describe('Testing Gizmo', () => {
|
|||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
// position
|
// position
|
||||||
expect(page.getByTestId('cam-x-position')).toHaveValue(
|
_expect(page.getByTestId('cam-x-position')).toHaveValue(
|
||||||
testCase.expectedCameraPosition.x.toString()
|
testCase.expectedCameraPosition.x.toString()
|
||||||
),
|
),
|
||||||
expect(page.getByTestId('cam-y-position')).toHaveValue(
|
_expect(page.getByTestId('cam-y-position')).toHaveValue(
|
||||||
testCase.expectedCameraPosition.y.toString()
|
testCase.expectedCameraPosition.y.toString()
|
||||||
),
|
),
|
||||||
expect(page.getByTestId('cam-z-position')).toHaveValue(
|
_expect(page.getByTestId('cam-z-position')).toHaveValue(
|
||||||
testCase.expectedCameraPosition.z.toString()
|
testCase.expectedCameraPosition.z.toString()
|
||||||
),
|
),
|
||||||
// target
|
// target
|
||||||
expect(page.getByTestId('cam-x-target')).toHaveValue(
|
_expect(page.getByTestId('cam-x-target')).toHaveValue(
|
||||||
testCase.expectedCameraTarget.x.toString()
|
testCase.expectedCameraTarget.x.toString()
|
||||||
),
|
),
|
||||||
expect(page.getByTestId('cam-y-target')).toHaveValue(
|
_expect(page.getByTestId('cam-y-target')).toHaveValue(
|
||||||
testCase.expectedCameraTarget.y.toString()
|
testCase.expectedCameraTarget.y.toString()
|
||||||
),
|
),
|
||||||
expect(page.getByTestId('cam-z-target')).toHaveValue(
|
_expect(page.getByTestId('cam-z-target')).toHaveValue(
|
||||||
testCase.expectedCameraTarget.z.toString()
|
testCase.expectedCameraTarget.z.toString()
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
@ -242,8 +242,60 @@ test.describe('Testing Gizmo', () => {
|
|||||||
const gizmoPopoverButton = page.getByRole('button', {
|
const gizmoPopoverButton = page.getByRole('button', {
|
||||||
name: 'view settings',
|
name: 'view settings',
|
||||||
})
|
})
|
||||||
await expect(gizmoPopoverButton).toBeVisible()
|
await _expect(gizmoPopoverButton).toBeVisible()
|
||||||
await gizmoPopoverButton.click()
|
await gizmoPopoverButton.click()
|
||||||
await expect(buttonToTest).toBeVisible()
|
await _expect(buttonToTest).toBeVisible()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test.describe(`Testing gizmo, fixture-based`, () => {
|
||||||
|
test('Center on selection from menu', async ({
|
||||||
|
app,
|
||||||
|
cmdBar,
|
||||||
|
editor,
|
||||||
|
toolbar,
|
||||||
|
scene,
|
||||||
|
}) => {
|
||||||
|
test.skip(
|
||||||
|
process.platform === 'win32',
|
||||||
|
'Fails on windows in CI, can not be replicated locally on windows.'
|
||||||
|
)
|
||||||
|
|
||||||
|
await test.step(`Setup`, async () => {
|
||||||
|
const file = await app.getInputFile('test-circle-extrude.kcl')
|
||||||
|
await app.initialise(file)
|
||||||
|
await scene.expectState({
|
||||||
|
camera: {
|
||||||
|
position: [4982.21, -23865.37, 13810.64],
|
||||||
|
target: [4982.21, 0, 2737.1],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const [clickCircle, moveToCircle] = scene.makeMouseHelpers(582, 217)
|
||||||
|
|
||||||
|
await test.step(`Select an edge of this circle`, async () => {
|
||||||
|
const circleSnippet =
|
||||||
|
'circle({ center: [318.33, 168.1], radius: 182.8 }, %)'
|
||||||
|
await moveToCircle()
|
||||||
|
await clickCircle()
|
||||||
|
await editor.expectState({
|
||||||
|
activeLines: [circleSnippet.slice(-5)],
|
||||||
|
highlightedCode: circleSnippet,
|
||||||
|
diagnostics: [],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
await test.step(`Center on selection from menu`, async () => {
|
||||||
|
await scene.clickGizmoMenuItem('Center view on selection')
|
||||||
|
})
|
||||||
|
|
||||||
|
await test.step(`Verify the camera moved`, async () => {
|
||||||
|
await scene.expectState({
|
||||||
|
camera: {
|
||||||
|
position: [0, -23865.37, 11073.54],
|
||||||
|
target: [0, 0, 0],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@headlessui/react": "^1.7.19",
|
"@headlessui/react": "^1.7.19",
|
||||||
"@headlessui/tailwindcss": "^0.2.0",
|
"@headlessui/tailwindcss": "^0.2.0",
|
||||||
"@kittycad/lib": "^2.0.1",
|
"@kittycad/lib": "2.0.7",
|
||||||
"@lezer/highlight": "^1.2.1",
|
"@lezer/highlight": "^1.2.1",
|
||||||
"@lezer/lr": "^1.4.1",
|
"@lezer/lr": "^1.4.1",
|
||||||
"@react-hook/resize-observer": "^2.0.1",
|
"@react-hook/resize-observer": "^2.0.1",
|
||||||
|
@ -893,6 +893,7 @@ export class CameraControls {
|
|||||||
type: 'zoom_to_fit',
|
type: 'zoom_to_fit',
|
||||||
object_ids: [], // leave empty to zoom to all objects
|
object_ids: [], // leave empty to zoom to all objects
|
||||||
padding: 0.2, // padding around the objects
|
padding: 0.2, // padding around the objects
|
||||||
|
animated: false, // don't animate the zoom for now
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
import { Popover } from '@headlessui/react'
|
import { Popover } from '@headlessui/react'
|
||||||
import { CustomIcon } from './CustomIcon'
|
import { CustomIcon } from './CustomIcon'
|
||||||
import { reportRejection } from 'lib/trap'
|
import { reportRejection } from 'lib/trap'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
const CANVAS_SIZE = 80
|
const CANVAS_SIZE = 80
|
||||||
const FRUSTUM_SIZE = 0.5
|
const FRUSTUM_SIZE = 0.5
|
||||||
@ -62,6 +63,7 @@ export default function Gizmo() {
|
|||||||
const raycasterIntersect = useRef<Intersection<Object3D> | null>(null)
|
const raycasterIntersect = useRef<Intersection<Object3D> | null>(null)
|
||||||
const cameraPassiveUpdateTimer = useRef(0)
|
const cameraPassiveUpdateTimer = useRef(0)
|
||||||
const raycasterPassiveUpdateTimer = useRef(0)
|
const raycasterPassiveUpdateTimer = useRef(0)
|
||||||
|
const { send: modelingSend } = useModelingContext()
|
||||||
const menuItems = useMemo(
|
const menuItems = useMemo(
|
||||||
() => [
|
() => [
|
||||||
...Object.entries(axisNamesSemantic).map(([axisName, axisSemantic]) => (
|
...Object.entries(axisNamesSemantic).map(([axisName, axisSemantic]) => (
|
||||||
@ -76,6 +78,7 @@ export default function Gizmo() {
|
|||||||
{axisSemantic} view
|
{axisSemantic} view
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
)),
|
)),
|
||||||
|
<ContextMenuDivider />,
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
sceneInfra.camControls.resetCameraPosition().catch(reportRejection)
|
sceneInfra.camControls.resetCameraPosition().catch(reportRejection)
|
||||||
@ -83,6 +86,13 @@ export default function Gizmo() {
|
|||||||
>
|
>
|
||||||
Reset view
|
Reset view
|
||||||
</ContextMenuItem>,
|
</ContextMenuItem>,
|
||||||
|
<ContextMenuItem
|
||||||
|
onClick={() => {
|
||||||
|
modelingSend({ type: 'Center camera on selection' })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Center view on selection
|
||||||
|
</ContextMenuItem>,
|
||||||
<ContextMenuDivider />,
|
<ContextMenuDivider />,
|
||||||
<ContextMenuItemRefresh />,
|
<ContextMenuItemRefresh />,
|
||||||
],
|
],
|
||||||
|
@ -83,6 +83,7 @@ import {
|
|||||||
} from 'lang/std/engineConnection'
|
} from 'lang/std/engineConnection'
|
||||||
import { submitAndAwaitTextToKcl } from 'lib/textToCad'
|
import { submitAndAwaitTextToKcl } from 'lib/textToCad'
|
||||||
import { useFileContext } from 'hooks/useFileContext'
|
import { useFileContext } from 'hooks/useFileContext'
|
||||||
|
import { uuidv4 } from 'lib/utils'
|
||||||
|
|
||||||
type MachineContext<T extends AnyStateMachine> = {
|
type MachineContext<T extends AnyStateMachine> = {
|
||||||
state: StateFrom<T>
|
state: StateFrom<T>
|
||||||
@ -243,6 +244,17 @@ export const ModelingMachineProvider = ({
|
|||||||
return {}
|
return {}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
'Center camera on selection': () => {
|
||||||
|
engineCommandManager
|
||||||
|
.sendSceneCommand({
|
||||||
|
type: 'modeling_cmd_req',
|
||||||
|
cmd_id: uuidv4(),
|
||||||
|
cmd: {
|
||||||
|
type: 'default_camera_center_to_selection',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch(reportRejection)
|
||||||
|
},
|
||||||
'Set sketchDetails': assign(({ context: { sketchDetails }, event }) => {
|
'Set sketchDetails': assign(({ context: { sketchDetails }, event }) => {
|
||||||
if (event.type !== 'Delete segment') return {}
|
if (event.type !== 'Delete segment') return {}
|
||||||
if (!sketchDetails) return {}
|
if (!sketchDetails) return {}
|
||||||
@ -1037,6 +1049,11 @@ export const ModelingMachineProvider = ({
|
|||||||
modelingSend({ type: 'Delete selection' })
|
modelingSend({ type: 'Delete selection' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Allow ctrl+alt+c to center to selection
|
||||||
|
useHotkeys(['mod + alt + c'], () => {
|
||||||
|
modelingSend({ type: 'Center camera on selection' })
|
||||||
|
})
|
||||||
|
|
||||||
useStateMachineCommands({
|
useStateMachineCommands({
|
||||||
machineId: 'modeling',
|
machineId: 'modeling',
|
||||||
state: modelingState,
|
state: modelingState,
|
||||||
|
@ -282,6 +282,7 @@ export class KclManager {
|
|||||||
type: 'zoom_to_fit',
|
type: 'zoom_to_fit',
|
||||||
object_ids: zoomObjectId ? [zoomObjectId] : [], // leave empty to zoom to all objects
|
object_ids: zoomObjectId ? [zoomObjectId] : [], // leave empty to zoom to all objects
|
||||||
padding: 0.1, // padding around the objects
|
padding: 0.1, // padding around the objects
|
||||||
|
animated: false, // don't animate the zoom for now
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -145,6 +145,13 @@ export const interactionMap: Record<
|
|||||||
description:
|
description:
|
||||||
'Available while modeling with either a face selected or an empty selection, when not typing in the code editor.',
|
'Available while modeling with either a face selected or an empty selection, when not typing in the code editor.',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'center-on-selection',
|
||||||
|
sequence: `${PRIMARY}+Alt+C`,
|
||||||
|
title: 'Center on selection',
|
||||||
|
description:
|
||||||
|
'Centers the view on the selected geometry, or everything if nothing is selected.',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
'Code Editor': [
|
'Code Editor': [
|
||||||
{
|
{
|
||||||
|
@ -49,6 +49,7 @@ if (typeof window !== 'undefined') {
|
|||||||
type: 'zoom_to_fit',
|
type: 'zoom_to_fit',
|
||||||
object_ids: [], // leave empty to zoom to all objects
|
object_ids: [], // leave empty to zoom to all objects
|
||||||
padding: 0.2, // padding around the objects
|
padding: 0.2, // padding around the objects
|
||||||
|
animated: false, // don't animate the zoom for now
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ export async function submitAndAwaitTextToKcl({
|
|||||||
|
|
||||||
export async function sendTelemetry(
|
export async function sendTelemetry(
|
||||||
id: string,
|
id: string,
|
||||||
feedback: Models['AiFeedback_type'],
|
feedback: Models['MlFeedback_type'],
|
||||||
token?: string
|
token?: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const url =
|
const url =
|
||||||
|
@ -252,6 +252,9 @@ export type ModelingMachineEvent =
|
|||||||
type: 'Set Segment Overlays'
|
type: 'Set Segment Overlays'
|
||||||
data: SegmentOverlayPayload
|
data: SegmentOverlayPayload
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: 'Center camera on selection'
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'Delete segment'
|
type: 'Delete segment'
|
||||||
data: PathToNode
|
data: PathToNode
|
||||||
@ -938,6 +941,7 @@ export const modelingMachine = setup({
|
|||||||
'Set selection': () => {},
|
'Set selection': () => {},
|
||||||
'Set mouse state': () => {},
|
'Set mouse state': () => {},
|
||||||
'Set Segment Overlays': () => {},
|
'Set Segment Overlays': () => {},
|
||||||
|
'Center camera on selection': () => {},
|
||||||
'Engine export': () => {},
|
'Engine export': () => {},
|
||||||
'Submit to Text-to-CAD API': () => {},
|
'Submit to Text-to-CAD API': () => {},
|
||||||
'Set sketchDetails': () => {},
|
'Set sketchDetails': () => {},
|
||||||
@ -2105,6 +2109,10 @@ export const modelingMachine = setup({
|
|||||||
reenter: false,
|
reenter: false,
|
||||||
actions: 'Set Segment Overlays',
|
actions: 'Set Segment Overlays',
|
||||||
},
|
},
|
||||||
|
'Center camera on selection': {
|
||||||
|
reenter: false,
|
||||||
|
actions: 'Center camera on selection',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -2075,10 +2075,10 @@
|
|||||||
"@jridgewell/resolve-uri" "^3.1.0"
|
"@jridgewell/resolve-uri" "^3.1.0"
|
||||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||||
|
|
||||||
"@kittycad/lib@^2.0.1":
|
"@kittycad/lib@2.0.7":
|
||||||
version "2.0.1"
|
version "2.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-2.0.1.tgz#d3f1c80d9903452b0b9df378c72ed1e83b19a73d"
|
resolved "https://registry.yarnpkg.com/@kittycad/lib/-/lib-2.0.7.tgz#63e9c81fc7705c9d0c5fab5939e5d839ec6f393b"
|
||||||
integrity sha512-VYunezWS+cNZbdKfVkB3zg2YbDCQEb/AjzER85+yyDAlTU5PL4paQDpNlEI6icSglDGRUIR4Er/bRFj68r3UQg==
|
integrity sha512-P26rRZ0KF8C3zhEG2beLlkTJhTPtJF6Nn1wg7w1MxXNvK9RZF6P7DcXqdIh7nJGQt72+JrXoPmApB8Z/R1gQRg==
|
||||||
dependencies:
|
dependencies:
|
||||||
openapi-types "^12.0.0"
|
openapi-types "^12.0.0"
|
||||||
ts-node "^10.9.1"
|
ts-node "^10.9.1"
|
||||||
|
Reference in New Issue
Block a user