initial migration from zustand (#2852)
* inital migration with a couple lingering concerns
* move is stream ready back
* put htmlRef back in useStore
* final tidy of useStore
* test tweaks
* tweak more
* more test tweaks
* fmt
* test tweaks
* attempts at fixing 'Basic default modeling and sketch hotkeys work'
* more tries
* 😭
* try again
* fmt
This commit is contained in:
@ -30,6 +30,8 @@ import { EngineCommand } from 'lang/std/engineConnection'
|
|||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { bracket } from 'lib/exampleKcl'
|
import { bracket } from 'lib/exampleKcl'
|
||||||
|
|
||||||
|
const PERSIST_MODELING_CONTEXT = 'persistModelingContext'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
|
debug helper: unfortunately we do rely on exact coord mouse clicks in a few places
|
||||||
just from the nature of the stream, running the test with debugger and pasting the below
|
just from the nature of the stream, running the test with debugger and pasting the below
|
||||||
@ -198,35 +200,17 @@ async function doBasicSketch(page: Page, openPanes: string[]) {
|
|||||||
|
|
||||||
test.describe('Basic sketch', () => {
|
test.describe('Basic sketch', () => {
|
||||||
test('code pane open at start', async ({ page }) => {
|
test('code pane open at start', async ({ page }) => {
|
||||||
// Load the app with the code panes
|
|
||||||
await page.addInitScript(async () => {
|
|
||||||
localStorage.setItem(
|
|
||||||
'store',
|
|
||||||
JSON.stringify({
|
|
||||||
state: {
|
|
||||||
openPanes: ['code'],
|
|
||||||
},
|
|
||||||
version: 0,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
await doBasicSketch(page, ['code'])
|
await doBasicSketch(page, ['code'])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('code pane closed at start', async ({ page }) => {
|
test('code pane closed at start', async ({ page }) => {
|
||||||
// Load the app with the code panes
|
// Load the app with the code panes
|
||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async (persistModelingContext) => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'store',
|
persistModelingContext,
|
||||||
JSON.stringify({
|
JSON.stringify({ openPanes: [] })
|
||||||
state: {
|
|
||||||
openPanes: [],
|
|
||||||
},
|
|
||||||
version: 0,
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
})
|
}, PERSIST_MODELING_CONTEXT)
|
||||||
await doBasicSketch(page, [])
|
await doBasicSketch(page, [])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -457,7 +441,9 @@ test.describe('Testing Camera Movement', () => {
|
|||||||
// await u.canvasLocator.hover({position: {x: 700, y: 325}})
|
// await u.canvasLocator.hover({position: {x: 700, y: 325}})
|
||||||
await page.mouse.move(700, 325)
|
await page.mouse.move(700, 325)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
await expect(page.getByTestId('hover-highlight')).not.toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
|
||||||
@ -465,12 +451,18 @@ test.describe('Testing Camera Movement', () => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
// hover over horizontal line
|
// hover over horizontal line
|
||||||
await u.canvasLocator.hover({ position: { x: 800, y } })
|
await u.canvasLocator.hover({ position: { x: 800, y } })
|
||||||
await expect(page.getByTestId('hover-highlight')).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
|
await page.waitForTimeout(200)
|
||||||
// hover over vertical line
|
// hover over vertical line
|
||||||
await u.canvasLocator.hover({ position: { x, y: 325 } })
|
await u.canvasLocator.hover({ position: { x, y: 325 } })
|
||||||
await expect(page.getByTestId('hover-highlight')).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
|
|
||||||
@ -479,22 +471,28 @@ test.describe('Testing Camera Movement', () => {
|
|||||||
await page.waitForTimeout(400)
|
await page.waitForTimeout(400)
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(200)
|
||||||
// hover over horizontal line
|
// hover over horizontal line
|
||||||
await page.mouse.move(858, y, { steps: 5 })
|
await page.mouse.move(858, y, { steps: 5 })
|
||||||
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
|
|
||||||
// hover over vertical line
|
// hover over vertical line
|
||||||
await page.mouse.move(x, 325)
|
await page.mouse.move(x, 325)
|
||||||
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
|
|
||||||
// hover over vertical line
|
// hover over vertical line
|
||||||
await page.mouse.move(857, y)
|
await page.mouse.move(857, y)
|
||||||
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
// now click it
|
// now click it
|
||||||
await page.mouse.click(857, y)
|
await page.mouse.click(857, y)
|
||||||
|
|
||||||
@ -511,27 +509,36 @@ test.describe('Testing Camera Movement', () => {
|
|||||||
|
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.mouse.move(x, 419, { steps: 5 })
|
await page.mouse.move(x, 419, { steps: 5 })
|
||||||
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
|
|
||||||
await page.mouse.move(855, y)
|
await page.mouse.move(855, y)
|
||||||
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
|
|
||||||
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
await page.getByRole('button', { name: 'Exit Sketch' }).click()
|
||||||
await page.waitForTimeout(400)
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
|
||||||
await page.mouse.move(x, 419)
|
await page.mouse.move(x, 419)
|
||||||
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
|
|
||||||
await hoverOverNothing()
|
await hoverOverNothing()
|
||||||
|
|
||||||
await page.mouse.move(855, y)
|
await page.mouse.move(855, y)
|
||||||
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
|
await expect(page.getByTestId('hover-highlight').first()).toBeVisible({
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -3734,17 +3741,12 @@ test.describe('Can edit segments by dragging their handles', () => {
|
|||||||
|
|
||||||
test('code pane closed at start-handles', async ({ page }) => {
|
test('code pane closed at start-handles', async ({ page }) => {
|
||||||
// Load the app with the code panes
|
// Load the app with the code panes
|
||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async (persistModelingContext) => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'store',
|
persistModelingContext,
|
||||||
JSON.stringify({
|
JSON.stringify({ openPanes: [] })
|
||||||
state: {
|
|
||||||
openPanes: [],
|
|
||||||
},
|
|
||||||
version: 0,
|
|
||||||
})
|
|
||||||
)
|
)
|
||||||
})
|
}, PERSIST_MODELING_CONTEXT)
|
||||||
await doEditSegmentsByDraggingHandle(page, [])
|
await doEditSegmentsByDraggingHandle(page, [])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -5081,6 +5083,7 @@ const part002 = startSketchOn('XZ')
|
|||||||
test('Horizontally constrained line remains selected after applying constraint', async ({
|
test('Horizontally constrained line remains selected after applying constraint', async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
test.setTimeout(70_000)
|
||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
'persistCode',
|
'persistCode',
|
||||||
@ -5096,6 +5099,9 @@ const part002 = startSketchOn('XZ')
|
|||||||
await u.waitForAuthSkipAppStart()
|
await u.waitForAuthSkipAppStart()
|
||||||
|
|
||||||
await page.getByText('line([3.79, 2.68], %, $seg01)').click()
|
await page.getByText('line([3.79, 2.68], %, $seg01)').click()
|
||||||
|
await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeEnabled(
|
||||||
|
{ timeout: 10_000 }
|
||||||
|
)
|
||||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||||
|
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
@ -5136,12 +5142,16 @@ const part002 = startSketchOn('XZ')
|
|||||||
await u.getGreatestPixDiff(lineAfter, TEST_COLORS.BLUE)
|
await u.getGreatestPixDiff(lineAfter, TEST_COLORS.BLUE)
|
||||||
).toBeLessThan(3)
|
).toBeLessThan(3)
|
||||||
|
|
||||||
|
await page.waitForTimeout(300)
|
||||||
await page
|
await page
|
||||||
.getByRole('button', {
|
.getByRole('button', {
|
||||||
name: 'Constraints',
|
name: 'Constraints',
|
||||||
})
|
})
|
||||||
.click()
|
.click()
|
||||||
await page.getByRole('button', { name: 'length', exact: true }).click()
|
// await expect(page.getByRole('button', { name: 'length', exact: true })).toBeVisible()
|
||||||
|
await page.waitForTimeout(200)
|
||||||
|
// await page.getByRole('button', { name: 'length', exact: true }).click()
|
||||||
|
await page.locator('[data-testid="length"]').click()
|
||||||
|
|
||||||
await page.getByLabel('length Value').fill('10')
|
await page.getByLabel('length Value').fill('10')
|
||||||
await page.getByRole('button', { name: 'Add constraining value' }).click()
|
await page.getByRole('button', { name: 'Add constraining value' }).click()
|
||||||
@ -6519,23 +6529,28 @@ test('Basic default modeling and sketch hotkeys work', async ({ page }) => {
|
|||||||
// Test that the hotkeys do nothing when
|
// Test that the hotkeys do nothing when
|
||||||
// focus is on the code pane
|
// focus is on the code pane
|
||||||
await codePane.click()
|
await codePane.click()
|
||||||
|
await page.keyboard.press('/')
|
||||||
|
await page.keyboard.press('/')
|
||||||
await page.keyboard.press('s')
|
await page.keyboard.press('s')
|
||||||
await page.keyboard.press('l')
|
await page.keyboard.press('l')
|
||||||
await page.keyboard.press('a')
|
await page.keyboard.press('a')
|
||||||
await page.keyboard.press('e')
|
await page.keyboard.press('e')
|
||||||
await expect(page.locator('.cm-content')).toHaveText('slae')
|
await expect(page.locator('.cm-content')).toHaveText('//slae')
|
||||||
await page.keyboard.press('Meta+/')
|
await page.keyboard.press('Meta+/')
|
||||||
|
await page.waitForTimeout(2000)
|
||||||
// Test these hotkeys perform actions when
|
// Test these hotkeys perform actions when
|
||||||
// focus is on the canvas
|
// focus is on the canvas
|
||||||
await page.mouse.move(600, 250)
|
await page.mouse.move(600, 250)
|
||||||
await page.mouse.click(600, 250)
|
await page.mouse.click(600, 250)
|
||||||
// Start a sketch
|
// Start a sketch
|
||||||
await page.keyboard.press('s')
|
await page.keyboard.press('s')
|
||||||
await page.mouse.move(800, 300)
|
await page.waitForTimeout(2000)
|
||||||
|
await page.mouse.move(800, 300, { steps: 5 })
|
||||||
await page.mouse.click(800, 300)
|
await page.mouse.click(800, 300)
|
||||||
await page.waitForTimeout(1000)
|
await page.waitForTimeout(2000)
|
||||||
await expect(lineButton).toHaveAttribute('aria-pressed', 'true')
|
await expect(lineButton).toHaveAttribute('aria-pressed', 'true', {
|
||||||
|
timeout: 15_000,
|
||||||
|
})
|
||||||
/**
|
/**
|
||||||
* TODO: There is a bug somewhere that causes this test to fail
|
* TODO: There is a bug somewhere that causes this test to fail
|
||||||
* if you toggle the codePane closed before your trigger the
|
* if you toggle the codePane closed before your trigger the
|
||||||
@ -6546,10 +6561,13 @@ test('Basic default modeling and sketch hotkeys work', async ({ page }) => {
|
|||||||
* https://discuss.codemirror.net/t/how-to-force-unfocus-of-the-codemirror-element-in-safari/8095/3
|
* https://discuss.codemirror.net/t/how-to-force-unfocus-of-the-codemirror-element-in-safari/8095/3
|
||||||
*/
|
*/
|
||||||
await codePaneButton.click()
|
await codePaneButton.click()
|
||||||
|
await expect(u.codeLocator).not.toBeVisible()
|
||||||
|
await page.waitForTimeout(300)
|
||||||
|
|
||||||
// Draw a line
|
// Draw a line
|
||||||
await page.mouse.move(700, 200, { steps: 5 })
|
await page.mouse.move(700, 200, { steps: 5 })
|
||||||
await page.mouse.click(700, 200)
|
await page.mouse.click(700, 200)
|
||||||
|
await page.waitForTimeout(300)
|
||||||
await page.mouse.move(800, 250, { steps: 5 })
|
await page.mouse.move(800, 250, { steps: 5 })
|
||||||
await page.mouse.click(800, 250)
|
await page.mouse.click(800, 250)
|
||||||
// Unequip line tool
|
// Unequip line tool
|
||||||
@ -6557,7 +6575,9 @@ test('Basic default modeling and sketch hotkeys work', async ({ page }) => {
|
|||||||
await expect(lineButton).not.toHaveAttribute('aria-pressed', 'true')
|
await expect(lineButton).not.toHaveAttribute('aria-pressed', 'true')
|
||||||
// Equip arc tool
|
// Equip arc tool
|
||||||
await page.keyboard.press('a')
|
await page.keyboard.press('a')
|
||||||
await expect(arcButton).toHaveAttribute('aria-pressed', 'true')
|
await expect(arcButton).toHaveAttribute('aria-pressed', 'true', {
|
||||||
|
timeout: 10_000,
|
||||||
|
})
|
||||||
await page.mouse.move(1000, 100, { steps: 5 })
|
await page.mouse.move(1000, 100, { steps: 5 })
|
||||||
await page.mouse.click(1000, 100)
|
await page.mouse.click(1000, 100)
|
||||||
await page.keyboard.press('Escape')
|
await page.keyboard.press('Escape')
|
||||||
@ -6582,8 +6602,13 @@ test('Basic default modeling and sketch hotkeys work', async ({ page }) => {
|
|||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(100)
|
||||||
await page.mouse.move(800, 200, { steps: 5 })
|
await page.mouse.move(800, 200, { steps: 5 })
|
||||||
await page.mouse.click(800, 200)
|
await page.mouse.click(800, 200)
|
||||||
await page.waitForTimeout(100)
|
await page.waitForTimeout(300)
|
||||||
|
await expect(page.getByRole('button', { name: 'Continue' })).toBeVisible()
|
||||||
await page.getByRole('button', { name: 'Continue' }).click()
|
await page.getByRole('button', { name: 'Continue' }).click()
|
||||||
|
await page.waitForTimeout(300)
|
||||||
|
await expect(
|
||||||
|
page.getByRole('button', { name: 'Submit command' })
|
||||||
|
).toBeVisible()
|
||||||
await page.getByRole('button', { name: 'Submit command' }).click()
|
await page.getByRole('button', { name: 'Submit command' }).click()
|
||||||
|
|
||||||
await codePaneButton.click()
|
await codePaneButton.click()
|
||||||
|
21
src/App.tsx
21
src/App.tsx
@ -1,6 +1,5 @@
|
|||||||
import { MouseEventHandler, useEffect, useRef } from 'react'
|
import { MouseEventHandler, useEffect, useRef } from 'react'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
import { useStore } from './useStore'
|
|
||||||
import { useHotKeyListener } from './hooks/useHotKeyListener'
|
import { useHotKeyListener } from './hooks/useHotKeyListener'
|
||||||
import { Stream } from './components/Stream'
|
import { Stream } from './components/Stream'
|
||||||
import { EngineCommand } from './lang/std/engineConnection'
|
import { EngineCommand } from './lang/std/engineConnection'
|
||||||
@ -26,6 +25,7 @@ import ModalContainer from 'react-modal-promise'
|
|||||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
||||||
import Gizmo from 'components/Gizmo'
|
import Gizmo from 'components/Gizmo'
|
||||||
import { CoreDumpManager } from 'lib/coredump'
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
|
import { useStore } from 'useStore'
|
||||||
|
|
||||||
export function App() {
|
export function App() {
|
||||||
useRefreshSettings(paths.FILE + 'SETTINGS')
|
useRefreshSettings(paths.FILE + 'SETTINGS')
|
||||||
@ -44,13 +44,10 @@ export function App() {
|
|||||||
}, [projectName, projectPath])
|
}, [projectName, projectPath])
|
||||||
|
|
||||||
useHotKeyListener()
|
useHotKeyListener()
|
||||||
const { buttonDownInStream, didDragInStream, streamDimensions, setHtmlRef } =
|
const { context } = useModelingContext()
|
||||||
useStore((s) => ({
|
const { setHtmlRef } = useStore((s) => ({
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
setHtmlRef: s.setHtmlRef,
|
||||||
didDragInStream: s.didDragInStream,
|
}))
|
||||||
streamDimensions: s.streamDimensions,
|
|
||||||
setHtmlRef: s.setHtmlRef,
|
|
||||||
}))
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setHtmlRef(ref)
|
setHtmlRef(ref)
|
||||||
@ -81,7 +78,7 @@ export function App() {
|
|||||||
(p) => p === onboardingStatus.current
|
(p) => p === onboardingStatus.current
|
||||||
)
|
)
|
||||||
? 'opacity-20'
|
? 'opacity-20'
|
||||||
: didDragInStream
|
: context.store?.didDragInStream
|
||||||
? 'opacity-40'
|
? 'opacity-40'
|
||||||
: ''
|
: ''
|
||||||
|
|
||||||
@ -99,11 +96,11 @@ export function App() {
|
|||||||
clientX: e.clientX,
|
clientX: e.clientX,
|
||||||
clientY: e.clientY,
|
clientY: e.clientY,
|
||||||
el: e.currentTarget,
|
el: e.currentTarget,
|
||||||
...streamDimensions,
|
...context.store?.streamDimensions,
|
||||||
})
|
})
|
||||||
|
|
||||||
const newCmdId = uuidv4()
|
const newCmdId = uuidv4()
|
||||||
if (buttonDownInStream === undefined) {
|
if (context.store?.buttonDownInStream === undefined) {
|
||||||
debounceSocketSend({
|
debounceSocketSend({
|
||||||
type: 'modeling_cmd_req',
|
type: 'modeling_cmd_req',
|
||||||
cmd: {
|
cmd: {
|
||||||
@ -125,7 +122,7 @@ export function App() {
|
|||||||
className={
|
className={
|
||||||
'transition-opacity transition-duration-75 ' +
|
'transition-opacity transition-duration-75 ' +
|
||||||
paneOpacity +
|
paneOpacity +
|
||||||
(buttonDownInStream ? ' pointer-events-none' : '')
|
(context.store?.buttonDownInStream ? ' pointer-events-none' : '')
|
||||||
}
|
}
|
||||||
project={{ project, file }}
|
project={{ project, file }}
|
||||||
enableMenu={true}
|
enableMenu={true}
|
||||||
|
@ -33,6 +33,14 @@ import LspProvider from 'components/LspProvider'
|
|||||||
import { KclContextProvider } from 'lang/KclProvider'
|
import { KclContextProvider } from 'lang/KclProvider'
|
||||||
import { BROWSER_PROJECT_NAME } from 'lib/constants'
|
import { BROWSER_PROJECT_NAME } from 'lib/constants'
|
||||||
import { getState, setState } from 'lib/tauri'
|
import { getState, setState } from 'lib/tauri'
|
||||||
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
|
import { engineCommandManager } from 'lib/singletons'
|
||||||
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
|
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
import { coreDump } from 'lang/wasm'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
import { useStore } from 'useStore'
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@ -87,6 +95,7 @@ const router = createBrowserRouter([
|
|||||||
<Auth>
|
<Auth>
|
||||||
<FileMachineProvider>
|
<FileMachineProvider>
|
||||||
<ModelingMachineProvider>
|
<ModelingMachineProvider>
|
||||||
|
<CoreDump />
|
||||||
<Outlet />
|
<Outlet />
|
||||||
<App />
|
<App />
|
||||||
<CommandBar />
|
<CommandBar />
|
||||||
@ -165,3 +174,33 @@ export const Router = () => {
|
|||||||
</NetworkContext.Provider>
|
</NetworkContext.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function CoreDump() {
|
||||||
|
const { auth } = useSettingsAuthContext()
|
||||||
|
const token = auth?.context?.token
|
||||||
|
const { htmlRef } = useStore((s) => ({
|
||||||
|
htmlRef: s.htmlRef,
|
||||||
|
}))
|
||||||
|
const coreDumpManager = useMemo(
|
||||||
|
() => new CoreDumpManager(engineCommandManager, htmlRef, token),
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
useHotkeyWrapper(['meta + shift + .'], () => {
|
||||||
|
toast.promise(
|
||||||
|
coreDump(coreDumpManager, true),
|
||||||
|
{
|
||||||
|
loading: 'Starting core dump...',
|
||||||
|
success: 'Core dump completed successfully',
|
||||||
|
error: 'Error while exporting core dump',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
success: {
|
||||||
|
// Note: this extended duration is especially important for Playwright e2e testing
|
||||||
|
// default duration is 2000 - https://react-hot-toast.com/docs/toast#default-durations
|
||||||
|
duration: 6000,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
@ -8,10 +8,10 @@ import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
|||||||
import { ActionButton } from 'components/ActionButton'
|
import { ActionButton } from 'components/ActionButton'
|
||||||
import { isSingleCursorInPipe } from 'lang/queryAst'
|
import { isSingleCursorInPipe } from 'lang/queryAst'
|
||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
|
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import Tooltip from 'components/Tooltip'
|
import Tooltip from 'components/Tooltip'
|
||||||
|
import { useStore } from 'useStore'
|
||||||
|
|
||||||
export function Toolbar({
|
export function Toolbar({
|
||||||
className = '',
|
className = '',
|
||||||
|
@ -37,7 +37,7 @@ import { Dialog, Popover, Transition } from '@headlessui/react'
|
|||||||
import { LineInputsType } from 'lang/std/sketchcombos'
|
import { LineInputsType } from 'lang/std/sketchcombos'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { InstanceProps, create } from 'react-modal-promise'
|
import { InstanceProps, create } from 'react-modal-promise'
|
||||||
import { executeAst } from 'useStore'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import {
|
import {
|
||||||
deleteSegmentFromPipeExpression,
|
deleteSegmentFromPipeExpression,
|
||||||
makeRemoveSingleConstraintInput,
|
makeRemoveSingleConstraintInput,
|
||||||
|
@ -58,7 +58,7 @@ import {
|
|||||||
editorManager,
|
editorManager,
|
||||||
} from 'lib/singletons'
|
} from 'lib/singletons'
|
||||||
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
|
import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst'
|
||||||
import { executeAst, useStore } from 'useStore'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import {
|
import {
|
||||||
createArcGeometry,
|
createArcGeometry,
|
||||||
dashedStraight,
|
dashedStraight,
|
||||||
@ -1444,11 +1444,10 @@ export class SceneEntities {
|
|||||||
selected.material.color = defaultPlaneColor(type)
|
selected.material.color = defaultPlaneColor(type)
|
||||||
},
|
},
|
||||||
onClick: async (args) => {
|
onClick: async (args) => {
|
||||||
const { streamDimensions } = useStore.getState()
|
|
||||||
const { entity_id } = await sendSelectEventToEngine(
|
const { entity_id } = await sendSelectEventToEngine(
|
||||||
args?.mouseEvent,
|
args?.mouseEvent,
|
||||||
document.getElementById('video-stream') as HTMLVideoElement,
|
document.getElementById('video-stream') as HTMLVideoElement,
|
||||||
streamDimensions
|
sceneInfra._streamDimensions
|
||||||
)
|
)
|
||||||
|
|
||||||
let _entity_id = entity_id
|
let _entity_id = entity_id
|
||||||
|
@ -103,6 +103,10 @@ export class SceneInfra {
|
|||||||
_baseUnit: BaseUnit = 'mm'
|
_baseUnit: BaseUnit = 'mm'
|
||||||
_baseUnitMultiplier = 1
|
_baseUnitMultiplier = 1
|
||||||
_theme: Themes = Themes.System
|
_theme: Themes = Themes.System
|
||||||
|
_streamDimensions: { streamWidth: number; streamHeight: number } = {
|
||||||
|
streamWidth: 1280,
|
||||||
|
streamHeight: 720,
|
||||||
|
}
|
||||||
extraSegmentTexture: Texture
|
extraSegmentTexture: Texture
|
||||||
lastMouseState: MouseState = { type: 'idle' }
|
lastMouseState: MouseState = { type: 'idle' }
|
||||||
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
onDragStartCallback: (arg: OnDragCallbackArgs) => void = () => {}
|
||||||
|
@ -10,7 +10,7 @@ import { findAllPreviousVariables, PrevVariable } from '../lang/queryAst'
|
|||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
import { useModelingContext } from 'hooks/useModelingContext'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
import { executeAst } from 'useStore'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import { trap } from 'lib/trap'
|
import { trap } from 'lib/trap'
|
||||||
|
|
||||||
export const AvailableVars = ({
|
export const AvailableVars = ({
|
||||||
|
@ -30,7 +30,6 @@ import {
|
|||||||
applyConstraintAngleBetween,
|
applyConstraintAngleBetween,
|
||||||
} from './Toolbar/SetAngleBetween'
|
} from './Toolbar/SetAngleBetween'
|
||||||
import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
|
import { applyConstraintAngleLength } from './Toolbar/setAngleLength'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import {
|
import {
|
||||||
Selections,
|
Selections,
|
||||||
canExtrudeSelection,
|
canExtrudeSelection,
|
||||||
@ -54,13 +53,7 @@ import {
|
|||||||
sketchOnExtrudedFace,
|
sketchOnExtrudedFace,
|
||||||
startSketchOnDefault,
|
startSketchOnDefault,
|
||||||
} from 'lang/modifyAst'
|
} from 'lang/modifyAst'
|
||||||
import {
|
import { Program, VariableDeclaration, parse, recast } from 'lang/wasm'
|
||||||
Program,
|
|
||||||
VariableDeclaration,
|
|
||||||
coreDump,
|
|
||||||
parse,
|
|
||||||
recast,
|
|
||||||
} from 'lang/wasm'
|
|
||||||
import {
|
import {
|
||||||
getNodeFromPath,
|
getNodeFromPath,
|
||||||
getNodePathFromSourceRange,
|
getNodePathFromSourceRange,
|
||||||
@ -72,11 +65,9 @@ import { exportFromEngine } from 'lib/exportFromEngine'
|
|||||||
import { Models } from '@kittycad/lib/dist/types/src'
|
import { Models } from '@kittycad/lib/dist/types/src'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { EditorSelection, Transaction } from '@uiw/react-codemirror'
|
import { EditorSelection, Transaction } from '@uiw/react-codemirror'
|
||||||
import { CoreDumpManager } from 'lib/coredump'
|
|
||||||
import { useSearchParams } from 'react-router-dom'
|
import { useSearchParams } from 'react-router-dom'
|
||||||
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
|
import { letEngineAnimateAndSyncCamAfter } from 'clientSideScene/CameraControls'
|
||||||
import { getVarNameModal } from 'hooks/useToolbarGuards'
|
import { getVarNameModal } from 'hooks/useToolbarGuards'
|
||||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
import { err, trap } from 'lib/trap'
|
import { err, trap } from 'lib/trap'
|
||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
@ -112,38 +103,6 @@ export const ModelingMachineProvider = ({
|
|||||||
let [searchParams] = useSearchParams()
|
let [searchParams] = useSearchParams()
|
||||||
const pool = searchParams.get('pool')
|
const pool = searchParams.get('pool')
|
||||||
|
|
||||||
useSetupEngineManager(streamRef, token, {
|
|
||||||
pool: pool,
|
|
||||||
theme: theme.current,
|
|
||||||
highlightEdges: highlightEdges.current,
|
|
||||||
enableSSAO: enableSSAO.current,
|
|
||||||
showScaleGrid: showScaleGrid.current,
|
|
||||||
})
|
|
||||||
const { htmlRef } = useStore((s) => ({
|
|
||||||
htmlRef: s.htmlRef,
|
|
||||||
}))
|
|
||||||
const coreDumpManager = new CoreDumpManager(
|
|
||||||
engineCommandManager,
|
|
||||||
htmlRef,
|
|
||||||
token
|
|
||||||
)
|
|
||||||
useHotkeyWrapper(['meta + shift + .'], () => {
|
|
||||||
toast.promise(
|
|
||||||
coreDump(coreDumpManager, true),
|
|
||||||
{
|
|
||||||
loading: 'Starting core dump...',
|
|
||||||
success: 'Core dump completed successfully',
|
|
||||||
error: 'Error while exporting core dump',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
success: {
|
|
||||||
// Note: this extended duration is especially important for Playwright e2e testing
|
|
||||||
// default duration is 2000 - https://react-hot-toast.com/docs/toast#default-durations
|
|
||||||
duration: 6000,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
const { commandBarState } = useCommandsContext()
|
const { commandBarState } = useCommandsContext()
|
||||||
|
|
||||||
// Settings machine setup
|
// Settings machine setup
|
||||||
@ -904,6 +863,16 @@ export const ModelingMachineProvider = ({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
useSetupEngineManager(streamRef, token, {
|
||||||
|
pool: pool,
|
||||||
|
theme: theme.current,
|
||||||
|
highlightEdges: highlightEdges.current,
|
||||||
|
enableSSAO: enableSSAO.current,
|
||||||
|
modelingSend,
|
||||||
|
modelingContext: modelingState.context,
|
||||||
|
showScaleGrid: showScaleGrid.current,
|
||||||
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
kclManager.registerExecuteCallback(() => {
|
kclManager.registerExecuteCallback(() => {
|
||||||
modelingSend({ type: 'Re-execute' })
|
modelingSend({ type: 'Re-execute' })
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useStore } from 'useStore'
|
|
||||||
import styles from './ModelingPane.module.css'
|
import styles from './ModelingPane.module.css'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export interface ModelingPaneProps
|
export interface ModelingPaneProps
|
||||||
extends React.PropsWithChildren,
|
extends React.PropsWithChildren,
|
||||||
@ -33,11 +33,9 @@ export const ModelingPane = ({
|
|||||||
}: ModelingPaneProps) => {
|
}: ModelingPaneProps) => {
|
||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const onboardingStatus = settings.context.app.onboardingStatus
|
const onboardingStatus = settings.context.app.onboardingStatus
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const pointerEventsCssClass =
|
const pointerEventsCssClass =
|
||||||
buttonDownInStream || onboardingStatus.current === 'camera'
|
context.store?.buttonDownInStream || onboardingStatus.current === 'camera'
|
||||||
? 'pointer-events-none '
|
? 'pointer-events-none '
|
||||||
: 'pointer-events-auto '
|
: 'pointer-events-auto '
|
||||||
return (
|
return (
|
||||||
|
@ -2,7 +2,6 @@ import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
|||||||
import { Resizable } from 're-resizable'
|
import { Resizable } from 're-resizable'
|
||||||
import { HTMLAttributes, useCallback, useEffect, useState } from 'react'
|
import { HTMLAttributes, useCallback, useEffect, useState } from 'react'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { Tab } from '@headlessui/react'
|
import { Tab } from '@headlessui/react'
|
||||||
import {
|
import {
|
||||||
SidebarPane,
|
SidebarPane,
|
||||||
@ -15,6 +14,7 @@ import { ActionIcon } from 'components/ActionIcon'
|
|||||||
import styles from './ModelingSidebar.module.css'
|
import styles from './ModelingSidebar.module.css'
|
||||||
import { ModelingPane } from './ModelingPane'
|
import { ModelingPane } from './ModelingPane'
|
||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
interface ModelingSidebarProps {
|
interface ModelingSidebarProps {
|
||||||
paneOpacity: '' | 'opacity-20' | 'opacity-40'
|
paneOpacity: '' | 'opacity-20' | 'opacity-40'
|
||||||
@ -23,14 +23,11 @@ interface ModelingSidebarProps {
|
|||||||
export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const onboardingStatus = settings.context.app.onboardingStatus
|
const onboardingStatus = settings.context.app.onboardingStatus
|
||||||
const { openPanes, buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
openPanes: s.openPanes,
|
|
||||||
}))
|
|
||||||
const pointerEventsCssClass =
|
const pointerEventsCssClass =
|
||||||
buttonDownInStream ||
|
context.store?.buttonDownInStream ||
|
||||||
onboardingStatus.current === 'camera' ||
|
onboardingStatus.current === 'camera' ||
|
||||||
openPanes.length === 0
|
context.store?.openPanes.length === 0
|
||||||
? 'pointer-events-none '
|
? 'pointer-events-none '
|
||||||
: 'pointer-events-auto '
|
: 'pointer-events-auto '
|
||||||
|
|
||||||
@ -45,7 +42,7 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
|||||||
maxWidth={800}
|
maxWidth={800}
|
||||||
handleClasses={{
|
handleClasses={{
|
||||||
right:
|
right:
|
||||||
(openPanes.length === 0 ? 'hidden ' : 'block ') +
|
(context.store?.openPanes.length === 0 ? 'hidden ' : 'block ') +
|
||||||
'translate-x-1/2 hover:bg-chalkboard-10 hover:dark:bg-chalkboard-110 bg-transparent transition-colors duration-75 transition-ease-out delay-100 ',
|
'translate-x-1/2 hover:bg-chalkboard-10 hover:dark:bg-chalkboard-110 bg-transparent transition-colors duration-75 transition-ease-out delay-100 ',
|
||||||
left: 'hidden',
|
left: 'hidden',
|
||||||
top: 'hidden',
|
top: 'hidden',
|
||||||
@ -82,11 +79,10 @@ function ModelingSidebarSection({
|
|||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const showDebugPanel = settings.context.modeling.showDebugPanel
|
const showDebugPanel = settings.context.modeling.showDebugPanel
|
||||||
const paneIds = panes.map((pane) => pane.id)
|
const paneIds = panes.map((pane) => pane.id)
|
||||||
const { openPanes, setOpenPanes } = useStore((s) => ({
|
const { send, context } = useModelingContext()
|
||||||
openPanes: s.openPanes,
|
const foundOpenPane = context.store?.openPanes.find((pane) =>
|
||||||
setOpenPanes: s.setOpenPanes,
|
paneIds.includes(pane)
|
||||||
}))
|
)
|
||||||
const foundOpenPane = openPanes.find((pane) => paneIds.includes(pane))
|
|
||||||
const [currentPane, setCurrentPane] = useState(
|
const [currentPane, setCurrentPane] = useState(
|
||||||
foundOpenPane || ('none' as SidebarType | 'none')
|
foundOpenPane || ('none' as SidebarType | 'none')
|
||||||
)
|
)
|
||||||
@ -94,17 +90,37 @@ function ModelingSidebarSection({
|
|||||||
const togglePane = useCallback(
|
const togglePane = useCallback(
|
||||||
(newPane: SidebarType | 'none') => {
|
(newPane: SidebarType | 'none') => {
|
||||||
if (newPane === 'none') {
|
if (newPane === 'none') {
|
||||||
setOpenPanes(openPanes.filter((p) => p !== currentPane))
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
openPanes: context.store?.openPanes.filter(
|
||||||
|
(p) => p !== currentPane
|
||||||
|
),
|
||||||
|
},
|
||||||
|
})
|
||||||
setCurrentPane('none')
|
setCurrentPane('none')
|
||||||
} else if (newPane === currentPane) {
|
} else if (newPane === currentPane) {
|
||||||
setCurrentPane('none')
|
setCurrentPane('none')
|
||||||
setOpenPanes(openPanes.filter((p) => p !== newPane))
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
openPanes: context.store?.openPanes.filter((p) => p !== newPane),
|
||||||
|
},
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
setOpenPanes([...openPanes.filter((p) => p !== currentPane), newPane])
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
openPanes: [
|
||||||
|
...context.store?.openPanes.filter((p) => p !== currentPane),
|
||||||
|
newPane,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
setCurrentPane(newPane)
|
setCurrentPane(newPane)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[openPanes, setOpenPanes, currentPane, setCurrentPane]
|
[context.store?.openPanes, send, currentPane, setCurrentPane]
|
||||||
)
|
)
|
||||||
|
|
||||||
// Filter out the debug panel if it's not supposed to be shown
|
// Filter out the debug panel if it's not supposed to be shown
|
||||||
@ -122,11 +138,11 @@ function ModelingSidebarSection({
|
|||||||
if (
|
if (
|
||||||
!showDebugPanel.current &&
|
!showDebugPanel.current &&
|
||||||
currentPane === 'debug' &&
|
currentPane === 'debug' &&
|
||||||
openPanes.includes('debug')
|
context.store?.openPanes.includes('debug')
|
||||||
) {
|
) {
|
||||||
togglePane('debug')
|
togglePane('debug')
|
||||||
}
|
}
|
||||||
}, [showDebugPanel.current, togglePane, openPanes])
|
}, [showDebugPanel.current, togglePane, context.store?.openPanes])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'group contents ' + className} {...props}>
|
<div className={'group contents ' + className} {...props}>
|
||||||
@ -152,7 +168,9 @@ function ModelingSidebarSection({
|
|||||||
: ' border-r-0') +
|
: ' border-r-0') +
|
||||||
' p-2 col-start-1 col-span-1 h-fit w-fit flex flex-col items-start gap-2 ' +
|
' p-2 col-start-1 col-span-1 h-fit w-fit flex flex-col items-start gap-2 ' +
|
||||||
'bg-chalkboard-10 border border-solid border-chalkboard-20 dark:bg-chalkboard-90 dark:border-chalkboard-80 group-focus-within:border-primary dark:group-focus-within:border-chalkboard-50 ' +
|
'bg-chalkboard-10 border border-solid border-chalkboard-20 dark:bg-chalkboard-90 dark:border-chalkboard-80 group-focus-within:border-primary dark:group-focus-within:border-chalkboard-50 ' +
|
||||||
(openPanes.length === 1 && currentPane === 'none' ? 'pr-0.5' : '')
|
(context.store?.openPanes.length === 1 && currentPane === 'none'
|
||||||
|
? 'pr-0.5'
|
||||||
|
: '')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tab key="none" className="sr-only">
|
<Tab key="none" className="sr-only">
|
||||||
@ -172,7 +190,7 @@ function ModelingSidebarSection({
|
|||||||
as="article"
|
as="article"
|
||||||
className={
|
className={
|
||||||
'col-start-2 col-span-1 ' +
|
'col-start-2 col-span-1 ' +
|
||||||
(openPanes.length === 1
|
(context.store?.openPanes.length === 1
|
||||||
? currentPane !== 'none'
|
? currentPane !== 'none'
|
||||||
? `row-start-1 row-end-3`
|
? `row-start-1 row-end-3`
|
||||||
: `hidden`
|
: `hidden`
|
||||||
|
@ -2,11 +2,11 @@ import { coreDump } from 'lang/wasm'
|
|||||||
import { CoreDumpManager } from 'lib/coredump'
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
import { CustomIcon } from './CustomIcon'
|
import { CustomIcon } from './CustomIcon'
|
||||||
import { engineCommandManager } from 'lib/singletons'
|
import { engineCommandManager } from 'lib/singletons'
|
||||||
import React from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import Tooltip from './Tooltip'
|
import Tooltip from './Tooltip'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
|
import { useStore } from 'useStore'
|
||||||
|
|
||||||
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
|
export const RefreshButton = ({ children }: React.PropsWithChildren) => {
|
||||||
const { auth } = useSettingsAuthContext()
|
const { auth } = useSettingsAuthContext()
|
||||||
@ -14,10 +14,9 @@ export const RefreshButton = ({ children }: React.PropsWithChildren) => {
|
|||||||
const { htmlRef } = useStore((s) => ({
|
const { htmlRef } = useStore((s) => ({
|
||||||
htmlRef: s.htmlRef,
|
htmlRef: s.htmlRef,
|
||||||
}))
|
}))
|
||||||
const coreDumpManager = new CoreDumpManager(
|
const coreDumpManager = useMemo(
|
||||||
engineCommandManager,
|
() => new CoreDumpManager(engineCommandManager, htmlRef, token),
|
||||||
htmlRef,
|
[]
|
||||||
token
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
|
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
|
||||||
import { useStore } from '../useStore'
|
|
||||||
import { getNormalisedCoordinates } from '../lib/utils'
|
import { getNormalisedCoordinates } from '../lib/utils'
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
@ -10,25 +9,12 @@ import { ClientSideScene } from 'clientSideScene/ClientSideSceneComp'
|
|||||||
import { butName } from 'lib/cameraControls'
|
import { butName } from 'lib/cameraControls'
|
||||||
import { sendSelectEventToEngine } from 'lib/selections'
|
import { sendSelectEventToEngine } from 'lib/selections'
|
||||||
|
|
||||||
export const Stream = ({ className = '' }: { className?: string }) => {
|
export const Stream = () => {
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const [isLoading, setIsLoading] = useState(true)
|
||||||
const [clickCoords, setClickCoords] = useState<{ x: number; y: number }>()
|
const [clickCoords, setClickCoords] = useState<{ x: number; y: number }>()
|
||||||
const videoRef = useRef<HTMLVideoElement>(null)
|
const videoRef = useRef<HTMLVideoElement>(null)
|
||||||
const {
|
|
||||||
mediaStream,
|
|
||||||
setButtonDownInStream,
|
|
||||||
didDragInStream,
|
|
||||||
setDidDragInStream,
|
|
||||||
streamDimensions,
|
|
||||||
} = useStore((s) => ({
|
|
||||||
mediaStream: s.mediaStream,
|
|
||||||
setButtonDownInStream: s.setButtonDownInStream,
|
|
||||||
didDragInStream: s.didDragInStream,
|
|
||||||
setDidDragInStream: s.setDidDragInStream,
|
|
||||||
streamDimensions: s.streamDimensions,
|
|
||||||
}))
|
|
||||||
const { settings } = useSettingsAuthContext()
|
const { settings } = useSettingsAuthContext()
|
||||||
const { state } = useModelingContext()
|
const { state, send, context } = useModelingContext()
|
||||||
const { overallState } = useNetworkContext()
|
const { overallState } = useNetworkContext()
|
||||||
|
|
||||||
const isNetworkOkay =
|
const isNetworkOkay =
|
||||||
@ -74,9 +60,9 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return
|
||||||
if (!mediaStream) return
|
if (!context.store?.mediaStream) return
|
||||||
videoRef.current.srcObject = mediaStream
|
videoRef.current.srcObject = context.store.mediaStream
|
||||||
}, [mediaStream])
|
}, [context.store?.mediaStream])
|
||||||
|
|
||||||
const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {
|
const handleMouseDown: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||||
if (!isNetworkOkay) return
|
if (!isNetworkOkay) return
|
||||||
@ -88,25 +74,44 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
|||||||
clientX: e.clientX,
|
clientX: e.clientX,
|
||||||
clientY: e.clientY,
|
clientY: e.clientY,
|
||||||
el: videoRef.current,
|
el: videoRef.current,
|
||||||
...streamDimensions,
|
...context.store?.streamDimensions,
|
||||||
})
|
})
|
||||||
|
|
||||||
setButtonDownInStream(e.button)
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
buttonDownInStream: e.button,
|
||||||
|
},
|
||||||
|
})
|
||||||
setClickCoords({ x, y })
|
setClickCoords({ x, y })
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
|
const handleMouseUp: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||||
if (!isNetworkOkay) return
|
if (!isNetworkOkay) return
|
||||||
if (!videoRef.current) return
|
if (!videoRef.current) return
|
||||||
setButtonDownInStream(undefined)
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
buttonDownInStream: undefined,
|
||||||
|
},
|
||||||
|
})
|
||||||
if (state.matches('Sketch')) return
|
if (state.matches('Sketch')) return
|
||||||
if (state.matches('Sketch no face')) return
|
if (state.matches('Sketch no face')) return
|
||||||
|
|
||||||
if (!didDragInStream && butName(e).left) {
|
if (!context.store?.didDragInStream && butName(e).left) {
|
||||||
sendSelectEventToEngine(e, videoRef.current, streamDimensions)
|
sendSelectEventToEngine(
|
||||||
|
e,
|
||||||
|
videoRef.current,
|
||||||
|
context.store?.streamDimensions
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setDidDragInStream(false)
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
didDragInStream: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
setClickCoords(undefined)
|
setClickCoords(undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,8 +125,13 @@ export const Stream = ({ className = '' }: { className?: string }) => {
|
|||||||
((clickCoords.x - e.clientX) ** 2 + (clickCoords.y - e.clientY) ** 2) **
|
((clickCoords.x - e.clientX) ** 2 + (clickCoords.y - e.clientY) ** 2) **
|
||||||
0.5
|
0.5
|
||||||
|
|
||||||
if (delta > 5 && !didDragInStream) {
|
if (delta > 5 && !context.store?.didDragInStream) {
|
||||||
setDidDragInStream(true)
|
send({
|
||||||
|
type: 'Set context',
|
||||||
|
data: {
|
||||||
|
didDragInStream: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { Program, ProgramMemory, Value } from '../../lang/wasm'
|
import { Program, ProgramMemory, Value } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selection, Selections } from 'lib/selections'
|
import { Selection, Selections } from 'lib/selections'
|
||||||
import { PathToNode, Program, Value } from '../../lang/wasm'
|
import { PathToNode, Program, Value } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { BinaryPart, Program, Value } from '../../lang/wasm'
|
import { BinaryPart, Program, Value } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
import { BinaryPart, Program, Value, VariableDeclarator } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
getNodePathFromSourceRange,
|
getNodePathFromSourceRange,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { toolTips } from '../../useStore'
|
import { toolTips } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { BinaryPart, Program, Value } from '../../lang/wasm'
|
import { BinaryPart, Program, Value } from '../../lang/wasm'
|
||||||
import {
|
import {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { useLayoutEffect, useEffect, useRef } from 'react'
|
import { useLayoutEffect, useEffect, useRef } from 'react'
|
||||||
import { useStore } from '../useStore'
|
|
||||||
import { engineCommandManager, kclManager } from 'lib/singletons'
|
import { engineCommandManager, kclManager } from 'lib/singletons'
|
||||||
import { deferExecution } from 'lib/utils'
|
import { deferExecution } from 'lib/utils'
|
||||||
import { Themes } from 'lib/theme'
|
import { Themes } from 'lib/theme'
|
||||||
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
|
import { makeDefaultPlanes, modifyGrid } from 'lang/wasm'
|
||||||
|
import { useModelingContext } from './useModelingContext'
|
||||||
|
import { useStore } from 'useStore'
|
||||||
|
|
||||||
export function useSetupEngineManager(
|
export function useSetupEngineManager(
|
||||||
streamRef: React.RefObject<HTMLDivElement>,
|
streamRef: React.RefObject<HTMLDivElement>,
|
||||||
@ -13,25 +14,21 @@ export function useSetupEngineManager(
|
|||||||
theme: Themes.System,
|
theme: Themes.System,
|
||||||
highlightEdges: true,
|
highlightEdges: true,
|
||||||
enableSSAO: true,
|
enableSSAO: true,
|
||||||
|
modelingSend: (() => {}) as any,
|
||||||
|
modelingContext: {} as any,
|
||||||
showScaleGrid: false,
|
showScaleGrid: false,
|
||||||
} as {
|
} as {
|
||||||
pool: string | null
|
pool: string | null
|
||||||
theme: Themes
|
theme: Themes
|
||||||
highlightEdges: boolean
|
highlightEdges: boolean
|
||||||
enableSSAO: boolean
|
enableSSAO: boolean
|
||||||
|
modelingSend: ReturnType<typeof useModelingContext>['send']
|
||||||
|
modelingContext: ReturnType<typeof useModelingContext>['context']
|
||||||
showScaleGrid: boolean
|
showScaleGrid: boolean
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const {
|
const { setIsStreamReady } = useStore((s) => ({
|
||||||
setMediaStream,
|
|
||||||
setIsStreamReady,
|
|
||||||
setStreamDimensions,
|
|
||||||
streamDimensions,
|
|
||||||
} = useStore((s) => ({
|
|
||||||
setMediaStream: s.setMediaStream,
|
|
||||||
setIsStreamReady: s.setIsStreamReady,
|
setIsStreamReady: s.setIsStreamReady,
|
||||||
setStreamDimensions: s.setStreamDimensions,
|
|
||||||
streamDimensions: s.streamDimensions,
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const streamWidth = streamRef?.current?.offsetWidth
|
const streamWidth = streamRef?.current?.offsetWidth
|
||||||
@ -52,9 +49,18 @@ export function useSetupEngineManager(
|
|||||||
streamWidth,
|
streamWidth,
|
||||||
streamHeight
|
streamHeight
|
||||||
)
|
)
|
||||||
if (!hasSetNonZeroDimensions.current && quadHeight && quadWidth) {
|
if (
|
||||||
|
!hasSetNonZeroDimensions.current &&
|
||||||
|
quadHeight &&
|
||||||
|
quadWidth &&
|
||||||
|
settings.modelingSend
|
||||||
|
) {
|
||||||
engineCommandManager.start({
|
engineCommandManager.start({
|
||||||
setMediaStream,
|
setMediaStream: (mediaStream) =>
|
||||||
|
settings.modelingSend({
|
||||||
|
type: 'Set context',
|
||||||
|
data: { mediaStream },
|
||||||
|
}),
|
||||||
setIsStreamReady,
|
setIsStreamReady,
|
||||||
width: quadWidth,
|
width: quadWidth,
|
||||||
height: quadHeight,
|
height: quadHeight,
|
||||||
@ -72,9 +78,14 @@ export function useSetupEngineManager(
|
|||||||
return modifyGrid(kclManager.engineCommandManager, hidden)
|
return modifyGrid(kclManager.engineCommandManager, hidden)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
setStreamDimensions({
|
settings.modelingSend({
|
||||||
streamWidth: quadWidth,
|
type: 'Set context',
|
||||||
streamHeight: quadHeight,
|
data: {
|
||||||
|
streamDimensions: {
|
||||||
|
streamWidth: quadWidth,
|
||||||
|
streamHeight: quadHeight,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
hasSetNonZeroDimensions.current = true
|
hasSetNonZeroDimensions.current = true
|
||||||
}
|
}
|
||||||
@ -83,6 +94,7 @@ export function useSetupEngineManager(
|
|||||||
useLayoutEffect(startEngineInstance, [
|
useLayoutEffect(startEngineInstance, [
|
||||||
streamRef?.current?.offsetWidth,
|
streamRef?.current?.offsetWidth,
|
||||||
streamRef?.current?.offsetHeight,
|
streamRef?.current?.offsetHeight,
|
||||||
|
settings.modelingSend,
|
||||||
])
|
])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -92,16 +104,21 @@ export function useSetupEngineManager(
|
|||||||
streamRef?.current?.offsetHeight
|
streamRef?.current?.offsetHeight
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
streamDimensions.streamWidth !== width ||
|
settings.modelingContext.store.streamDimensions.streamWidth !== width ||
|
||||||
streamDimensions.streamHeight !== height
|
settings.modelingContext.store.streamDimensions.streamHeight !== height
|
||||||
) {
|
) {
|
||||||
engineCommandManager.handleResize({
|
engineCommandManager.handleResize({
|
||||||
streamWidth: width,
|
streamWidth: width,
|
||||||
streamHeight: height,
|
streamHeight: height,
|
||||||
})
|
})
|
||||||
setStreamDimensions({
|
settings.modelingSend({
|
||||||
streamWidth: width,
|
type: 'Set context',
|
||||||
streamHeight: height,
|
data: {
|
||||||
|
streamDimensions: {
|
||||||
|
streamWidth: width,
|
||||||
|
streamHeight: height,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
|
@ -8,9 +8,9 @@ import { settingsMachine } from 'machines/settingsMachine'
|
|||||||
import { homeMachine } from 'machines/homeMachine'
|
import { homeMachine } from 'machines/homeMachine'
|
||||||
import { Command, CommandSetConfig, CommandSetSchema } from 'lib/commandTypes'
|
import { Command, CommandSetConfig, CommandSetSchema } from 'lib/commandTypes'
|
||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { useNetworkContext } from 'hooks/useNetworkContext'
|
import { useNetworkContext } from 'hooks/useNetworkContext'
|
||||||
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
import { NetworkHealthState } from 'hooks/useNetworkStatus'
|
||||||
|
import { useStore } from 'useStore'
|
||||||
|
|
||||||
// This might not be necessary, AnyStateMachine from xstate is working
|
// This might not be necessary, AnyStateMachine from xstate is working
|
||||||
export type AllMachines =
|
export type AllMachines =
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { executeAst, lintAst } from 'useStore'
|
import { executeAst, lintAst } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { KCLError, kclErrorsToDiagnostics } from './errors'
|
import { KCLError, kclErrorsToDiagnostics } from './errors'
|
||||||
import { uuidv4 } from 'lib/utils'
|
import { uuidv4 } from 'lib/utils'
|
||||||
|
@ -8,7 +8,7 @@ import toast from 'react-hot-toast'
|
|||||||
import { editorManager } from 'lib/singletons'
|
import { editorManager } from 'lib/singletons'
|
||||||
import { Annotation, KeyBinding, Transaction } from '@uiw/react-codemirror'
|
import { Annotation, KeyBinding, Transaction } from '@uiw/react-codemirror'
|
||||||
|
|
||||||
const PERSIST_CODE_TOKEN = 'persistCode'
|
const PERSIST_CODE_KEY = 'persistCode'
|
||||||
|
|
||||||
const codeManagerUpdateAnnotation = Annotation.define<null>()
|
const codeManagerUpdateAnnotation = Annotation.define<null>()
|
||||||
export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(null)
|
export const codeManagerUpdateEvent = codeManagerUpdateAnnotation.of(null)
|
||||||
@ -25,7 +25,7 @@ export default class CodeManager {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const storedCode = safeLSGetItem(PERSIST_CODE_TOKEN)
|
const storedCode = safeLSGetItem(PERSIST_CODE_KEY)
|
||||||
// TODO #819 remove zustand persistence logic in a few months
|
// TODO #819 remove zustand persistence logic in a few months
|
||||||
// short term migration, shouldn't make a difference for tauri app users
|
// short term migration, shouldn't make a difference for tauri app users
|
||||||
// anyway since that's filesystem based.
|
// anyway since that's filesystem based.
|
||||||
@ -125,7 +125,7 @@ export default class CodeManager {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
safeLSSetItem(PERSIST_CODE_TOKEN, this.code)
|
safeLSSetItem(PERSIST_CODE_KEY, this.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
120
src/lang/langHelpers.ts
Normal file
120
src/lang/langHelpers.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import {
|
||||||
|
Program,
|
||||||
|
_executor,
|
||||||
|
ProgramMemory,
|
||||||
|
programMemoryInit,
|
||||||
|
kclLint,
|
||||||
|
} from 'lang/wasm'
|
||||||
|
import { enginelessExecutor } from 'lib/testHelpers'
|
||||||
|
import { EngineCommandManager } from 'lang/std/engineConnection'
|
||||||
|
import { KCLError } from 'lang/errors'
|
||||||
|
import { Diagnostic } from '@codemirror/lint'
|
||||||
|
|
||||||
|
export type ToolTip =
|
||||||
|
| 'lineTo'
|
||||||
|
| 'line'
|
||||||
|
| 'angledLine'
|
||||||
|
| 'angledLineOfXLength'
|
||||||
|
| 'angledLineOfYLength'
|
||||||
|
| 'angledLineToX'
|
||||||
|
| 'angledLineToY'
|
||||||
|
| 'xLine'
|
||||||
|
| 'yLine'
|
||||||
|
| 'xLineTo'
|
||||||
|
| 'yLineTo'
|
||||||
|
| 'angledLineThatIntersects'
|
||||||
|
| 'tangentialArcTo'
|
||||||
|
|
||||||
|
export const toolTips = [
|
||||||
|
'sketch_line',
|
||||||
|
'move',
|
||||||
|
// original tooltips
|
||||||
|
'line',
|
||||||
|
'lineTo',
|
||||||
|
'angledLine',
|
||||||
|
'angledLineOfXLength',
|
||||||
|
'angledLineOfYLength',
|
||||||
|
'angledLineToX',
|
||||||
|
'angledLineToY',
|
||||||
|
'xLine',
|
||||||
|
'yLine',
|
||||||
|
'xLineTo',
|
||||||
|
'yLineTo',
|
||||||
|
'angledLineThatIntersects',
|
||||||
|
'tangentialArcTo',
|
||||||
|
] as any as ToolTip[]
|
||||||
|
|
||||||
|
export async function executeAst({
|
||||||
|
ast,
|
||||||
|
engineCommandManager,
|
||||||
|
useFakeExecutor = false,
|
||||||
|
programMemoryOverride,
|
||||||
|
}: {
|
||||||
|
ast: Program
|
||||||
|
engineCommandManager: EngineCommandManager
|
||||||
|
useFakeExecutor?: boolean
|
||||||
|
programMemoryOverride?: ProgramMemory
|
||||||
|
}): Promise<{
|
||||||
|
logs: string[]
|
||||||
|
errors: KCLError[]
|
||||||
|
programMemory: ProgramMemory
|
||||||
|
}> {
|
||||||
|
try {
|
||||||
|
if (!useFakeExecutor) {
|
||||||
|
engineCommandManager.endSession()
|
||||||
|
engineCommandManager.startNewSession()
|
||||||
|
}
|
||||||
|
const programMemory = await (useFakeExecutor
|
||||||
|
? enginelessExecutor(ast, programMemoryOverride || programMemoryInit())
|
||||||
|
: _executor(ast, programMemoryInit(), engineCommandManager, false))
|
||||||
|
|
||||||
|
await engineCommandManager.waitForAllCommands()
|
||||||
|
return {
|
||||||
|
logs: [],
|
||||||
|
errors: [],
|
||||||
|
programMemory,
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
if (e instanceof KCLError) {
|
||||||
|
return {
|
||||||
|
errors: [e],
|
||||||
|
logs: [],
|
||||||
|
programMemory: {
|
||||||
|
root: {},
|
||||||
|
return: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(e)
|
||||||
|
return {
|
||||||
|
logs: [e],
|
||||||
|
errors: [],
|
||||||
|
programMemory: {
|
||||||
|
root: {},
|
||||||
|
return: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function lintAst({
|
||||||
|
ast,
|
||||||
|
}: {
|
||||||
|
ast: Program
|
||||||
|
}): Promise<Array<Diagnostic>> {
|
||||||
|
try {
|
||||||
|
const discovered_findings = await kclLint(ast)
|
||||||
|
return discovered_findings.map((lint) => {
|
||||||
|
return {
|
||||||
|
message: lint.finding.title,
|
||||||
|
severity: 'info',
|
||||||
|
from: lint.pos[0],
|
||||||
|
to: lint.pos[1],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e: any) {
|
||||||
|
console.log(e)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { ToolTip } from '../useStore'
|
import { ToolTip } from 'lang/langHelpers'
|
||||||
import { Selection, Selections } from 'lib/selections'
|
import { Selection, Selections } from 'lib/selections'
|
||||||
import {
|
import {
|
||||||
ArrayExpression,
|
ArrayExpression,
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
isLiteralArrayOrStatic,
|
isLiteralArrayOrStatic,
|
||||||
isNotLiteralArrayOrStatic,
|
isNotLiteralArrayOrStatic,
|
||||||
} from 'lang/std/sketchcombos'
|
} from 'lang/std/sketchcombos'
|
||||||
import { toolTips, ToolTip } from '../../useStore'
|
import { toolTips, ToolTip } from 'lang/langHelpers'
|
||||||
import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
|
import { createPipeExpression, splitPathAtPipeExpression } from '../modifyAst'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { getNodeFromPath } from 'lang/queryAst'
|
import { getNodeFromPath } from 'lang/queryAst'
|
||||||
import { ToolTip, toolTips } from '../../useStore'
|
import { ToolTip, toolTips } from 'lang/langHelpers'
|
||||||
import {
|
import {
|
||||||
Program,
|
Program,
|
||||||
VariableDeclarator,
|
VariableDeclarator,
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
ConstraintLevel,
|
ConstraintLevel,
|
||||||
getConstraintLevelFromSourceRange,
|
getConstraintLevelFromSourceRange,
|
||||||
} from './sketchcombos'
|
} from './sketchcombos'
|
||||||
import { ToolTip } from '../../useStore'
|
import { ToolTip } from 'lang/langHelpers'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
import { err } from 'lib/trap'
|
import { err } from 'lib/trap'
|
||||||
import { enginelessExecutor } from '../../lib/testHelpers'
|
import { enginelessExecutor } from '../../lib/testHelpers'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { TransformCallback, VarValues } from './stdTypes'
|
import { TransformCallback, VarValues } from './stdTypes'
|
||||||
import { toolTips, ToolTip } from '../../useStore'
|
import { ToolTip, toolTips } from 'lang/langHelpers'
|
||||||
import { Selections, Selection } from 'lib/selections'
|
import { Selections, Selection } from 'lib/selections'
|
||||||
import { cleanErrs, err } from 'lib/trap'
|
import { cleanErrs, err } from 'lib/trap'
|
||||||
import {
|
import {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ToolTip } from 'useStore'
|
import { ToolTip } from 'lang/langHelpers'
|
||||||
import {
|
import {
|
||||||
ProgramMemory,
|
ProgramMemory,
|
||||||
Path,
|
Path,
|
||||||
|
@ -5,7 +5,7 @@ import { findUniqueName } from 'lang/modifyAst'
|
|||||||
import { PrevVariable, findAllPreviousVariables } from 'lang/queryAst'
|
import { PrevVariable, findAllPreviousVariables } from 'lang/queryAst'
|
||||||
import { Value, parse } from 'lang/wasm'
|
import { Value, parse } from 'lang/wasm'
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { executeAst } from 'useStore'
|
import { executeAst } from 'lang/langHelpers'
|
||||||
import { trap } from 'lib/trap'
|
import { trap } from 'lib/trap'
|
||||||
|
|
||||||
const isValidVariableName = (name: string) =>
|
const isValidVariableName = (name: string) =>
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,5 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
import {
|
import {
|
||||||
CameraSystem,
|
CameraSystem,
|
||||||
@ -8,11 +7,10 @@ import {
|
|||||||
cameraSystems,
|
cameraSystems,
|
||||||
} from 'lib/cameraControls'
|
} from 'lib/cameraControls'
|
||||||
import { SettingsSection } from 'components/Settings/SettingsSection'
|
import { SettingsSection } from 'components/Settings/SettingsSection'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function Units() {
|
export default function Units() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.STREAMING)
|
const next = useNextClick(onboardingPaths.STREAMING)
|
||||||
const {
|
const {
|
||||||
@ -31,7 +29,7 @@ export default function Units() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SettingsSection
|
<SettingsSection
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import usePlatform from 'hooks/usePlatform'
|
import usePlatform from 'hooks/usePlatform'
|
||||||
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, kbdClasses, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function CmdK() {
|
export default function CmdK() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.USER_MENU)
|
const next = useNextClick(onboardingPaths.USER_MENU)
|
||||||
const platformName = usePlatform()
|
const platformName = usePlatform()
|
||||||
@ -16,7 +14,7 @@ export default function CmdK() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'max-w-full xl:max-w-4xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'max-w-full xl:max-w-4xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<h2 className="text-2xl font-bold">Command Bar</h2>
|
<h2 className="text-2xl font-bold">Command Bar</h2>
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
|
|
||||||
export default function OnboardingCodeEditor() {
|
export default function OnboardingCodeEditor() {
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
|
const next = useNextClick(onboardingPaths.PARAMETRIC_MODELING)
|
||||||
|
|
||||||
@ -15,7 +13,7 @@ export default function OnboardingCodeEditor() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1 overflow-y-auto">
|
<section className="flex-1 overflow-y-auto">
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { APP_NAME } from 'lib/constants'
|
import { APP_NAME } from 'lib/constants'
|
||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function Export() {
|
export default function Export() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.SKETCHING)
|
const next = useNextClick(onboardingPaths.SKETCHING)
|
||||||
|
|
||||||
@ -15,7 +13,7 @@ export default function Export() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1">
|
<section className="flex-1">
|
||||||
|
@ -6,14 +6,12 @@ import {
|
|||||||
useNextClick,
|
useNextClick,
|
||||||
} from '.'
|
} from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { bracketWidthConstantLine } from 'lib/exampleKcl'
|
import { bracketWidthConstantLine } from 'lib/exampleKcl'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function OnboardingInteractiveNumbers() {
|
export default function OnboardingInteractiveNumbers() {
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.COMMAND_K)
|
const next = useNextClick(onboardingPaths.COMMAND_K)
|
||||||
|
|
||||||
@ -22,7 +20,7 @@ export default function OnboardingInteractiveNumbers() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1 overflow-y-auto mb-6">
|
<section className="flex-1 overflow-y-auto mb-6">
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDemoCode, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { Themes, getSystemTheme } from 'lib/theme'
|
import { Themes, getSystemTheme } from 'lib/theme'
|
||||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||||
import { bracketThicknessCalculationLine } from 'lib/exampleKcl'
|
import { bracketThicknessCalculationLine } from 'lib/exampleKcl'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function OnboardingParametricModeling() {
|
export default function OnboardingParametricModeling() {
|
||||||
useDemoCode()
|
useDemoCode()
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const {
|
const {
|
||||||
settings: {
|
settings: {
|
||||||
context: {
|
context: {
|
||||||
@ -32,7 +30,7 @@ export default function OnboardingParametricModeling() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'z-10 max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1 overflow-y-auto mb-6">
|
<section className="flex-1 overflow-y-auto mb-6">
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { isTauri } from 'lib/isTauri'
|
import { isTauri } from 'lib/isTauri'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function ProjectMenu() {
|
export default function ProjectMenu() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.EXPORT)
|
const next = useNextClick(onboardingPaths.EXPORT)
|
||||||
const tauri = isTauri()
|
const tauri = isTauri()
|
||||||
@ -16,7 +14,7 @@ export default function ProjectMenu() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1">
|
<section className="flex-1">
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from 'useStore'
|
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { codeManager, kclManager } from 'lib/singletons'
|
import { codeManager, kclManager } from 'lib/singletons'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function Sketching() {
|
export default function Sketching() {
|
||||||
const buttonDownInStream = useStore((s) => s.buttonDownInStream)
|
const { context } = useModelingContext()
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.FUTURE_WORK)
|
const next = useNextClick(onboardingPaths.FUTURE_WORK)
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ export default function Sketching() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'max-w-full xl:max-w-2xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<h1 className="text-2xl font-bold">Sketching</h1>
|
<h1 className="text-2xl font-bold">Sketching</h1>
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
|
|
||||||
export default function Streaming() {
|
export default function Streaming() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.EDITOR)
|
const next = useNextClick(onboardingPaths.EDITOR)
|
||||||
|
|
||||||
@ -14,7 +12,7 @@ export default function Streaming() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'max-w-xl border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg h-[75vh] flex flex-col justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1 overflow-y-auto">
|
<section className="flex-1 overflow-y-auto">
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
import { OnboardingButtons, useDismiss, useNextClick } from '.'
|
||||||
import { onboardingPaths } from 'routes/Onboarding/paths'
|
import { onboardingPaths } from 'routes/Onboarding/paths'
|
||||||
import { useStore } from '../../useStore'
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
|
||||||
export default function UserMenu() {
|
export default function UserMenu() {
|
||||||
const { buttonDownInStream } = useStore((s) => ({
|
const { context } = useModelingContext()
|
||||||
buttonDownInStream: s.buttonDownInStream,
|
|
||||||
}))
|
|
||||||
const dismiss = useDismiss()
|
const dismiss = useDismiss()
|
||||||
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
const next = useNextClick(onboardingPaths.PROJECT_MENU)
|
||||||
const [avatarErrored, setAvatarErrored] = useState(false)
|
const [avatarErrored, setAvatarErrored] = useState(false)
|
||||||
@ -33,7 +31,7 @@ export default function UserMenu() {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
'max-w-xl flex flex-col border border-chalkboard-50 dark:border-chalkboard-80 shadow-lg justify-center bg-chalkboard-10 dark:bg-chalkboard-90 p-8 rounded' +
|
||||||
(buttonDownInStream ? '' : ' pointer-events-auto')
|
(context.store?.buttonDownInStream ? '' : ' pointer-events-auto')
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<section className="flex-1">
|
<section className="flex-1">
|
||||||
|
199
src/useStore.ts
199
src/useStore.ts
@ -1,202 +1,19 @@
|
|||||||
import { create } from 'zustand'
|
import { create } from 'zustand'
|
||||||
import { persist } from 'zustand/middleware'
|
|
||||||
import {
|
|
||||||
Program,
|
|
||||||
_executor,
|
|
||||||
ProgramMemory,
|
|
||||||
programMemoryInit,
|
|
||||||
kclLint,
|
|
||||||
} from './lang/wasm'
|
|
||||||
import { enginelessExecutor } from './lib/testHelpers'
|
|
||||||
import { EngineCommandManager } from './lang/std/engineConnection'
|
|
||||||
import { KCLError } from './lang/errors'
|
|
||||||
import { SidebarType } from 'components/ModelingSidebar/ModelingPanes'
|
|
||||||
import { Diagnostic } from '@codemirror/lint'
|
|
||||||
|
|
||||||
export type ToolTip =
|
|
||||||
| 'lineTo'
|
|
||||||
| 'line'
|
|
||||||
| 'angledLine'
|
|
||||||
| 'angledLineOfXLength'
|
|
||||||
| 'angledLineOfYLength'
|
|
||||||
| 'angledLineToX'
|
|
||||||
| 'angledLineToY'
|
|
||||||
| 'xLine'
|
|
||||||
| 'yLine'
|
|
||||||
| 'xLineTo'
|
|
||||||
| 'yLineTo'
|
|
||||||
| 'angledLineThatIntersects'
|
|
||||||
| 'tangentialArcTo'
|
|
||||||
|
|
||||||
export const toolTips = [
|
|
||||||
'sketch_line',
|
|
||||||
'move',
|
|
||||||
// original tooltips
|
|
||||||
'line',
|
|
||||||
'lineTo',
|
|
||||||
'angledLine',
|
|
||||||
'angledLineOfXLength',
|
|
||||||
'angledLineOfYLength',
|
|
||||||
'angledLineToX',
|
|
||||||
'angledLineToY',
|
|
||||||
'xLine',
|
|
||||||
'yLine',
|
|
||||||
'xLineTo',
|
|
||||||
'yLineTo',
|
|
||||||
'angledLineThatIntersects',
|
|
||||||
'tangentialArcTo',
|
|
||||||
] as any as ToolTip[]
|
|
||||||
|
|
||||||
export interface StoreState {
|
export interface StoreState {
|
||||||
mediaStream?: MediaStream
|
|
||||||
setMediaStream: (mediaStream: MediaStream) => void
|
|
||||||
isStreamReady: boolean
|
isStreamReady: boolean
|
||||||
setIsStreamReady: (isStreamReady: boolean) => void
|
setIsStreamReady: (isStreamReady: boolean) => void
|
||||||
buttonDownInStream: number | undefined
|
|
||||||
setButtonDownInStream: (buttonDownInStream: number | undefined) => void
|
|
||||||
didDragInStream: boolean
|
|
||||||
setDidDragInStream: (didDragInStream: boolean) => void
|
|
||||||
fileId: string
|
|
||||||
setFileId: (fileId: string) => void
|
|
||||||
streamDimensions: { streamWidth: number; streamHeight: number }
|
|
||||||
setStreamDimensions: (dimensions: {
|
|
||||||
streamWidth: number
|
|
||||||
streamHeight: number
|
|
||||||
}) => void
|
|
||||||
setHtmlRef: (ref: React.RefObject<HTMLDivElement>) => void
|
setHtmlRef: (ref: React.RefObject<HTMLDivElement>) => void
|
||||||
htmlRef: React.RefObject<HTMLDivElement> | null
|
htmlRef: React.RefObject<HTMLDivElement> | null
|
||||||
|
|
||||||
showHomeMenu: boolean
|
|
||||||
setHomeShowMenu: (showMenu: boolean) => void
|
|
||||||
openPanes: SidebarType[]
|
|
||||||
setOpenPanes: (panes: SidebarType[]) => void
|
|
||||||
homeMenuItems: {
|
|
||||||
name: string
|
|
||||||
path: string
|
|
||||||
}[]
|
|
||||||
setHomeMenuItems: (items: { name: string; path: string }[]) => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useStore = create<StoreState>()(
|
export const useStore = create<StoreState>()((set, get) => {
|
||||||
persist(
|
return {
|
||||||
(set, get) => {
|
setIsStreamReady: (isStreamReady) => set({ isStreamReady }),
|
||||||
return {
|
setHtmlRef: (htmlRef) => {
|
||||||
setMediaStream: (mediaStream) => set({ mediaStream }),
|
set({ htmlRef })
|
||||||
isStreamReady: false,
|
|
||||||
setIsStreamReady: (isStreamReady) => set({ isStreamReady }),
|
|
||||||
buttonDownInStream: undefined,
|
|
||||||
setButtonDownInStream: (buttonDownInStream) => {
|
|
||||||
set({ buttonDownInStream })
|
|
||||||
},
|
|
||||||
setHtmlRef: (htmlRef) => {
|
|
||||||
set({ htmlRef })
|
|
||||||
},
|
|
||||||
htmlRef: null,
|
|
||||||
didDragInStream: false,
|
|
||||||
setDidDragInStream: (didDragInStream) => {
|
|
||||||
set({ didDragInStream })
|
|
||||||
},
|
|
||||||
// For stream event handling
|
|
||||||
fileId: '',
|
|
||||||
setFileId: (fileId) => set({ fileId }),
|
|
||||||
streamDimensions: { streamWidth: 1280, streamHeight: 720 },
|
|
||||||
setStreamDimensions: (streamDimensions) => {
|
|
||||||
set({ streamDimensions })
|
|
||||||
},
|
|
||||||
|
|
||||||
// tauri specific app settings
|
|
||||||
defaultDir: {
|
|
||||||
dir: '',
|
|
||||||
},
|
|
||||||
openPanes: ['code'],
|
|
||||||
setOpenPanes: (openPanes) => set({ openPanes }),
|
|
||||||
showHomeMenu: true,
|
|
||||||
setHomeShowMenu: (showHomeMenu) => set({ showHomeMenu }),
|
|
||||||
homeMenuItems: [],
|
|
||||||
setHomeMenuItems: (homeMenuItems) => set({ homeMenuItems }),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
htmlRef: null,
|
||||||
name: 'store',
|
isStreamReady: false,
|
||||||
partialize: (state) =>
|
|
||||||
Object.fromEntries(
|
|
||||||
Object.entries(state).filter(([key]) => ['openPanes'].includes(key))
|
|
||||||
),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
export async function executeAst({
|
|
||||||
ast,
|
|
||||||
engineCommandManager,
|
|
||||||
useFakeExecutor = false,
|
|
||||||
programMemoryOverride,
|
|
||||||
}: {
|
|
||||||
ast: Program
|
|
||||||
engineCommandManager: EngineCommandManager
|
|
||||||
useFakeExecutor?: boolean
|
|
||||||
programMemoryOverride?: ProgramMemory
|
|
||||||
}): Promise<{
|
|
||||||
logs: string[]
|
|
||||||
errors: KCLError[]
|
|
||||||
programMemory: ProgramMemory
|
|
||||||
}> {
|
|
||||||
try {
|
|
||||||
if (!useFakeExecutor) {
|
|
||||||
engineCommandManager.endSession()
|
|
||||||
engineCommandManager.startNewSession()
|
|
||||||
}
|
|
||||||
const programMemory = await (useFakeExecutor
|
|
||||||
? enginelessExecutor(ast, programMemoryOverride || programMemoryInit())
|
|
||||||
: _executor(ast, programMemoryInit(), engineCommandManager, false))
|
|
||||||
|
|
||||||
await engineCommandManager.waitForAllCommands()
|
|
||||||
return {
|
|
||||||
logs: [],
|
|
||||||
errors: [],
|
|
||||||
programMemory,
|
|
||||||
}
|
|
||||||
} catch (e: any) {
|
|
||||||
if (e instanceof KCLError) {
|
|
||||||
return {
|
|
||||||
errors: [e],
|
|
||||||
logs: [],
|
|
||||||
programMemory: {
|
|
||||||
root: {},
|
|
||||||
return: null,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log(e)
|
|
||||||
return {
|
|
||||||
logs: [e],
|
|
||||||
errors: [],
|
|
||||||
programMemory: {
|
|
||||||
root: {},
|
|
||||||
return: null,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
export async function lintAst({
|
|
||||||
ast,
|
|
||||||
}: {
|
|
||||||
ast: Program
|
|
||||||
}): Promise<Array<Diagnostic>> {
|
|
||||||
try {
|
|
||||||
const discovered_findings = await kclLint(ast)
|
|
||||||
return discovered_findings.map((lint) => {
|
|
||||||
return {
|
|
||||||
message: lint.finding.title,
|
|
||||||
severity: 'info',
|
|
||||||
from: lint.pos[0],
|
|
||||||
to: lint.pos[1],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (e: any) {
|
|
||||||
console.log(e)
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user