Compare commits

..

7 Commits

Author SHA1 Message Date
ec4fd08a7d Update package-lock.json, unsure why 2025-07-03 09:47:26 -04:00
40388b80e7 Remove circular dependency, avoid adding 2 new ones 2025-07-03 09:47:05 -04:00
4b00d00977 Update snapshots 2025-07-03 09:47:05 -04:00
fc574fa638 Tiny CSS fix 2025-07-03 09:47:05 -04:00
0bea2bcc98 Rework top bar to not include toolbar
Closes #7679 by creating a definite top bar, and moving the toolbar
below it. Still side-steps the E2E test issue by allowing the modeling
scene extend under this top bar. I will finally address this in the next
step, which is bringing back a proper sidebar that doesn't overlay the
modeling scene.

I have a fast-follow PR coming that adds visual undo and redo buttons to
this top bar, but I wanted to keep them separate.
2025-07-03 09:47:05 -04:00
a1059d547a Fix conflict 2025-07-03 09:47:05 -04:00
e4b40f6d36 Rework top bar to not include toolbar
Closes #7679 by creating a definite top bar, and moving the toolbar
below it. Still side-steps the E2E test issue by allowing the modeling
scene extend under this top bar. I will finally address this in the next
step, which is bringing back a proper sidebar that doesn't overlay the
modeling scene.

I have a fast-follow PR coming that adds visual undo and redo buttons to
this top bar, but I wanted to keep them separate.
2025-07-03 09:47:05 -04:00
80 changed files with 318 additions and 334 deletions

View File

@ -3,17 +3,17 @@
NODE_ENV=development
DEV=true
# App
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
VITE_KITTYCAD_API_BASE_URL=https://api.dev.zoo.dev
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
VITE_KC_SITE_APP_URL=https://app.dev.zoo.dev
VITE_KC_CONNECTION_TIMEOUT_MS=5000
#VITE_WASM_URL="optional override of Wasm URL if not on default port 3000"
#VITE_KITTYCAD_API_TOKEN="required for testing, optional to skip auth in the app"
FAIL_ON_CONSOLE_ERRORS=true
#VITE_WASM_URL="optional way of overriding the wasm url, particular for unit tests which need this if you running not on the default 3000 port"
#VITE_KC_DEV_TOKEN="optional token to skip auth in the app"
#token="required token for playwright. TODO: clean up env vars in #3973"
# KCL
RUST_BACKTRACE=1
PYO3_PYTHON=/usr/local/bin/python3
#KITTYCAD_API_TOKEN=$VITE_KITTYCAD_API_TOKEN
#KITTYCAD_API_TOKEN="required token for engine testing"
FAIL_ON_CONSOLE_ERRORS=true

View File

@ -1,8 +1,6 @@
NODE_ENV=production
# App
VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands
VITE_KITTYCAD_API_BASE_URL=https://api.zoo.dev
VITE_KC_API_BASE_URL=https://api.zoo.dev
VITE_KC_SITE_BASE_URL=https://zoo.dev
VITE_KC_SITE_APP_URL=https://app.zoo.dev
VITE_KC_CONNECTION_TIMEOUT_MS=15000

View File

@ -157,7 +157,7 @@ jobs:
timeout_minutes: 5
max_attempts: 5
env:
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
@ -169,7 +169,7 @@ jobs:
if: always()
run: npm run test:snapshots -- --last-failed --update-snapshots
env:
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
@ -284,7 +284,7 @@ jobs:
timeout_minutes: 5
max_attempts: 5
env:
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
@ -410,7 +410,7 @@ jobs:
max_attempts: 9
env:
FAIL_ON_CONSOLE_ERRORS: true
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}

View File

@ -62,7 +62,7 @@ jobs:
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: xvfb-run -a npm run test:unit
env:
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- name: Check for changes
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}

View File

