Compare commits

...

4 Commits

Author SHA1 Message Date
cccb71fd30 Set initial window size depending on screen size (#5845)
* set initial electron window size to be almost full screen with some space left

* refine initial window size and position

* slightly larger

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-18 15:39:04 -04:00
44be072d04 Fix deep links and double clicks on second instance (#5865)
* Deep links or double clicks don't work on second instance on Windows
Fixes #5864

* A snapshot a day keeps the bugs away! 📷🐛

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-18 15:17:21 -04:00
86beb6ebf1 Improve local setup instructions (#5860)
* Fix overwrite confirmation on existing wasm-pack

* Recommend using local .env for overrides
2025-03-18 14:39:02 -04:00
6d72104faa fix unused vars and imports (#5852)
* update eslintrc, and fix most of the errors

* more

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix last one

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* A snapshot a day keeps the bugs away! 📷🐛

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-03-18 09:52:10 -07:00
64 changed files with 87 additions and 217 deletions

View File

@ -22,6 +22,13 @@
"rules": {
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-misused-promises": "error",
"@typescript-eslint/no-unused-vars": ["error", {
"varsIgnorePattern": "^_",
"argsIgnorePattern": "^_",
"ignoreRestSiblings": true,
"vars": "all",
"args": "none"
}],
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",

View File

@ -105,7 +105,7 @@ Finally, to run the web app only, run:
yarn start
```
If you're not a Zoo employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development` to make it point to production instead, then when you navigate to `localhost:3000` the easiest way to sign in is to paste `localStorage.setItem('TOKEN_PERSIST_KEY', "your-token-from-https://zoo.dev/account/api-tokens")` replacing the with a real token from https://zoo.dev/account/api-tokens of course, then navigate to localhost:3000 again. Note that navigating to `localhost:3000/signin` removes your token so you will need to set the token again.
If you're not a Zoo employee you won't be able to access the dev environment, you should copy everything from `.env.production` to `.env.development.local` to make it point to production instead, then when you navigate to `localhost:3000` the easiest way to sign in is to paste `localStorage.setItem('TOKEN_PERSIST_KEY', "your-token-from-https://zoo.dev/account/api-tokens")` replacing the with a real token from https://zoo.dev/account/api-tokens of course, then navigate to `localhost:3000` again. Note that navigating to `localhost:3000/signin` removes your token so you will need to set the token again.
### Development environment variables
@ -122,7 +122,7 @@ Third-Party Cookies".
## Desktop
To spin up the desktop app, `yarn install` and `yarn build:wasm` need to have been done before hand then
To spin up the desktop app, `yarn install` and `yarn build:wasm` need to have been done before hand then:
```
yarn tron:start
@ -130,13 +130,13 @@ yarn tron:start
This will start the application and hot-reload on changes.
Devtools can be opened with the usual Cmd-Opt-I (Mac) or Ctrl-Shift-I (Linux and Windows).
Devtools can be opened with the usual Command-Option-I (macOS) or Ctrl-Shift-I (Linux and Windows).
To package the app for your platform with electron-builder, run `yarn tronb:package:dev` (or `yarn tronb:package:prod` to point to the .env.production variables)
To package the app for your platform with electron-builder, run `yarn tronb:package:dev` (or `yarn tronb:package:prod` to point to the .env.production variables).
## Checking out commits / Bisecting
Which commands from setup are one off vs need to be run every time?
Which commands from setup are one off vs. need to be run every time?
The following will need to be run when checking out a new commit and guarantees the build is not stale:

View File

@ -100,7 +100,8 @@ test(
try {
const outputGltf = await fsp.readFile(firstFileFullPath)
return outputGltf.byteLength
} catch (e) {
} catch (error: unknown) {
void error
return 0
}
},
@ -179,7 +180,8 @@ test(
try {
const outputGltf = await fsp.readFile(secondFileFullPath)
return outputGltf.byteLength
} catch (e) {
} catch (error: unknown) {
void error
return 0
}
},

View File

@ -1197,7 +1197,7 @@ test.describe('Undo and redo do not keep history when navigating between files',
`cloned file has an incremented name and same contents`,
{ tag: '@electron' },
async ({ page, context, homePage }, testInfo) => {
const { panesOpen, createNewFile, cloneFile } = await getUtils(page, test)
const { panesOpen, cloneFile } = await getUtils(page, test)
const { dir } = await context.folderSetupFn(async (dir) => {
const finalDir = join(dir, 'testDefault')

View File

@ -3,25 +3,15 @@
import type {
BrowserContext,
ElectronApplication,
Fixtures as PlaywrightFixtures,
TestInfo,
Page,
} from '@playwright/test'
import {
_electron as electron,
PlaywrightTestArgs,
PlaywrightWorkerArgs,
} from '@playwright/test'
import { _electron as electron } from '@playwright/test'
import * as TOML from '@iarna/toml'
import {
TEST_SETTINGS_KEY,
TEST_SETTINGS_CORRUPTED,
TEST_SETTINGS,
TEST_SETTINGS_DEFAULT_THEME,
} from '../storageStates'
import { SETTINGS_FILE_NAME, PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
import { TEST_SETTINGS } from '../storageStates'
import { SETTINGS_FILE_NAME } from 'lib/constants'
import { getUtils, setup } from '../test-utils'
import fsp from 'fs/promises'
import fs from 'node:fs'
@ -31,7 +21,6 @@ import { EditorFixture } from './editorFixture'
import { ToolbarFixture } from './toolbarFixture'
import { SceneFixture } from './sceneFixture'
import { HomePageFixture } from './homePageFixture'
import { unsafeTypedKeys } from 'lib/utils'
import { DeepPartial } from 'lib/types'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
@ -278,13 +267,14 @@ export class ElectronZoo {
if (fs.existsSync(this.projectDirName)) {
await fsp.rm(this.projectDirName, { recursive: true })
}
} catch (e) {
console.error(e)
} catch (_e) {
console.error(_e)
}
try {
await fsp.mkdir(this.projectDirName)
} catch (e) {
} catch (error: unknown) {
void error
// Not a problem if it already exists.
}

View File

@ -1906,7 +1906,6 @@ extrude001 = extrude(sketch001, length = -12)
// Locators
const firstEdgeLocation = { x: 600, y: 193 }
const secondEdgeLocation = { x: 600, y: 383 }
const bodyLocation = { x: 630, y: 290 }
const [clickOnFirstEdge] = scene.makeMouseHelpers(
firstEdgeLocation.x,
firstEdgeLocation.y
@ -1919,7 +1918,6 @@ extrude001 = extrude(sketch001, length = -12)
// Colors
const edgeColorWhite: [number, number, number] = [248, 248, 248]
const edgeColorYellow: [number, number, number] = [251, 251, 40] // Mac:B=67 Ubuntu:B=12
const bodyColor: [number, number, number] = [155, 155, 155]
const chamferColor: [number, number, number] = [168, 168, 168]
const backgroundColor: [number, number, number] = [30, 30, 30]
const lowTolerance = 20

View File

@ -539,7 +539,8 @@ test.describe('Can export from electron app', () => {
try {
const outputGltf = await fsp.readFile(filepath)
return outputGltf.byteLength
} catch (e) {
} catch (error: unknown) {
void error
return 0
}
},

View File

@ -14,7 +14,8 @@ try {
// prefer env vars over secrets file
secrets[key] = process.env[key] || (value as any).replaceAll('"', '')
})
} catch (err) {
} catch (error: unknown) {
void error
// probably running in CI
console.warn(
`Error reading ${secretsPath}; environment variables will be used`

View File

@ -2626,11 +2626,6 @@ extrude003 = extrude(profile011, length = 2.5)
{ x: 834, y: -680, z: 534 },
{ x: -54, y: -476, z: 148 }
)
const camPositionForSelectingSketchOnCapProfiles = () =>
scene.moveCameraTo(
{ x: 404, y: 690, z: 38 },
{ x: 16, y: -140, z: -10 }
)
const wallSelectionOptions = [
{
title: 'select wall segment',
@ -2653,29 +2648,6 @@ extrude003 = extrude(profile011, length = 2.5)
selectClick: scene.makeMouseHelpers(836, 103)[0],
},
] as const
const capSelectionOptions = [
{
title: 'select cap segment',
selectClick: scene.makeMouseHelpers(688, 91)[0],
},
{
title: 'select cap solid 2d',
selectClick: scene.makeMouseHelpers(733, 204)[0],
},
// TODO keeps failing
// {
// title: 'select cap circle',
// selectClick: scene.makeMouseHelpers(679, 290)[0],
// },
{
title: 'select cap extrude wall',
selectClick: scene.makeMouseHelpers(649, 402)[0],
},
{
title: 'select cap extrude cap',
selectClick: scene.makeMouseHelpers(693, 408)[0],
},
] as const
const verifyWallProfilesAreDrawn = async () =>
test.step('verify wall profiles are drawn', async () => {
@ -2697,44 +2669,6 @@ extrude003 = extrude(profile011, length = 2.5)
])
})
const verifyCapProfilesAreDrawn = async () =>
test.step('verify cap profiles are drawn', async () => {
// open polygon
await scene.expectPixelColor(
TEST_COLORS.WHITE,
// TEST_COLORS.BLUE, // When entering via the circle, it's selected and therefore blue
{ x: 620, y: 58 },
15
)
// revolved profile
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 641, y: 110 },
15
)
// closed polygon
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 632, y: 200 },
15
)
// extruded profile
await scene.expectPixelColor(
TEST_COLORS.WHITE,
{ x: 628, y: 410 },
15
)
// circle
await scene.expectPixelColor(
[
TEST_COLORS.WHITE,
TEST_COLORS.BLUE, // When entering via the circle, it's selected and therefore blue
],
{ x: 681, y: 303 },
15
)
})
await test.step('select wall profiles', async () => {
for (const { title, selectClick } of wallSelectionOptions) {
await test.step(title, async () => {

View File

@ -7,12 +7,7 @@ import { spawn } from 'child_process'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import JSZip from 'jszip'
import path from 'path'
import {
IS_PLAYWRIGHT_KEY,
TEST_SETTINGS,
TEST_SETTINGS_KEY,
} from './storageStates'
import * as TOML from '@iarna/toml'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from './storageStates'
import { SceneFixture } from './fixtures/sceneFixture'
import { CmdBarFixture } from './fixtures/cmdBarFixture'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -1,4 +1,3 @@
import { MouseControlType } from '@rust/kcl-lib/bindings/MouseControlType'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
import { Themes } from 'lib/theme'

View File

@ -2,15 +2,12 @@ import {
expect,
BrowserContext,
TestInfo,
_electron as electron,
ElectronApplication,
Locator,
Page,
} from '@playwright/test'
import { test } from './zoo-test'
import { EngineCommand } from 'lang/std/artifactGraph'
import fsp from 'fs/promises'
import fsSync from 'fs'
import path from 'path'
import pixelMatch from 'pixelmatch'
import { PNG } from 'pngjs'
@ -24,14 +21,11 @@ import {
IS_PLAYWRIGHT_KEY,
} from './storageStates'
import * as TOML from '@iarna/toml'
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
import { SETTINGS_FILE_NAME } from 'lib/constants'
import { isErrorWhitelisted } from './lib/console-error-whitelist'
import { isArray } from 'lib/utils'
import { reportRejection } from 'lib/trap'
import { DeepPartial } from 'lib/types'
import { Configuration } from 'lang/wasm'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
const toNormalizedCode = (text: string) => {
return text.replace(/\s+/g, '')
@ -928,10 +922,6 @@ export async function setup(
// await page.reload()
}
let electronApp: ElectronApplication | undefined = undefined
let context: BrowserContext | undefined = undefined
let page: Page | undefined = undefined
function failOnConsoleErrors(page: Page, testInfo?: TestInfo) {
// enabled for chrome for now
if (page.context().browser()?.browserType().name() === 'chromium') {

View File

@ -4,7 +4,6 @@ import { bracket } from 'lib/exampleKcl'
import * as fsp from 'fs/promises'
import { join } from 'path'
import { FILE_EXT } from 'lib/constants'
import { UnitLength_type } from '@kittycad/lib/dist/types/src/models'
test.describe('Testing in-app sample loading', () => {
/**
@ -49,8 +48,6 @@ test.describe('Testing in-app sample loading', () => {
})
const warningText = page.getByText('Overwrite current file and units?')
const confirmButton = page.getByRole('button', { name: 'Submit command' })
const unitsToast = (unit: UnitLength_type) =>
page.getByText(`Set default unit to "${unit}" for this project`)
await test.step(`Precondition: check the initial code`, async () => {
await u.openKclCodePanel()
@ -125,8 +122,6 @@ test.describe('Testing in-app sample loading', () => {
page.getByRole('listitem').filter({
has: page.getByRole('button', { name }),
})
const unitsToast = (unit: UnitLength_type) =>
page.getByText(`Set default unit to "${unit}" for this project`)
await test.step(`Test setup`, async () => {
await page.setBodyDimensions({ width: 1200, height: 500 })

View File

@ -1386,7 +1386,8 @@ profile001 = startProfileAt([56.37, 120.33], sketch001)
page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible()
return true
} catch (_) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (_e) {
return false
}
})

View File

@ -364,7 +364,6 @@ profile003 = startProfileAt([40.16, -120.48], sketch006)
await camPosition1()
const revolve = { x: 635, y: 253 }
const parentExtrude = { x: 915, y: 133 }
const solid2d = { x: 770, y: 167 }
const individualProfile = { x: 694, y: 432 }

View File

@ -7,7 +7,7 @@ import {
createProject,
tomlToSettings,
} from './test-utils'
import { SaveSettingsPayload, SettingsLevel } from 'lib/settings/settingsTypes'
import { SettingsLevel } from 'lib/settings/settingsTypes'
import { SETTINGS_FILE_NAME, PROJECT_SETTINGS_FILE_NAME } from 'lib/constants'
import {
TEST_SETTINGS_KEY,
@ -15,7 +15,6 @@ import {
TEST_SETTINGS,
TEST_SETTINGS_DEFAULT_THEME,
} from './storageStates'
import * as TOML from '@iarna/toml'
import { DeepPartial } from 'lib/types'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
@ -1006,11 +1005,6 @@ fn cube`
page.getByText(
`Set highlight edges to "${String(value)}" as a user default`
)
const initialPath = testInfo.snapshotPath('toggle-settings-initial.png')
const initialScreenshot = await scene.streamWrapper.screenshot({
path: initialPath,
mask: [page.getByTestId('model-state-indicator')],
})
await test.step(`Toggle highlightEdges off`, async () => {
await cmdBar.openCmdBar()

View File

@ -1,6 +1,6 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { test as playwrightTestFn, ElectronApplication } from '@playwright/test'
import { test as playwrightTestFn } from '@playwright/test'
import {
fixturesBasedOnProcessEnvPlatform,
@ -8,8 +8,6 @@ import {
ElectronZoo,
} from './fixtures/fixtureSetup'
import { Settings } from '@rust/kcl-lib/bindings/Settings'
import { DeepPartial } from 'lib/types'
export { expect } from '@playwright/test'
declare module '@playwright/test' {

View File

@ -71,7 +71,7 @@
"scripts": {
"install:rust": "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none && source \"$HOME/.cargo/env\" && (cd rust && (rustup show active-toolchain || rustup toolchain install))",
"install:rust:windows": "winget install Microsoft.VisualStudio.2022.Community --silent --override \"--wait --quiet --add ProductLang En-us --add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended\" && winget install Rustlang.Rustup",
"install:wasm-pack:sh": ". $HOME/.cargo/env && curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -y",
"install:wasm-pack:sh": ". $HOME/.cargo/env && curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f",
"install:wasm-pack:cargo": "cargo install wasm-pack",
"install:tools:windows": "winget install jqlang.jq MikeFarah.yq GitHub.cli",
"start": "vite --port=3000 --host=0.0.0.0",

View File

@ -248,6 +248,7 @@ export class Ctx {
this.clientSubscriptions = []
try {
await this._client?.dispose(2000)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
// DO nothing.
}

View File

@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import { useEffect, useMemo, useRef } from 'react'
import { useHotKeyListener } from './hooks/useHotKeyListener'
import { Stream } from './components/Stream'
import { AppHeader } from './components/AppHeader'
@ -60,7 +60,6 @@ export function App() {
const projectPath = project?.path || null
const [commands] = useEngineCommands()
const [capturedCanvas, setCapturedCanvas] = useState(false)
const loaderData = useRouteLoaderData(PATHS.FILE) as IndexLoaderData
const lastCommandType = commands[commands.length - 1]?.type
@ -109,11 +108,7 @@ export function App() {
// Generate thumbnail.png when loading the app
useEffect(() => {
if (
isDesktop() &&
!capturedCanvas &&
lastCommandType === 'execution-done'
) {
if (isDesktop() && lastCommandType === 'execution-done') {
setTimeout(() => {
const projectDirectoryWithoutEndingSlash = loaderData?.project?.path
if (!projectDirectoryWithoutEndingSlash) {

View File

@ -6,7 +6,7 @@ import { useEffect, useRef, useState } from 'react'
import { trap } from 'lib/trap'
import { codeToIdSelections } from 'lib/selections'
import { codeRefFromRange } from 'lang/std/artifactGraph'
import { defaultSourceRange, SourceRange, topLevelRange } from 'lang/wasm'
import { defaultSourceRange, topLevelRange } from 'lang/wasm'
import { isArray } from 'lib/utils'
export function AstExplorer() {

View File

@ -4,7 +4,6 @@ import {
Selections,
canSubmitSelectionArg,
getSelectionCountByType,
getSelectionTypeDisplayText,
} from 'lib/selections'
import { useSelector } from '@xstate/react'
import { commandBarActor, useCommandBarState } from 'machines/commandBarMachine'

View File

@ -1,13 +1,9 @@
import { Dialog } from '@headlessui/react'
import { ActionButton } from './ActionButton'
import { useState } from 'react'
import { useSearchParams } from 'react-router-dom'
import { CREATE_FILE_URL_PARAM } from 'lib/constants'
import { useSettings } from 'machines/appMachine'
const DownloadAppBanner = () => {
const [searchParams] = useSearchParams()
const hasCreateFileParam = searchParams.has(CREATE_FILE_URL_PARAM)
const settings = useSettings()
const [isBannerDismissed, setIsBannerDismissed] = useState(
settings.app.dismissWebBanner.current

View File

@ -111,7 +111,6 @@ import { commandBarActor } from 'machines/commandBarMachine'
import { useToken } from 'machines/appMachine'
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
import { useSettings } from 'machines/appMachine'
import { isDesktop } from 'lib/isDesktop'
type MachineContext<T extends AnyStateMachine> = {
state: StateFrom<T>

View File

@ -4,12 +4,11 @@ import {
useLocation,
useNavigate,
useRouteLoaderData,
redirect,
} from 'react-router-dom'
import { PATHS } from 'lib/paths'
import { markOnce } from 'lib/performance'
import { useAuthNavigation } from 'hooks/useAuthNavigation'
import { useAuthState, useSettings } from 'machines/appMachine'
import { useSettings } from 'machines/appMachine'
import { IndexLoaderData } from 'lib/types'
import { getAppSettingsFilePath } from 'lib/desktop'
import { isDesktop } from 'lib/isDesktop'
@ -17,9 +16,7 @@ import { trap } from 'lib/trap'
import { useFileSystemWatcher } from 'hooks/useFileSystemWatcher'
import { loadAndValidateSettings } from 'lib/settings/settingsUtils'
import { settingsActor } from 'machines/appMachine'
import makeUrlPathRelative from 'lib/makeUrlPathRelative'
import { OnboardingStatus } from '@rust/kcl-lib/bindings/OnboardingStatus'
import { SnapshotFrom } from 'xstate'
export const RouteProviderContext = createContext({})
@ -35,7 +32,6 @@ export function RouteProvider({ children }: { children: ReactNode }) {
const location = useLocation()
const settings = useSettings()
const authState = useAuthState()
useEffect(() => {
// On initialization, the react-router-dom does not send a 'loading' state event.
// it sends an idle event first.

View File

@ -3,7 +3,6 @@ import { CustomIcon } from 'components/CustomIcon'
import decamelize from 'decamelize'
import Fuse from 'fuse.js'
import { interactionMap } from 'lib/settings/initialKeybindings'
import { Setting } from 'lib/settings/initialSettings'
import { SettingsLevel } from 'lib/settings/settingsTypes'
import { useSettings } from 'machines/appMachine'
import { useEffect, useMemo, useRef, useState } from 'react'

View File

@ -28,7 +28,7 @@ import { base64Decode } from 'lang/wasm'
import { sendTelemetry } from 'lib/textToCad'
import { Themes } from 'lib/theme'
import { ActionButton } from './ActionButton'
import { commandBarActor, commandBarMachine } from 'machines/commandBarMachine'
import { commandBarActor } from 'machines/commandBarMachine'
import { EventFrom } from 'xstate'
import { fileMachine } from 'machines/fileMachine'
import { reportRejection } from 'lib/trap'

View File

@ -1,5 +1,5 @@
import { useLayoutEffect, useEffect, useRef } from 'react'
import { engineCommandManager, kclManager } from 'lib/singletons'
import { engineCommandManager } from 'lib/singletons'
import { deferExecution } from 'lib/utils'
import { Themes } from 'lib/theme'
import { useModelingContext } from './useModelingContext'
@ -93,10 +93,6 @@ export function useSetupEngineManager(
engineCommandManager.settings = settings
const handleResize = deferExecution(() => {
const { width, height } = getDimensions(
streamRef?.current?.offsetWidth ?? 0,
streamRef?.current?.offsetHeight ?? 0
)
engineCommandManager.handleResize(engineCommandManager.streamDimensions)
}, 500)

View File

@ -324,6 +324,7 @@ export class KclManager {
if (this.wasmInitFailed) {
this.wasmInitFailed = false
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
this.wasmInitFailed = true
}

View File

@ -7,7 +7,6 @@ import {
sketchFromKclValue,
defaultArtifactGraph,
topLevelRange,
VariableMap,
} from './wasm'
import { enginelessExecutor } from '../lib/testHelpers'
import { KCLError } from './errors'

View File

@ -5,7 +5,6 @@ import {
assertParse,
initPromise,
Parameter,
SourceRange,
topLevelRange,
} from './wasm'
import { err } from 'lib/trap'

View File

@ -38,6 +38,7 @@ afterAll(async () => {
try {
process.chdir('..')
await fs.rm(DIR_KCL_SAMPLES, { recursive: true })
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {}
})

View File

@ -19,7 +19,6 @@ import {
BinaryExpression,
PathToNode,
SourceRange,
sketchFromKclValue,
isPathToNodeNumber,
parse,
formatNumber,
@ -75,7 +74,6 @@ import {
import { BodyItem } from '@rust/kcl-lib/bindings/BodyItem'
import { findKwArg } from './util'
import { deleteEdgeTreatment } from './modifyAst/addEdgeTreatment'
import { codeManager } from 'lib/singletons'
export function startSketchOnDefault(
node: Node<Program>,

View File

@ -13,8 +13,6 @@ import {
} from '../wasm'
import {
createCallExpressionStdLib,
createPipeSubstitution,
createObjectExpression,
createArrayExpression,
createIdentifier,
createPipeExpression,

View File

@ -5,9 +5,6 @@ import {
PathToNode,
Identifier,
topLevelRange,
PipeExpression,
CallExpression,
VariableDeclarator,
} from './wasm'
import {
findAllPreviousVariables,

View File

@ -39,7 +39,7 @@ import {
import { err, Reason } from 'lib/trap'
import { Node } from '@rust/kcl-lib/bindings/Node'
import { findKwArg } from './util'
import { codeRefFromRange, getPlaneFromArtifact } from './std/artifactGraph'
import { codeRefFromRange } from './std/artifactGraph'
import { FunctionExpression } from '@rust/kcl-lib/bindings/FunctionExpression'
import { ImportStatement } from '@rust/kcl-lib/bindings/ImportStatement'
import { KclSettingsAnnotation } from 'lib/settings/settingsTypes'
@ -595,6 +595,7 @@ export function isLinesParallelAndConstrained(
artifact: artifactGraph.get(prevSegment.__geoMeta.id),
},
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
return {
isParallelAndConstrained: false,

View File

@ -1,5 +1,3 @@
import { isDesktop } from 'lib/isDesktop'
// Polyfill window.electron fs functions as needed when in a nodejs context
// (INTENDED FOR VITEST SHINANGANS.)
if (process.env.NODE_ENV === 'test' && process.env.VITEST) {

View File

@ -19,7 +19,6 @@ import {
ARG_INDEX_FIELD,
getNodeFromPath,
getNodeFromPathCurry,
getObjExprProperty,
LABELED_ARG_FIELD,
} from 'lang/queryAst'
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
@ -629,7 +628,7 @@ export const lineTo: SketchLineHelperKw = {
},
updateArgs: ({ node, pathToNode, input }) => {
if (input.type !== 'straight-segment') return STRAIGHT_SEGMENT_ERR
const { to, from } = input
const { to } = input
const _node = { ...node }
const nodeMeta = getNodeFromPath<CallExpressionKw>(_node, pathToNode)
if (err(nodeMeta)) return nodeMeta
@ -1675,7 +1674,7 @@ export const arcTo: SketchLineHelper = {
updateArgs: ({ node, pathToNode, input }) => {
if (input.type !== 'circle-three-point-segment') return ARC_SEGMENT_ERR
const { p1, p2, p3 } = input
const { p2, p3 } = input
const _node = { ...node }
const nodeMeta = getNodeFromPath<CallExpression>(_node, pathToNode)
if (err(nodeMeta)) return nodeMeta

View File

@ -16,7 +16,7 @@ import {
} from '../wasm'
import { err } from 'lib/trap'
import { findKwArgAny } from 'lang/util'
import { ARG_END, ARG_END_ABSOLUTE, DETERMINING_ARGS } from './sketch'
import { DETERMINING_ARGS } from './sketch'
export function getSketchSegmentFromPathToNode(
sketch: Sketch,

View File

@ -26,7 +26,6 @@ import { Discovered } from '@rust/kcl-lib/bindings/Discovered'
import { KclValue } from '@rust/kcl-lib/bindings/KclValue'
import type { Program } from '@rust/kcl-lib/bindings/Program'
import { Coords2d } from './std/sketch'
import { fileSystemManager } from 'lang/std/fileSystemManager'
import { CoreDumpInfo } from '@rust/kcl-lib/bindings/CoreDumpInfo'
import { CoreDumpManager } from 'lib/coredump'
import openWindow from 'lib/openWindow'
@ -318,7 +317,7 @@ export function execStateFromRust(
): ExecState {
const artifactGraph = rustArtifactGraphToMap(execOutcome.artifactGraph)
// We haven't ported pathToNode logic to Rust yet, so we need to fill it in.
for (const [id, artifact] of artifactGraph) {
for (const [_id, artifact] of artifactGraph) {
if (!artifact) continue
if (!('codeRef' in artifact)) continue
const pathToNode = getNodePathFromSourceRange(

View File

@ -3,11 +3,7 @@ import { angleLengthInfo } from 'components/Toolbar/setAngleLength'
import { transformAstSketchLines } from 'lang/std/sketchcombos'
import { PathToNode } from 'lang/wasm'
import { StateMachineCommandSetConfig, KclCommandValue } from 'lib/commandTypes'
import {
KCL_DEFAULT_LENGTH,
KCL_DEFAULT_DEGREE,
KCL_DEFAULT_COLOR,
} from 'lib/constants'
import { KCL_DEFAULT_LENGTH, KCL_DEFAULT_DEGREE } from 'lib/constants'
import { components } from 'lib/machine-api'
import { Selections } from 'lib/selections'
import { kclManager } from 'lib/singletons'

View File

@ -8,9 +8,11 @@ import { MachineManager } from 'components/MachineManagerProvider'
import { Node } from '@rust/kcl-lib/bindings/Node'
import { Artifact } from 'lang/std/artifactGraph'
import { CommandBarContext } from 'machines/commandBarMachine'
type Icon = CustomIconName
const PLATFORMS = ['both', 'web', 'desktop'] as const
const INPUT_TYPES = [
const _PLATFORMS = ['both', 'web', 'desktop'] as const
type PLATFORM = typeof _PLATFORMS
const _INPUT_TYPES = [
'options',
'string',
'text',
@ -19,6 +21,7 @@ const INPUT_TYPES = [
'selectionMixed',
'boolean',
] as const
type INPUT_TYPE = typeof _INPUT_TYPES
export interface KclExpression {
valueAst: Expr
valueText: string
@ -31,7 +34,7 @@ export interface KclExpressionWithVariable extends KclExpression {
insertIndex: number
}
export type KclCommandValue = KclExpression | KclExpressionWithVariable
export type CommandInputType = (typeof INPUT_TYPES)[number]
export type CommandInputType = INPUT_TYPE[number]
export type StateMachineCommandSetSchema<T extends AnyStateMachine> = Partial<{
[EventType in EventFrom<T>['type']]: Record<string, any>
@ -86,7 +89,7 @@ export type Command<
displayName?: string
description?: string
icon?: Icon
hide?: (typeof PLATFORMS)[number]
hide?: PLATFORM[number]
}
export type CommandConfig<

View File

@ -1,4 +1,4 @@
import { ParseResult, VariableMap } from 'lang/wasm'
import { ParseResult } from 'lang/wasm'
import { getCalculatedKclExpressionValue } from './kclHelpers'
describe('KCL expression calculations', () => {

View File

@ -24,6 +24,7 @@ export class SafeRenderer extends Renderer {
prot = decodeURIComponent(unescape(href))
.replace(/[^\w:]/g, '')
.toLowerCase()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
return text
}

View File

@ -9,8 +9,7 @@ import {
import { updateCenterRectangleSketch } from './rectangleTool'
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
import { getNodeFromPath } from 'lang/queryAst'
import { findUniqueName } from 'lang/modifyAst'
import { err, trap } from './trap'
import { trap } from './trap'
beforeAll(async () => {
await initPromise

View File

@ -10,12 +10,7 @@ import {
createTagDeclarator,
createUnaryExpression,
} from 'lang/modifyAst'
import {
ArrayExpression,
CallExpression,
PipeExpression,
recast,
} from 'lang/wasm'
import { ArrayExpression, CallExpression, PipeExpression } from 'lang/wasm'
import { roundOff } from 'lib/utils'
import {
isCallExpression,

View File

@ -1,4 +1,4 @@
import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom'
import { LoaderFunction, redirect } from 'react-router-dom'
import { FileLoaderData, HomeLoaderData, IndexLoaderData } from './types'
import { getProjectMetaByRouteId, PATHS } from './paths'
import { isDesktop } from './isDesktop'
@ -10,13 +10,11 @@ import {
PROJECT_ENTRYPOINT,
} from 'lib/constants'
import { loadAndValidateSettings } from './settings/settingsUtils'
import makeUrlPathRelative from './makeUrlPathRelative'
import { codeManager } from 'lib/singletons'
import { fileSystemManager } from 'lang/std/fileSystemManager'
import { getProjectInfo } from './desktop'
import { normalizeLineEndings } from 'lib/codeEditor'
import { OnboardingStatus } from '@rust/kcl-lib/bindings/OnboardingStatus'
import { getSettings, settingsActor } from 'machines/appMachine'
import { settingsActor } from 'machines/appMachine'
import { waitFor } from 'xstate'
export const telemetryLoader: LoaderFunction = async ({

View File

@ -32,6 +32,7 @@ export default class RustContext {
if (this.wasmInitFailed) {
this.wasmInitFailed = false
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
this.wasmInitFailed = true
}

View File

@ -167,6 +167,7 @@ export function readLocalStorageAppSettingsFile():
try {
return parseAppSettings(stored)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
const settings = defaultAppSettings()
if (err(settings)) return settings
@ -358,7 +359,6 @@ export function clearSettingsAtLevel(
level: SettingsLevel
) {
Object.entries(allSettings).forEach(([category, settingsCategory]) => {
const categoryKey = category as keyof typeof settings
Object.entries(settingsCategory).forEach(
([_, settingValue]: [string, Setting]) => {
settingValue[level] = undefined

View File

@ -12,7 +12,6 @@ import { NavigateFunction } from 'react-router-dom'
import crossPlatformFetch from './crossPlatformFetch'
import { isDesktop } from 'lib/isDesktop'
import { Themes } from './theme'
import { commandBarMachine } from 'machines/commandBarMachine'
import { getNextFileName } from './desktopFS'
import { reportRejection } from './trap'
import { toSync } from './utils'

View File

@ -1,4 +1,4 @@
import { ActorRefFrom, assign, createActor, setup, spawnChild } from 'xstate'
import { ActorRefFrom, createActor, setup, spawnChild } from 'xstate'
import { authMachine } from './authMachine'
import { useSelector } from '@xstate/react'
import { ACTOR_IDS } from './machineConstants'
@ -11,12 +11,6 @@ const appMachineActors = {
[SETTINGS]: settingsMachine,
} as const
type AppMachineActors = {
[K in keyof typeof appMachineActors]: ActorRefFrom<
(typeof appMachineActors)[K]
>
}
const appMachine = setup({
actors: appMachineActors,
}).createMachine({

View File

@ -93,9 +93,8 @@ import {
} from 'lang/modifyAst/deleteSelection'
import { getPathsFromPlaneArtifact } from 'lang/std/artifactGraph'
import { createProfileStartHandle } from 'clientSideScene/segments'
import { DRAFT_POINT, SKETCH_LAYER } from 'clientSideScene/sceneInfra'
import { DRAFT_POINT } from 'clientSideScene/sceneInfra'
import { setAppearance } from 'lang/modifyAst/setAppearance'
import { getThemeColorForThreeJs } from 'lib/theme'
import { DRAFT_DASHED_LINE } from 'clientSideScene/sceneEntities'
export const MODELING_PERSIST_KEY = 'MODELING_PERSIST_KEY'

View File

@ -2,7 +2,6 @@ import {
AnyActorRef,
assign,
enqueueActions,
EventObject,
fromCallback,
fromPromise,
sendTo,

View File

@ -10,6 +10,7 @@ import {
nativeTheme,
desktopCapturer,
systemPreferences,
screen,
} from 'electron'
import path from 'path'
import { Issuer } from 'openid-client'
@ -58,6 +59,7 @@ console.log('Environment vars', process.env)
console.log('Parsed CLI args', args)
/// Register our application to handle all "zoo-studio:" protocols.
const singleInstanceLock = app.requestSingleInstanceLock()
if (process.defaultApp) {
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient(ZOO_STUDIO_PROTOCOL, process.execPath, [
@ -72,11 +74,8 @@ if (process.defaultApp) {
// Must be done before ready event.
// Checking against this lock is needed for Windows and Linux, see
// https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app#windows-and-linux-code
if (!IS_PLAYWRIGHT) {
const singleInstanceLock = app.requestSingleInstanceLock()
if (!singleInstanceLock) {
if (!singleInstanceLock && !IS_PLAYWRIGHT) {
app.quit()
}
} else {
registerStartupListeners()
}
@ -88,12 +87,24 @@ const createWindow = (pathToOpen?: string, reuse?: boolean): BrowserWindow => {
newWindow = mainWindow
}
if (!newWindow) {
const primaryDisplay = screen.getPrimaryDisplay()
const { width, height } = primaryDisplay.workAreaSize
const windowWidth = Math.max(500, width - 150)
const windowHeight = Math.max(400, height - 100)
const x = primaryDisplay.workArea.x + Math.floor((width - windowWidth) / 2)
const y =
primaryDisplay.workArea.y + Math.floor((height - windowHeight) / 2)
newWindow = new BrowserWindow({
autoHideMenuBar: false,
show: false,
enableLargerThanScreen: true,
width: 1800,
height: 1200,
width: windowWidth,
height: windowHeight,
x,
y,
webPreferences: {
nodeIntegration: false, // do not give the application implicit system access
contextIsolation: true, // expose system functions in preload

View File

@ -9,8 +9,8 @@ import { SettingsSection } from 'components/Settings/SettingsSection'
import { settingsActor, useSettings } from 'machines/appMachine'
export default function Units() {
const dismiss = useDismiss()
const next = useNextClick(onboardingPaths.STREAMING)
useDismiss()
useNextClick(onboardingPaths.STREAMING)
const {
modeling: { mouseControls },
} = useSettings()