@ -65,7 +65,7 @@ If you're not a Zoo employee you won't be able to access the dev environment, yo
### Development environment variables
The Copilot LSP plugin in the editor requires a Zoo API token to run. In production, we authenticate this with a token via cookie in the browser and device auth token in the desktop environment, but this token is inaccessible in the dev browser version because the cookie is considered "cross-site" (from `localhost` to `zoo.dev`). There is an optional environment variable called `VITE_KITTYCAD_API_TOKEN` that you can populate with a dev token in a `.env.development.local` file to not check it into Git, which will use that token instead of other methods for the LSP service.
The Copilot LSP plugin in the editor requires a Zoo API token to run. In production, we authenticate this with a token via cookie in the browser and device auth token in the desktop environment, but this token is inaccessible in the dev browser version because the cookie is considered "cross-site" (from `localhost` to `zoo.dev`). There is an optional environment variable called `VITE_KC_DEV_TOKEN` that you can populate with a dev token in a `.env.development.local` file to not check it into Git, which will use that token instead of other methods for the LSP service.
### Developing in Chrome
@ -96,7 +96,7 @@ To package the app for your platform with electron-builder, run `npm run tronb:p
Prepare these system dependencies:
- Set `$VITE_KITTYCAD_API_TOKEN` from https://zoo.dev/account/api-tokens
- Set $token from https://zoo.dev/account/api-tokens
#### Snapshot tests (Google Chrome on Ubuntu only)

View File

@ -49,7 +49,7 @@ RUST_SOURCES := $(wildcard rust/**/*.rs)
REACT_SOURCES := $(wildcard src/*.tsx) $(wildcard src/**/*.tsx)
TYPESCRIPT_SOURCES := tsconfig.* $(wildcard src/*.ts) $(wildcard src/**/*.ts)
VITE_SOURCES := $(wildcard vite.*) $(wildcard vite/**/*.tsx) .env*
VITE_SOURCES := $(wildcard vite.*) $(wildcard vite/**/*.tsx)
.PHONY: build
build: install public/kcl_wasm_lib_bg.wasm public/kcl-samples/manifest.json .vite/build/main.js

View File

@ -1,5 +1,6 @@
import { expect, test } from '@e2e/playwright/zoo-test'
// test file is for testing auth functionality
test.describe('Authentication tests', () => {
test(
`The user can sign out and back in`,
@ -12,12 +13,22 @@ test.describe('Authentication tests', () => {
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.projectSection.waitFor()
// This is only needed as an override to test-utils' setup() for this test
await page.addInitScript(() => {
localStorage.setItem('TOKEN_PERSIST_KEY', '')
})
await test.step('Click on sign out and expect sign in page', async () => {
await toolbar.userSidebarButton.click()
await toolbar.signOutButton.click()
await expect(signInPage.signInButton).toBeVisible()
})
await test.step("Refresh doesn't log the user back in", async () => {
await page.reload()
await expect(signInPage.signInButton).toBeVisible()
})
await test.step('Click on sign in and cancel, click again and expect different code', async () => {
await signInPage.signInButton.click()
await expect(signInPage.userCode).toBeVisible()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 47 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: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -17,7 +17,7 @@ import dotenv from 'dotenv'
const NODE_ENV = process.env.NODE_ENV || 'development'
dotenv.config({ path: [`.env.${NODE_ENV}.local`, `.env.${NODE_ENV}`] })
export const token = process.env.VITE_KITTYCAD_API_TOKEN || ''
export const token = process.env.token || ''
import type { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'

5
interface.d.ts vendored
View File

@ -73,12 +73,13 @@ export interface IElectronAPI {
process: {
env: {
IS_PLAYWRIGHT: string
VITE_KITTYCAD_API_TOKEN: string
VITE_KC_DEV_TOKEN: string
VITE_KC_API_WS_MODELING_URL: string
VITE_KITTYCAD_API_BASE_URL: string
VITE_KC_API_BASE_URL: string
VITE_KC_SITE_BASE_URL: string
VITE_KC_SITE_APP_URL: string
VITE_KC_CONNECTION_TIMEOUT_MS: string
VITE_KC_DEV_TOKEN: string
NODE_ENV: string
PROD: string
DEV: string

221
package-lock.json generated
View File

@ -149,7 +149,7 @@
"ts-node": "^10.0.0",
"typescript": "^5.8.3",
"typescript-eslint": "^8.30.1",
"vite": "^5.4.19",
"vite": "^5.4.18",
"vite-plugin-package-version": "^1.1.0",
"vite-plugin-top-level-await": "^1.5.0",
"vite-tsconfig-paths": "^4.3.2",
@ -3652,9 +3652,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz",
"integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz",
"integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==",
"cpu": [
"ppc64"
],
@ -3668,9 +3668,9 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz",
"integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz",
"integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==",
"cpu": [
"arm"
],
@ -3684,9 +3684,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz",
"integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz",
"integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==",
"cpu": [
"arm64"
],
@ -3700,9 +3700,9 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz",
"integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz",
"integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==",
"cpu": [
"x64"
],
@ -3716,9 +3716,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz",
"integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz",
"integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==",
"cpu": [
"arm64"
],
@ -3732,9 +3732,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz",
"integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz",
"integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==",
"cpu": [
"x64"
],
@ -3748,9 +3748,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz",
"integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz",
"integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==",
"cpu": [
"arm64"
],
@ -3764,9 +3764,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz",
"integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz",
"integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==",
"cpu": [
"x64"
],
@ -3780,9 +3780,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz",
"integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz",
"integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==",
"cpu": [
"arm"
],
@ -3796,9 +3796,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz",
"integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz",
"integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==",
"cpu": [
"arm64"
],
@ -3812,9 +3812,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz",
"integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz",
"integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==",
"cpu": [
"ia32"
],
@ -3828,9 +3828,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz",
"integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz",
"integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==",
"cpu": [
"loong64"
],
@ -3844,9 +3844,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz",
"integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz",
"integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==",
"cpu": [
"mips64el"
],
@ -3860,9 +3860,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz",
"integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz",
"integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==",
"cpu": [
"ppc64"
],
@ -3876,9 +3876,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz",
"integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz",
"integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==",
"cpu": [
"riscv64"
],
@ -3892,9 +3892,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz",
"integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz",
"integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==",
"cpu": [
"s390x"
],
@ -3908,9 +3908,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz",
"integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz",
"integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==",
"cpu": [
"x64"
],
@ -3924,9 +3924,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz",
"integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz",
"integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==",
"cpu": [
"arm64"
],
@ -3940,9 +3940,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz",
"integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz",
"integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==",
"cpu": [
"x64"
],
@ -3956,9 +3956,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz",
"integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz",
"integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==",
"cpu": [
"arm64"
],
@ -3972,9 +3972,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz",
"integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz",
"integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==",
"cpu": [
"x64"
],
@ -3988,9 +3988,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz",
"integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz",
"integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==",
"cpu": [
"x64"
],
@ -4004,9 +4004,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz",
"integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz",
"integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==",
"cpu": [
"arm64"
],
@ -4020,9 +4020,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz",
"integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz",
"integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==",
"cpu": [
"ia32"
],
@ -4036,9 +4036,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz",
"integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz",
"integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==",
"cpu": [
"x64"
],
@ -13219,9 +13219,9 @@
"optional": true
},
"node_modules/esbuild": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz",
"integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==",
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz",
"integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==",
"dev": true,
"hasInstallScript": true,
"bin": {
@ -13231,31 +13231,31 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.25.4",
"@esbuild/android-arm": "0.25.4",
"@esbuild/android-arm64": "0.25.4",
"@esbuild/android-x64": "0.25.4",
"@esbuild/darwin-arm64": "0.25.4",
"@esbuild/darwin-x64": "0.25.4",
"@esbuild/freebsd-arm64": "0.25.4",
"@esbuild/freebsd-x64": "0.25.4",
"@esbuild/linux-arm": "0.25.4",
"@esbuild/linux-arm64": "0.25.4",
"@esbuild/linux-ia32": "0.25.4",
"@esbuild/linux-loong64": "0.25.4",
"@esbuild/linux-mips64el": "0.25.4",
"@esbuild/linux-ppc64": "0.25.4",
"@esbuild/linux-riscv64": "0.25.4",
"@esbuild/linux-s390x": "0.25.4",
"@esbuild/linux-x64": "0.25.4",
"@esbuild/netbsd-arm64": "0.25.4",
"@esbuild/netbsd-x64": "0.25.4",
"@esbuild/openbsd-arm64": "0.25.4",
"@esbuild/openbsd-x64": "0.25.4",
"@esbuild/sunos-x64": "0.25.4",
"@esbuild/win32-arm64": "0.25.4",
"@esbuild/win32-ia32": "0.25.4",
"@esbuild/win32-x64": "0.25.4"
"@esbuild/aix-ppc64": "0.25.3",
"@esbuild/android-arm": "0.25.3",
"@esbuild/android-arm64": "0.25.3",
"@esbuild/android-x64": "0.25.3",
"@esbuild/darwin-arm64": "0.25.3",
"@esbuild/darwin-x64": "0.25.3",
"@esbuild/freebsd-arm64": "0.25.3",
"@esbuild/freebsd-x64": "0.25.3",
"@esbuild/linux-arm": "0.25.3",
"@esbuild/linux-arm64": "0.25.3",
"@esbuild/linux-ia32": "0.25.3",
"@esbuild/linux-loong64": "0.25.3",
"@esbuild/linux-mips64el": "0.25.3",
"@esbuild/linux-ppc64": "0.25.3",
"@esbuild/linux-riscv64": "0.25.3",
"@esbuild/linux-s390x": "0.25.3",
"@esbuild/linux-x64": "0.25.3",
"@esbuild/netbsd-arm64": "0.25.3",
"@esbuild/netbsd-x64": "0.25.3",
"@esbuild/openbsd-arm64": "0.25.3",
"@esbuild/openbsd-x64": "0.25.3",
"@esbuild/sunos-x64": "0.25.3",
"@esbuild/win32-arm64": "0.25.3",
"@esbuild/win32-ia32": "0.25.3",
"@esbuild/win32-x64": "0.25.3"
}
},
"node_modules/escalade": {
@ -25132,10 +25132,11 @@
"optional": true
},
"node_modules/vite": {
"version": "5.4.19",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz",
"integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==",
"version": "5.4.18",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz",
"integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
@ -26648,6 +26649,7 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.10.tgz",
"integrity": "sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.8.0"
}
@ -26656,7 +26658,8 @@
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
"dev": true
"dev": true,
"license": "MIT"
},
"rust/kcl-language-server": {
"version": "0.0.0",
@ -26675,7 +26678,7 @@
"@vscode/test-electron": "^2.4.1",
"@vscode/vsce": "^3.3.2",
"cross-env": "^7.0.3",
"esbuild": "^0.25.4",
"esbuild": "^0.25.3",
"glob": "^11.0.1",
"mocha": "^11.1.0",
"typescript": "^5.8.3"

View File

@ -227,7 +227,7 @@
"ts-node": "^10.0.0",
"typescript": "^5.8.3",
"typescript-eslint": "^8.30.1",
"vite": "^5.4.19",
"vite": "^5.4.18",
"vite-plugin-package-version": "^1.1.0",
"vite-plugin-top-level-await": "^1.5.0",
"vite-tsconfig-paths": "^4.3.2",

View File

@ -123,7 +123,7 @@
"@vscode/test-electron": "^2.4.1",
"@vscode/vsce": "^3.3.2",
"cross-env": "^7.0.3",
"esbuild": "^0.25.4",
"esbuild": "^0.25.3",
"glob": "^11.0.1",
"mocha": "^11.1.0",
"typescript": "^5.8.3"

View File

@ -10,4 +10,3 @@
5) src/lang/std/sketch.ts -> src/lang/modifyAst.ts -> src/lang/std/sketchcombos.ts
6) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts -> src/components/Toolbar/angleLengthInfo.ts
7) src/lib/singletons.ts -> src/clientSideScene/sceneEntities.ts -> src/clientSideScene/segments.ts
8) src/hooks/useModelingContext.ts -> src/components/ModelingMachineProvider.tsx -> src/components/Toolbar/setAngleLength.tsx -> src/components/SetAngleLengthModal.tsx -> src/lib/useCalculateKclExpression.ts

View File

@ -4,8 +4,6 @@
URL STATUS
000 https://${BASE_URL}
405 https://api.dev.zoo.dev/oauth2/token/revoke
401 https://api.dev.zoo.dev/users
301 https://discord.gg/JQEpHR7Nt2
404 https://github.com/KittyCAD/engine/issues/3528
404 https://github.com/KittyCAD/modeling-app/commit/${ref}

View File

@ -65,6 +65,7 @@ import { useModelingContext } from '@src/hooks/useModelingContext'
import { xStateValueToString } from '@src/lib/xStateValueToString'
import { getSelectionTypeDisplayText } from '@src/lib/selections'
import type { StatusBarItemType } from '@src/components/StatusBar/statusBarTypes'
import { Toolbar } from '@src/Toolbar'
// CYCLIC REF
sceneInfra.camControls.engineStreamActor = engineStreamActor
@ -246,15 +247,18 @@ export function App() {
return (
<div className="h-screen flex flex-col overflow-hidden select-none">
<div className="relative flex flex-1 flex-col">
<AppHeader
className="transition-opacity transition-duration-75"
project={{ project, file }}
enableMenu={true}
nativeFileMenuCreated={nativeFileMenuCreated}
>
<CommandBarOpenButton />
<ShareButton />
</AppHeader>
<div className="relative flex items-center flex-col">
<AppHeader
className="transition-opacity transition-duration-75"
project={{ project, file }}
enableMenu={true}
nativeFileMenuCreated={nativeFileMenuCreated}
>
<CommandBarOpenButton />
<ShareButton />
</AppHeader>
<Toolbar />
</div>
<ModalContainer />
<ModelingSidebar />
<EngineStream pool={pool} authToken={authToken} />

View File

@ -203,7 +203,7 @@ export function Toolbar({
<menu
data-current-mode={currentMode}
data-onboarding-id="toolbar"
className="max-w-full whitespace-nowrap rounded-b px-2 py-1 bg-chalkboard-10 dark:bg-chalkboard-90 relative border border-chalkboard-30 dark:border-chalkboard-80 border-t-0 shadow-sm"
className="z-[19] max-w-full whitespace-nowrap rounded-b px-2 py-1 bg-chalkboard-10 dark:bg-chalkboard-90 relative border border-chalkboard-30 dark:border-chalkboard-80 border-t-0 shadow-sm"
>
<ul
{...props}

View File

@ -3,7 +3,6 @@
in Tailwind, such as complex grid layouts.
*/
.header {
grid-template-columns: 1fr auto 1fr;
user-select: none;
-webkit-user-select: none;
}

View File

@ -1,30 +1,30 @@
import { Toolbar } from '@src/Toolbar'
import { CommandBarOpenButton } from '@src/components/CommandBarOpenButton'
import ProjectSidebarMenu from '@src/components/ProjectSidebarMenu'
import UserSidebarMenu from '@src/components/UserSidebarMenu'
import { isDesktop } from '@src/lib/isDesktop'
import { type IndexLoaderData } from '@src/lib/types'
import type { IndexLoaderData } from '@src/lib/types'
import { useUser } from '@src/lib/singletons'
import styles from './AppHeader.module.css'
import type { ReactNode } from 'react'
interface AppHeaderProps extends React.PropsWithChildren {
showToolbar?: boolean
project?: Omit<IndexLoaderData, 'code'>
className?: string
enableMenu?: boolean
style?: React.CSSProperties
nativeFileMenuCreated: boolean
projectMenuChildren?: ReactNode
}
export const AppHeader = ({
showToolbar = true,
project,
children,
className = '',
style,
enableMenu = false,
nativeFileMenuCreated,
projectMenuChildren,
}: AppHeaderProps) => {
const user = useUser()
@ -32,14 +32,9 @@ export const AppHeader = ({
<header
id="app-header"
data-testid="app-header"
className={
'w-full grid ' +
styles.header +
` ${
isDesktop() ? styles.desktopApp + ' ' : ''
}overlaid-panes sticky top-0 z-20 px-2 items-start ` +
className
}
className={`w-full flex ${styles.header || ''} ${
isDesktop() ? styles.desktopApp : ''
} overlaid-panes sticky top-0 z-20 px-2 justify-between ${className || ''} bg-chalkboard-10 dark:bg-chalkboard-90 border-b border-chalkboard-30 dark:border-chalkboard-70`}
data-native-file-menu={nativeFileMenuCreated}
style={style}
>
@ -47,13 +42,9 @@ export const AppHeader = ({
enableMenu={enableMenu}
project={project?.project}
file={project?.file}
/>
{/* Toolbar if the context deems it */}
<div className="flex flex-col items-center gap-2">
<div className="flex-grow flex justify-center max-w-lg md:max-w-xl lg:max-w-2xl xl:max-w-4xl 2xl:max-w-5xl">
{showToolbar && <Toolbar />}
</div>
</div>
>
{projectMenuChildren}
</ProjectSidebarMenu>
<div className="flex items-center gap-2 py-1 ml-auto">
{/* If there are children, show them, otherwise show User menu */}
{children || <CommandBarOpenButton />}

View File

@ -33,6 +33,7 @@ import { useSettings } from '@src/lib/singletons'
import { commandBarActor, useCommandBarState } from '@src/lib/singletons'
import styles from './CommandBarKclInput.module.css'
import { useModelingContext } from '@src/hooks/useModelingContext'
// TODO: remove the need for this selector once we decouple all actors from React
const machineContextSelector = (snapshot?: SnapshotFrom<AnyStateMachine>) =>
@ -55,6 +56,9 @@ function CommandBarKclInput({
arg.name
] as KclCommandValue | undefined
const settings = useSettings()
const {
context: { selectionRanges },
} = useModelingContext()
const argMachineContext = useSelector(
arg.machineActor,
machineContextSelector
@ -126,6 +130,7 @@ function CommandBarKclInput({
value,
initialVariableName,
sourceRange: sourceRangeForPrevVariables,
selectionRanges,
})
const varMentionData: Completion[] = prevVariables.map((v) => {

View File

@ -10,13 +10,13 @@ export function CommandBarOpenButton() {
return (
<button
type="button"
className="flex gap-1 items-center py-0 px-0.5 m-0 text-primary dark:text-inherit bg-chalkboard-10/80 dark:bg-chalkboard-100/50 hover:bg-chalkboard-10 dark:hover:bg-chalkboard-100 border border-solid border-primary/50 hover:border-primary active:border-primary"
className="flex gap-1 items-center py-0 pl-0.5 pr-1 sm:pr-0.5 m-0 text-primary dark:text-inherit bg-chalkboard-10/80 dark:bg-chalkboard-100/50 hover:bg-chalkboard-10 dark:hover:bg-chalkboard-100 border border-solid border-primary/50 hover:border-primary active:border-primary"
onClick={() => commandBarActor.send({ type: 'Open' })}
data-testid="command-bar-open-button"
>
<CustomIcon name="command" className="w-5 h-5" />
<span>Commands</span>
<kbd className="dark:bg-chalkboard-80 font-mono rounded-sm text-primary/70 dark:text-inherit inline-block px-1">
<kbd className="hidden sm:block dark:bg-chalkboard-80 font-mono rounded-sm text-primary/70 dark:text-inherit inline-block px-1">
{hotkeyDisplay(COMMAND_PALETTE_HOTKEY, platform)}
</kbd>
</button>

View File

@ -7,7 +7,7 @@ import {
LanguageServerClient,
LspWorkerEventType,
} from '@kittycad/codemirror-lsp-client'
import { TEST } from '@src/env'
import { TEST, VITE_KC_API_BASE_URL } from '@src/env'
import React, { createContext, useContext, useMemo, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import type * as LSP from 'vscode-languageserver-protocol'
@ -28,7 +28,6 @@ import type { FileEntry } from '@src/lib/project'
import { codeManager } from '@src/lib/singletons'
import { err } from '@src/lib/trap'
import { useToken } from '@src/lib/singletons'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
return []
@ -86,7 +85,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const initEvent: KclWorkerOptions = {
wasmUrl: wasmUrl(),
token: token,
apiBaseUrl: withAPIBaseURL(''),
apiBaseUrl: VITE_KC_API_BASE_URL,
}
lspWorker.postMessage({
worker: LspWorker.Kcl,
@ -179,7 +178,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const initEvent: CopilotWorkerOptions = {
wasmUrl: wasmUrl(),
token: token,
apiBaseUrl: withAPIBaseURL(''),
apiBaseUrl: VITE_KC_API_BASE_URL,
}
lspWorker.postMessage({
worker: LspWorker.Copilot,

View File

@ -17,40 +17,39 @@ import { APP_NAME } from '@src/lib/constants'
import { isDesktop } from '@src/lib/isDesktop'
import { PATHS } from '@src/lib/paths'
import { engineCommandManager, kclManager } from '@src/lib/singletons'
import { type IndexLoaderData } from '@src/lib/types'
import type { IndexLoaderData } from '@src/lib/types'
import { commandBarActor } from '@src/lib/singletons'
interface ProjectSidebarMenuProps extends React.PropsWithChildren {
enableMenu?: boolean
project?: IndexLoaderData['project']
file?: IndexLoaderData['file']
}
const ProjectSidebarMenu = ({
project,
file,
enableMenu = false,
}: {
enableMenu?: boolean
project?: IndexLoaderData['project']
file?: IndexLoaderData['file']
}) => {
children,
}: ProjectSidebarMenuProps) => {
// Make room for traffic lights on desktop left side.
// TODO: make sure this doesn't look like shit on Linux or Windows
const trafficLightsOffset =
isDesktop() && window.electron.os.isMac ? 'ml-20' : ''
return (
<div
className={
'!no-underline h-full mr-auto max-h-min min-h-12 min-w-max flex items-center gap-2 ' +
trafficLightsOffset
}
>
<div className={'!no-underline flex gap-2 ' + trafficLightsOffset}>
<AppLogoLink project={project} file={file} />
{enableMenu ? (
<ProjectMenuPopover project={project} file={file} />
) : (
<span
className="hidden select-none cursor-default text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
className="hidden self-center px-2 select-none cursor-default text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
data-testid="project-name"
>
{project?.name ? project.name : APP_NAME}
</span>
)}
{children}
</div>
)
}
@ -64,7 +63,7 @@ function AppLogoLink({
}) {
const { onProjectClose } = useLspContext()
const wrapperClassName =
"relative h-full grid place-content-center group p-1.5 before:block before:content-[''] before:absolute before:inset-0 before:bottom-2.5 before:z-[-1] before:bg-primary before:rounded-b-sm"
"relative h-full grid flex-none place-content-center group p-1.5 before:block before:content-[''] before:absolute before:inset-0 before:bottom-1 before:z-[-1] before:bg-primary before:rounded-b-sm"
const logoClassName = 'w-auto h-4 text-chalkboard-10'
return isDesktop() ? (
@ -238,12 +237,23 @@ function ProjectMenuPopover({
return (
<Popover className="relative">
<Popover.Button
className="gap-1 rounded-sm h-9 mr-auto max-h-min min-w-max border-0 py-1 px-2 flex items-center focus-visible:outline-appForeground dark:hover:bg-chalkboard-90"
className="gap-1 rounded-sm mr-auto max-h-min min-w-max border-0 py-1 px-2 flex items-center focus-visible:outline-appForeground dark:hover:bg-chalkboard-90"
data-testid="project-sidebar-toggle"
>
<div className="flex flex-col items-start py-0.5">
<div className="flex items-baseline py-0.5 text-sm gap-1">
{isDesktop() && project?.name && (
<>
<span
className="hidden whitespace-nowrap md:block"
data-testid="app-header-project-name"
>
{project.name}
</span>
<span className="hidden md:block">/</span>
</>
)}
<span
className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"
className="text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap"
data-testid="app-header-file-name"
>
{isDesktop() && file?.name
@ -252,14 +262,6 @@ function ProjectMenuPopover({
)
: APP_NAME}
</span>
{isDesktop() && project?.name && (
<span
className="hidden text-xs text-chalkboard-70 dark:text-chalkboard-40 whitespace-nowrap lg:block"
data-testid="app-header-project-name"
>
{project.name}
</span>
)}
</div>
<CustomIcon
name="caretDown"

View File

@ -10,6 +10,7 @@ import {
} from '@src/components/AvailableVarsHelpers'
import type { Expr } from '@src/lang/wasm'
import { useCalculateKclExpression } from '@src/lib/useCalculateKclExpression'
import type { Selections } from '@src/lib/selections'
type ModalResolve = {
value: string
@ -25,6 +26,7 @@ type SetAngleLengthModalProps = InstanceProps<ModalResolve, ModalReject> & {
value: number
valueName: string
shouldCreateVariable?: boolean
selectionRanges: Selections
}
export const createSetAngleLengthModal = create<
@ -40,6 +42,7 @@ export const SetAngleLengthModal = ({
value: initialValue,
valueName,
shouldCreateVariable: initialShouldCreateVariable = false,
selectionRanges,
}: SetAngleLengthModalProps) => {
const [sign, setSign] = useState(Math.sign(Number(initialValue)))
const [value, setValue] = useState(String(initialValue * sign))
@ -59,6 +62,7 @@ export const SetAngleLengthModal = ({
} = useCalculateKclExpression({
value,
initialVariableName: valueName,
selectionRanges,
})
return (

View File

@ -10,6 +10,7 @@ import {
} from '@src/components/AvailableVarsHelpers'
import type { Expr } from '@src/lang/wasm'
import { useCalculateKclExpression } from '@src/lib/useCalculateKclExpression'
import type { Selections } from '@src/lib/selections'
type ModalResolve = {
value: string
@ -27,6 +28,7 @@ type GetInfoModalProps = InstanceProps<ModalResolve, ModalReject> & {
isSegNameEditable: boolean
value?: number
initialVariableName: string
selectionRanges: Selections
}
export const createInfoModal = create<
@ -43,6 +45,7 @@ export const GetInfoModal = ({
isSegNameEditable,
value: initialValue,
initialVariableName,
selectionRanges,
}: GetInfoModalProps) => {
const [sign, setSign] = useState(Math.sign(Number(initialValue)))
const [segName, setSegName] = useState(initialSegName)
@ -60,7 +63,11 @@ export const GetInfoModal = ({
newVariableName,
isNewVariableNameUnique,
newVariableInsertIndex,
} = useCalculateKclExpression({ value: value, initialVariableName })
} = useCalculateKclExpression({
value: value,
initialVariableName,
selectionRanges,
})
return (
<Transition appear show={isOpen} as={Fragment}>

View File

@ -6,11 +6,13 @@ import { type InstanceProps, create } from 'react-modal-promise'
import { ActionButton } from '@src/components/ActionButton'
import { CreateNewVariable } from '@src/components/AvailableVarsHelpers'
import { useCalculateKclExpression } from '@src/lib/useCalculateKclExpression'
import type { Selections } from '@src/lib/selections'
type ModalResolve = { variableName: string }
type ModalReject = boolean
type SetVarNameModalProps = InstanceProps<ModalResolve, ModalReject> & {
valueName: string
selectionRanges: Selections
}
export const createSetVarNameModal = create<
@ -24,9 +26,14 @@ export const SetVarNameModal = ({
onResolve,
onReject,
valueName,
selectionRanges,
}: SetVarNameModalProps) => {
const { isNewVariableNameUnique, newVariableName, setNewVariableName } =
useCalculateKclExpression({ value: '', initialVariableName: valueName })
useCalculateKclExpression({
value: '',
initialVariableName: valueName,
selectionRanges,
})
return (
<Transition appear show={isOpen} as={Fragment}>

View File

@ -83,7 +83,7 @@ export const ShareButton = memo(function ShareButton() {
billingContext.tier === undefined
return (
<Popover className="relative flex">
<Popover className="relative hidden sm:flex">
<Popover.Button
as="div"
className="relative group border-0 w-fit min-w-max p-0 rounded-l-full focus-visible:outline-appForeground"

View File

@ -1,5 +1,4 @@
import type { Node } from '@rust/kcl-lib/bindings/Node'
import { removeDoubleNegatives } from '@src/components/AvailableVarsHelpers'
import {
GetInfoModal,
@ -167,6 +166,7 @@ export async function applyConstraintIntersect({
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: 'offset',
selectionRanges,
})
if (
!variableName &&

View File

@ -113,6 +113,7 @@ export async function applyConstraintAbsDistance({
await getModalInfo({
value: forceVal,
valueName: constraint === 'yAbs' ? 'yDis' : 'xDis',
selectionRanges,
})
if (!isExprBinaryPart(valueNode))
return Promise.reject('Invalid valueNode, is not a BinaryPart')

View File

@ -117,7 +117,8 @@ export async function applyConstraintAngleBetween({
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: 'angle',
} as any)
selectionRanges,
})
if (
segName === tagInfo?.tag &&
Number(value) === valueUsedInTransform &&

View File

@ -123,7 +123,8 @@ export async function applyConstraintHorzVertDistance({
isSegNameEditable: !tagInfo?.isTagExisting,
value: valueUsedInTransform,
initialVariableName: constraint === 'setHorzDistance' ? 'xDis' : 'yDis',
} as any)
selectionRanges,
})
if (
!variableName &&
segName === tagInfo?.tag &&

View File

@ -143,6 +143,7 @@ export async function applyConstraintAngleLength({
value: forceVal,
valueName: angleOrLength === 'setAngle' ? 'angle' : 'length',
shouldCreateVariable: true,
selectionRanges,
})
if (!isExprBinaryPart(valueNode))
return Promise.reject('Invalid valueNode, is not a BinaryPart')

View File

@ -178,9 +178,9 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
}
return (
<Popover className="relative">
<Popover className="relative grid">
<Popover.Button
className="relative group border-0 w-fit min-w-max p-0 rounded-l-full focus-visible:outline-appForeground"
className="m-0 relative group border-0 w-fit min-w-max p-0 rounded-l-full rounded-r focus-visible:outline-appForeground"
data-testid="user-sidebar-toggle"
>
<div className="flex items-center">

View File

@ -8,14 +8,12 @@ export const NODE_ENV = env.NODE_ENV as string | undefined
export const VITE_KC_API_WS_MODELING_URL = env.VITE_KC_API_WS_MODELING_URL as
| string
| undefined
export const VITE_KITTYCAD_API_BASE_URL = env.VITE_KITTYCAD_API_BASE_URL
export const VITE_KC_API_BASE_URL = env.VITE_KC_API_BASE_URL
export const VITE_KC_SITE_BASE_URL = env.VITE_KC_SITE_BASE_URL
export const VITE_KC_SITE_APP_URL = env.VITE_KC_SITE_APP_URL
export const VITE_KC_CONNECTION_TIMEOUT_MS =
env.VITE_KC_CONNECTION_TIMEOUT_MS as string | undefined
export const VITE_KITTYCAD_API_TOKEN = env.VITE_KITTYCAD_API_TOKEN as
| string
| undefined
export const VITE_KC_DEV_TOKEN = env.VITE_KC_DEV_TOKEN as string | undefined
export const PROD = env.PROD as string | undefined
export const TEST = env.TEST as string | undefined
export const DEV = env.DEV as string | undefined

View File

@ -52,6 +52,7 @@ export function useConvertToVariable(range?: SourceRange) {
try {
const { variableName } = await getVarNameModal({
valueName: valueName || 'var',
selectionRanges: context.selectionRanges,
})
const { modifiedAst: _modifiedAst, pathToReplacedNode } =

View File

@ -1,4 +1,4 @@
import { VITE_KITTYCAD_API_TOKEN } from '@src/env'
import { VITE_KC_DEV_TOKEN } from '@src/env'
import { createLiteral } from '@src/lang/create'
import type {
@ -40,9 +40,10 @@ import { isOverlap } from '@src/lib/utils'
beforeAll(async () => {
await initPromise
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
await new Promise((resolve) => {
engineCommandManager.start({
token: VITE_KITTYCAD_API_TOKEN,
token: VITE_KC_DEV_TOKEN,
width: 256,
height: 256,
setMediaStream: () => {},

View File

@ -4,15 +4,16 @@ import { initPromise } from '@src/lang/wasmUtils'
import { err } from '@src/lib/trap'
import type { Selection } from '@src/lib/selections'
import { engineCommandManager, kclManager } from '@src/lib/singletons'
import { VITE_KITTYCAD_API_TOKEN } from '@src/env'
import { VITE_KC_DEV_TOKEN } from '@src/env'
import { modifyAstWithTagsForSelection } from '@src/lang/modifyAst/tagManagement'
beforeAll(async () => {
await initPromise
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
await new Promise((resolve) => {
engineCommandManager.start({
token: VITE_KITTYCAD_API_TOKEN,
token: VITE_KC_DEV_TOKEN,
width: 256,
height: 256,
setMediaStream: () => {},

View File

@ -1,5 +1,5 @@
import type { Models } from '@kittycad/lib'
import { VITE_KC_API_WS_MODELING_URL, VITE_KITTYCAD_API_TOKEN } from '@src/env'
import { VITE_KC_API_WS_MODELING_URL, VITE_KC_DEV_TOKEN } from '@src/env'
import { jsAppSettings } from '@src/lib/settings/settingsUtils'
import { BSON } from 'bson'
@ -400,7 +400,7 @@ class EngineConnection extends EventTarget {
this.send({
type: 'headers',
headers: {
Authorization: `Bearer ${VITE_KITTYCAD_API_TOKEN}`,
Authorization: `Bearer ${VITE_KC_DEV_TOKEN}`,
},
})
}

View File

@ -1,3 +1,4 @@
import { VITE_KC_API_BASE_URL } from '@src/env'
import { UAParser } from 'ua-parser-js'
import type { OsInfo } from '@rust/kcl-lib/bindings/OsInfo'
@ -10,7 +11,6 @@ import { isDesktop } from '@src/lib/isDesktop'
import type RustContext from '@src/lib/rustContext'
import screenshot from '@src/lib/screenshot'
import { APP_VERSION } from '@src/routes/utils'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
/* eslint-disable suggest-no-throw/suggest-no-throw --
* All the throws in CoreDumpManager are intentional and should be caught and handled properly
@ -35,7 +35,7 @@ export class CoreDumpManager {
codeManager: CodeManager
rustContext: RustContext
token: string | undefined
baseUrl: string = withAPIBaseURL('')
baseUrl: string = VITE_KC_API_BASE_URL
constructor(
engineCommandManager: EngineCommandManager,

View File

@ -26,7 +26,6 @@ import { err } from '@src/lib/trap'
import type { DeepPartial } from '@src/lib/types'
import { getInVariableCase } from '@src/lib/utils'
import { IS_STAGING } from '@src/routes/utils'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
export async function renameProjectDirectory(
projectPath: string,
@ -698,9 +697,7 @@ export const readTokenFile = async () => {
export const writeTokenFile = async (token: string) => {
const tokenFilePath = await getTokenFilePath()
if (err(token)) return Promise.reject(token)
const result = window.electron.writeFile(tokenFilePath, token)
console.log('token written to disk')
return result
return window.electron.writeFile(tokenFilePath, token)
}
export const writeTelemetryFile = async (content: string) => {
@ -725,9 +722,12 @@ export const setState = async (state: Project | undefined): Promise<void> => {
appStateStore = state
}
export const getUser = async (token: string): Promise<Models['User_type']> => {
export const getUser = async (
token: string,
hostname: string
): Promise<Models['User_type']> => {
try {
const user = await fetch(withAPIBaseURL('/users/me'), {
const user = await fetch(`${hostname}/users/me`, {
headers: new Headers({
Authorization: `Bearer ${token}`,
}),

View File

@ -1,4 +1,4 @@
import { VITE_KC_SITE_APP_URL } from '@src/env'
import { VITE_KC_API_BASE_URL, VITE_KC_SITE_APP_URL } from '@src/env'
import toast from 'react-hot-toast'
import { stringToBase64 } from '@src/lib/base64'
@ -7,7 +7,6 @@ import {
CREATE_FILE_URL_PARAM,
} from '@src/lib/constants'
import { err } from '@src/lib/trap'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
export interface FileLinkParams {
code: string
@ -97,7 +96,7 @@ export async function createShortlink(
if (password) {
body.password = password
}
const response = await fetch(withAPIBaseURL('/user/shortlinks'), {
const response = await fetch(`${VITE_KC_API_BASE_URL}/user/shortlinks`, {
method: 'POST',
headers: {
'Content-type': 'application/json',

View File

@ -1,7 +1,7 @@
import type { SelectionRange } from '@codemirror/state'
import { EditorSelection, Transaction } from '@codemirror/state'
import type { Models } from '@kittycad/lib'
import { VITE_KC_SITE_BASE_URL } from '@src/env'
import { VITE_KC_API_BASE_URL, VITE_KC_SITE_BASE_URL } from '@src/env'
import { diffLines } from 'diff'
import toast from 'react-hot-toast'
import type { TextToCadMultiFileIteration_type } from '@kittycad/lib/dist/types/src/models'
@ -28,7 +28,6 @@ import { uuidv4 } from '@src/lib/utils'
import type { File as KittyCadLibFile } from '@kittycad/lib/dist/types/src/models'
import type { FileMeta } from '@src/lib/types'
import type { RequestedKCLFile } from '@src/machines/systemIO/utils'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
type KclFileMetaMap = {
[execStateFileNamesIndex: number]: Extract<FileMeta, { type: 'kcl' }>
@ -78,7 +77,7 @@ async function submitTextToCadRequest(
})
const response = await fetch(
withAPIBaseURL('/ml/text-to-cad/multi-file/iteration'),
`${VITE_KC_API_BASE_URL}/ml/text-to-cad/multi-file/iteration`,
{
method: 'POST',
headers: {
@ -305,7 +304,7 @@ export async function getPromptToEditResult(
id: string,
token?: string
): Promise<Models['TextToCadMultiFileIteration_type'] | Error> {
const url = withAPIBaseURL(`/async/operations/${id}`)
const url = VITE_KC_API_BASE_URL + '/async/operations/' + id
const data: Models['TextToCadMultiFileIteration_type'] | Error =
await crossPlatformFetch(
url,
@ -336,6 +335,14 @@ export async function doPromptEdit({
const toastId = toast.loading('Submitting to Text-to-CAD API...')
let submitResult
// work around for @kittycad/lib not really being built for the browser
;(window as any).process = {
env: {
ZOO_API_TOKEN: token,
ZOO_HOST: VITE_KC_API_BASE_URL,
},
}
try {
submitResult = await submitPromptToEditToQueue({
prompt,

View File

@ -1,4 +1,4 @@
import { withAPIBaseURL } from '@src/lib/withBaseURL'
import { VITE_KC_API_BASE_URL } from '@src/env'
import EditorManager from '@src/editor/manager'
import { KclManager } from '@src/lang/KclSingleton'
@ -171,7 +171,7 @@ const appMachine = setup({
systemId: BILLING,
input: {
...BILLING_CONTEXT_DEFAULTS,
urlUserService: withAPIBaseURL(''),
urlUserService: VITE_KC_API_BASE_URL,
},
}),
],

View File

@ -1,4 +1,5 @@
import type { Models } from '@kittycad/lib'
import { VITE_KC_API_BASE_URL } from '@src/env'
import toast from 'react-hot-toast'
import type { NavigateFunction } from 'react-router-dom'
import {
@ -18,7 +19,6 @@ import { err, reportRejection } from '@src/lib/trap'
import { toSync } from '@src/lib/utils'
import { getAllSubDirectoriesAtProjectRoot } from '@src/machines/systemIO/snapshotContext'
import { joinOSPaths } from '@src/lib/paths'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
export async function submitTextToCadPrompt(
prompt: string,
@ -32,7 +32,7 @@ export async function submitTextToCadPrompt(
kcl_version: kclManager.kclVersion,
}
// Glb has a smaller footprint than gltf, should we want to render it.
const url = withAPIBaseURL('/ai/text-to-cad/glb?kcl=true')
const url = VITE_KC_API_BASE_URL + '/ai/text-to-cad/glb?kcl=true'
const data: Models['TextToCad_type'] | Error = await crossPlatformFetch(
url,
{
@ -58,7 +58,7 @@ export async function getTextToCadResult(
id: string,
token?: string
): Promise<Models['TextToCad_type'] | Error> {
const url = withAPIBaseURL(`/user/text-to-cad/${id}`)
const url = VITE_KC_API_BASE_URL + '/user/text-to-cad/' + id
const data: Models['TextToCad_type'] | Error = await crossPlatformFetch(
url,
{

View File

@ -1,13 +1,14 @@
import type { Models } from '@kittycad/lib/dist/types/src'
import { VITE_KC_API_BASE_URL } from '@src/env'
import crossPlatformFetch from '@src/lib/crossPlatformFetch'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
export async function sendTelemetry(
id: string,
feedback: Models['MlFeedback_type'],
token?: string
): Promise<void> {
const url = withAPIBaseURL(`/user/text-to-cad/${id}?feedback=${feedback}`)
const url =
VITE_KC_API_BASE_URL + '/user/text-to-cad/' + id + '?feedback=' + feedback
await crossPlatformFetch(
url,
{

View File

@ -1,6 +1,4 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useModelingContext } from '@src/hooks/useModelingContext'
import { useKclContext } from '@src/lang/KclProvider'
import { findUniqueName } from '@src/lang/create'
import type { PrevVariable } from '@src/lang/queryAst'
@ -12,6 +10,7 @@ import { getCalculatedKclExpressionValue } from '@src/lib/kclHelpers'
import { kclManager } from '@src/lib/singletons'
import { err } from '@src/lib/trap'
import { getInVariableCase } from '@src/lib/utils'
import type { Selections } from '@src/lib/selections'
const isValidVariableName = (name: string) =>
/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)
@ -25,10 +24,12 @@ export function useCalculateKclExpression({
value,
initialVariableName: valueName = '',
sourceRange,
selectionRanges,
}: {
value: string
initialVariableName?: string
sourceRange?: SourceRange
selectionRanges: Selections
}): {
inputRef: React.RefObject<HTMLInputElement>
valueNode: Expr | null
@ -45,12 +46,10 @@ export function useCalculateKclExpression({
// has completed
const [isExecuting, setIsExecuting] = useState(false)
const { variables, code } = useKclContext()
const { context } = useModelingContext()
// If there is no selection, use the end of the code
// so all variables are available
const selectionRange:
| (typeof context)['selectionRanges']['graphSelections'][number]['codeRef']['range']
| undefined = context.selectionRanges.graphSelections[0]?.codeRef?.range
const selectionRange: SourceRange | undefined =
selectionRanges.graphSelections[0]?.codeRef?.range
// If there is no selection, use the end of the code
// If we don't memoize this, we risk an infinite set/read state loop
const endingSourceRange = useMemo(

View File

@ -1,34 +0,0 @@
import { withAPIBaseURL } from '@src/lib/withBaseURL'
describe('withBaseURL', () => {
/**
* running in the development environment
* the .env.development should load
*/
describe('withAPIBaseUrl', () => {
it('should return base url', () => {
const expected = 'https://api.dev.zoo.dev'
const actual = withAPIBaseURL('')
expect(actual).toBe(expected)
})
it('should return base url with /users', () => {
const expected = 'https://api.dev.zoo.dev/users'
const actual = withAPIBaseURL('/users')
expect(actual).toBe(expected)
})
it('should return a longer base url with /oauth2/token/revoke', () => {
const expected = 'https://api.dev.zoo.dev/oauth2/token/revoke'
const actual = withAPIBaseURL('/oauth2/token/revoke')
expect(actual).toBe(expected)
})
it('should ensure base url does not have ending slash', () => {
const expected = 'https://api.dev.zoo.dev'
const actual = withAPIBaseURL('')
expect(actual).toBe(expected)
const expectedEndsWith = expected[expected.length - 1]
const actualEndsWith = actual[actual.length - 1]
expect(actual).toBe(expected)
expect(actualEndsWith).toBe(expectedEndsWith)
})
})
})

View File

@ -1,5 +1,5 @@
import { VITE_KITTYCAD_API_BASE_URL } from '@src/env'
import { VITE_KC_API_BASE_URL } from '@src/env'
export function withAPIBaseURL(path: string): string {
return VITE_KITTYCAD_API_BASE_URL + path
export default function withBaseUrl(path: string): string {
return VITE_KC_API_BASE_URL + path
}

View File

@ -1,5 +1,5 @@
import type { Models } from '@kittycad/lib'
import { VITE_KITTYCAD_API_TOKEN } from '@src/env'
import { VITE_KC_API_BASE_URL, VITE_KC_DEV_TOKEN } from '@src/env'
import { assign, fromPromise, setup } from 'xstate'
import { COOKIE_NAME, OAUTH2_DEVICE_CLIENT_ID } from '@src/lib/constants'
@ -10,7 +10,10 @@ import {
} from '@src/lib/desktop'
import { isDesktop } from '@src/lib/isDesktop'
import { markOnce } from '@src/lib/performance'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
import {
default as withBaseURL,
default as withBaseUrl,
} from '@src/lib/withBaseURL'
import { ACTOR_IDS } from '@src/machines/machineConstants'
export interface UserContext {
@ -28,21 +31,11 @@ export type Events =
}
export const TOKEN_PERSIST_KEY = 'TOKEN_PERSIST_KEY'
/**
* Determine which token do we have persisted to initialize the auth machine
*/
const persistedCookie = getCookie(COOKIE_NAME)
const persistedLocalStorage = localStorage?.getItem(TOKEN_PERSIST_KEY) || ''
const persistedDevToken = VITE_KITTYCAD_API_TOKEN
export const persistedToken =
persistedDevToken || persistedCookie || persistedLocalStorage
console.log('Initial persisted token')
console.table([
['cookie', !!persistedCookie],
['local storage', !!persistedLocalStorage],
['api token', !!persistedDevToken],
])
VITE_KC_DEV_TOKEN ||
getCookie(COOKIE_NAME) ||
localStorage?.getItem(TOKEN_PERSIST_KEY) ||
''
export const authMachine = setup({
types: {} as {
@ -139,7 +132,7 @@ export const authMachine = setup({
async function getUser(input: { token?: string }) {
const token = await getAndSyncStoredToken(input)
const url = withAPIBaseURL('/user')
const url = withBaseURL('/user')
const headers: { [key: string]: string } = {
'Content-Type': 'application/json',
}
@ -148,7 +141,7 @@ async function getUser(input: { token?: string }) {
if (token) headers['Authorization'] = `Bearer ${token}`
const userPromise = isDesktop()
? getUserDesktop(token)
? getUserDesktop(token, VITE_KC_API_BASE_URL)
: fetch(url, {
method: 'GET',
credentials: 'include',
@ -197,28 +190,16 @@ async function getAndSyncStoredToken(input: {
token?: string
}): Promise<string> {
// dev mode
if (VITE_KITTYCAD_API_TOKEN) {
console.log('Token used for authentication')
console.table([['api token', !!VITE_KITTYCAD_API_TOKEN]])
return VITE_KITTYCAD_API_TOKEN
}
if (VITE_KC_DEV_TOKEN) return VITE_KC_DEV_TOKEN
const inputToken = input.token && input.token !== '' ? input.token : ''
const cookieToken = getCookie(COOKIE_NAME)
const localStorageToken = localStorage?.getItem(TOKEN_PERSIST_KEY) || ''
const token = inputToken || cookieToken || localStorageToken
console.log('Token used for authentication')
console.table([
['persisted token', !!inputToken],
['cookie', !!cookieToken],
['local storage', !!localStorageToken],
['api token', !!VITE_KITTYCAD_API_TOKEN],
])
const token =
input.token && input.token !== ''
? input.token
: getCookie(COOKIE_NAME) || localStorage?.getItem(TOKEN_PERSIST_KEY) || ''
if (token) {
// has just logged in, update storage
localStorage.setItem(TOKEN_PERSIST_KEY, token)
if (isDesktop()) {
// has just logged in, update storage
localStorage.setItem(TOKEN_PERSIST_KEY, token)
await writeTokenFile(token)
}
return token
@ -240,7 +221,7 @@ async function logout() {
if (token) {
try {
await fetch(withAPIBaseURL('/oauth2/token/revoke'), {
await fetch(withBaseUrl('/oauth2/token/revoke'), {
method: 'POST',
credentials: 'include',
headers: {
@ -263,7 +244,7 @@ async function logout() {
}
}
return fetch(withAPIBaseURL('/logout'), {
return fetch(withBaseUrl('/logout'), {
method: 'POST',
credentials: 'include',
})

View File

@ -11,7 +11,7 @@ import {
engineCommandManager,
kclManager,
} from '@src/lib/singletons'
import { VITE_KITTYCAD_API_TOKEN } from '@src/env'
import { VITE_KC_DEV_TOKEN } from '@src/env'
import { getConstraintInfoKw } from '@src/lang/std/sketch'
import { getNodeFromPath } from '@src/lang/queryAst'
import type { Node } from '@rust/kcl-lib/bindings/Node'
@ -29,9 +29,10 @@ import { removeSingleConstraintInfo } from '@src/lang/modifyAst'
beforeAll(async () => {
await initPromise
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
await new Promise((resolve) => {
engineCommandManager.start({
token: VITE_KITTYCAD_API_TOKEN,
token: VITE_KC_DEV_TOKEN,
width: 256,
height: 256,
setMediaStream: () => {},

View File

@ -29,7 +29,6 @@ import {
applyConstraintHorzVert,
horzVertInfo,
} from '@src/components/Toolbar/HorzVert'
import { intersectInfo } from '@src/components/Toolbar/Intersect'
import {
applyRemoveConstrainingValues,
removeConstrainingValuesInfo,
@ -155,6 +154,7 @@ import type { Plane } from '@rust/kcl-lib/bindings/Plane'
import type { Point3d } from '@rust/kcl-lib/bindings/ModelingCmd'
import { getNodePathFromSourceRange } from '@src/lang/queryAstNodePathUtils'
import { letEngineAnimateAndSyncCamAfter } from '@src/clientSideScene/CameraControls'
import { intersectInfo } from '@src/components/Toolbar/Intersect'
export type SetSelections =
| {

View File

@ -1,5 +1,5 @@
import { engineCommandManager, kclManager } from '@src/lib/singletons'
import { VITE_KITTYCAD_API_TOKEN } from '@src/env'
import { VITE_KC_DEV_TOKEN } from '@src/env'
import { getModuleIdByFileName, isArray } from '@src/lib/utils'
import { vi, inject } from 'vitest'
import { assertParse } from '@src/lang/wasm'
@ -355,9 +355,10 @@ cases.push(
beforeAll(async () => {
await initPromise
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
await new Promise((resolve) => {
engineCommandManager.start({
token: VITE_KITTYCAD_API_TOKEN,
token: VITE_KC_DEV_TOKEN,
width: 256,
height: 256,
setMediaStream: () => {},

View File

@ -71,7 +71,7 @@ dotenv.config({ path: [`.env.${NODE_ENV}.local`, `.env.${NODE_ENV}`] })
// default vite values based on mode
process.env.NODE_ENV ??= viteEnv.MODE
process.env.VITE_KC_API_WS_MODELING_URL ??= viteEnv.VITE_KC_API_WS_MODELING_URL
process.env.VITE_KITTYCAD_API_BASE_URL ??= viteEnv.VITE_KITTYCAD_API_BASE_URL
process.env.VITE_KC_API_BASE_URL ??= viteEnv.VITE_KC_API_BASE_URL
process.env.VITE_KC_SITE_BASE_URL ??= viteEnv.VITE_KC_SITE_BASE_URL
process.env.VITE_KC_SITE_APP_URL ??= viteEnv.VITE_KC_SITE_APP_URL
process.env.VITE_KC_CONNECTION_TIMEOUT_MS ??=

View File

@ -289,11 +289,11 @@ contextBridge.exposeInMainWorld('electron', {
exposeProcessEnvs([
'NODE_ENV',
'VITE_KC_API_WS_MODELING_URL',
'VITE_KITTYCAD_API_BASE_URL',
'VITE_KC_API_BASE_URL',
'VITE_KC_SITE_BASE_URL',
'VITE_KC_SITE_APP_URL',
'VITE_KC_CONNECTION_TIMEOUT_MS',
'VITE_KITTYCAD_API_TOKEN',
'VITE_KC_DEV_TOKEN',
'IS_PLAYWRIGHT',

View File

@ -221,10 +221,7 @@ const Home = () => {
return (
<div className="relative flex flex-col items-stretch h-screen w-screen overflow-hidden">
<AppHeader
nativeFileMenuCreated={nativeFileMenuCreated}
showToolbar={false}
/>
<AppHeader nativeFileMenuCreated={nativeFileMenuCreated} />
<div className="overflow-hidden self-stretch w-full flex-1 home-layout max-w-4xl lg:max-w-5xl xl:max-w-7xl px-4 mx-auto mt-8 lg:mt-24 lg:px-0">
<HomeHeader
setQuery={setQuery}

View File

@ -6,7 +6,7 @@ import { Link } from 'react-router-dom'
import { ActionButton } from '@src/components/ActionButton'
import { CustomIcon } from '@src/components/CustomIcon'
import { Logo } from '@src/components/Logo'
import { VITE_KC_SITE_BASE_URL } from '@src/env'
import { VITE_KC_API_BASE_URL, VITE_KC_SITE_BASE_URL } from '@src/env'
import { APP_NAME } from '@src/lib/constants'
import { isDesktop } from '@src/lib/isDesktop'
import { openExternalBrowserIfDesktop } from '@src/lib/openWindow'
@ -15,7 +15,6 @@ import { reportRejection } from '@src/lib/trap'
import { toSync } from '@src/lib/utils'
import { authActor, useSettings } from '@src/lib/singletons'
import { APP_VERSION, generateSignInUrl } from '@src/routes/utils'
import { withAPIBaseURL } from '@src/lib/withBaseURL'
const subtleBorder =
'border border-solid border-chalkboard-30 dark:border-chalkboard-80'
@ -55,7 +54,7 @@ const SignIn = () => {
const signInDesktop = async () => {
// We want to invoke our command to login via device auth.
const userCodeToDisplay = await window.electron
.startDeviceFlow(withAPIBaseURL(location.search))
.startDeviceFlow(VITE_KC_API_BASE_URL + location.search)
.catch(reportError)
if (!userCodeToDisplay) {
console.error('No user code received while trying to log in')