Compare commits
34 Commits
jtran/plus
...
nadro/adho
Author | SHA1 | Date | |
---|---|---|---|
ac938e1f23 | |||
bf9dd893f1 | |||
03a13fd741 | |||
d567de1e5f | |||
66970d674d | |||
07d899e884 | |||
86e6590f4d | |||
340c503633 | |||
7abc119993 | |||
34494f3bba | |||
4102249bd8 | |||
df6256266c | |||
e5d082f441 | |||
d4d3e179b1 | |||
3929f2e9fb | |||
bab98ab5c9 | |||
8dc1b156ff | |||
693fd8eb31 | |||
14a72344e2 | |||
e5d1cd847d | |||
01d294a8bb | |||
aa460d631d | |||
23e609443b | |||
d3aa09a20b | |||
eba91e85ea | |||
74f6e338f7 | |||
529c619fb5 | |||
195000b50c | |||
7993b5f4e8 | |||
fb8acbefe7 | |||
8f2a2391d1 | |||
4f4c44e7c7 | |||
e2247669f0 | |||
1b75020686 |
@ -3,18 +3,17 @@
|
|||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
DEV=true
|
DEV=true
|
||||||
|
|
||||||
|
# App
|
||||||
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
|
VITE_KC_API_WS_MODELING_URL=wss://api.dev.zoo.dev/ws/modeling/commands
|
||||||
VITE_KC_API_BASE_URL=https://api.dev.zoo.dev
|
VITE_KITTYCAD_API_BASE_URL=https://api.dev.zoo.dev
|
||||||
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
|
VITE_KC_SITE_BASE_URL=https://dev.zoo.dev
|
||||||
VITE_KC_SITE_APP_URL=https://app.dev.zoo.dev
|
VITE_KC_SITE_APP_URL=https://app.dev.zoo.dev
|
||||||
VITE_KC_SKIP_AUTH=false
|
|
||||||
VITE_KC_CONNECTION_TIMEOUT_MS=5000
|
VITE_KC_CONNECTION_TIMEOUT_MS=5000
|
||||||
#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_WASM_URL="optional override of Wasm URL if not on default port 3000"
|
||||||
#VITE_KC_DEV_TOKEN="optional token to skip auth in the app"
|
#VITE_KITTYCAD_API_TOKEN="required for testing, optional to skip auth in the app"
|
||||||
#token="required token for playwright. TODO: clean up env vars in #3973"
|
FAIL_ON_CONSOLE_ERRORS=true
|
||||||
|
|
||||||
|
# KCL
|
||||||
RUST_BACKTRACE=1
|
RUST_BACKTRACE=1
|
||||||
PYO3_PYTHON=/usr/local/bin/python3
|
PYO3_PYTHON=/usr/local/bin/python3
|
||||||
#KITTYCAD_API_TOKEN="required token for engine testing"
|
#KITTYCAD_API_TOKEN=$VITE_KITTYCAD_API_TOKEN
|
||||||
|
|
||||||
FAIL_ON_CONSOLE_ERRORS=true
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
NODE_ENV=production
|
NODE_ENV=production
|
||||||
|
|
||||||
|
# App
|
||||||
VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands
|
VITE_KC_API_WS_MODELING_URL=wss://api.zoo.dev/ws/modeling/commands
|
||||||
VITE_KC_API_BASE_URL=https://api.zoo.dev
|
VITE_KITTYCAD_API_BASE_URL=https://api.zoo.dev
|
||||||
VITE_KC_SITE_BASE_URL=https://zoo.dev
|
VITE_KC_SITE_BASE_URL=https://zoo.dev
|
||||||
VITE_KC_SITE_APP_URL=https://app.zoo.dev
|
VITE_KC_SITE_APP_URL=https://app.zoo.dev
|
||||||
VITE_KC_SKIP_AUTH=false
|
|
||||||
VITE_KC_CONNECTION_TIMEOUT_MS=15000
|
VITE_KC_CONNECTION_TIMEOUT_MS=15000
|
||||||
|
8
.github/workflows/e2e-tests.yml
vendored
8
.github/workflows/e2e-tests.yml
vendored
@ -157,7 +157,7 @@ jobs:
|
|||||||
timeout_minutes: 5
|
timeout_minutes: 5
|
||||||
max_attempts: 5
|
max_attempts: 5
|
||||||
env:
|
env:
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||||
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
||||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
@ -169,7 +169,7 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
run: npm run test:snapshots -- --last-failed --update-snapshots
|
run: npm run test:snapshots -- --last-failed --update-snapshots
|
||||||
env:
|
env:
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||||
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
||||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
@ -284,7 +284,7 @@ jobs:
|
|||||||
timeout_minutes: 5
|
timeout_minutes: 5
|
||||||
max_attempts: 5
|
max_attempts: 5
|
||||||
env:
|
env:
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||||
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
||||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
@ -410,7 +410,7 @@ jobs:
|
|||||||
max_attempts: 9
|
max_attempts: 9
|
||||||
env:
|
env:
|
||||||
FAIL_ON_CONSOLE_ERRORS: true
|
FAIL_ON_CONSOLE_ERRORS: true
|
||||||
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||||
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
TAB_API_URL: ${{ secrets.TAB_API_URL }}
|
||||||
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
|
||||||
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
|
2
.github/workflows/unit-tests.yml
vendored
2
.github/workflows/unit-tests.yml
vendored
@ -62,7 +62,7 @@ jobs:
|
|||||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||||
run: xvfb-run -a npm run test:unit
|
run: xvfb-run -a npm run test:unit
|
||||||
env:
|
env:
|
||||||
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
VITE_KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
|
||||||
|
|
||||||
- name: Check for changes
|
- name: Check for changes
|
||||||
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
|
||||||
|
@ -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
|
### 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_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.
|
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.
|
||||||
|
|
||||||
### Developing in Chrome
|
### 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:
|
Prepare these system dependencies:
|
||||||
|
|
||||||
- Set $token from https://zoo.dev/account/api-tokens
|
- Set `$VITE_KITTYCAD_API_TOKEN` from https://zoo.dev/account/api-tokens
|
||||||
|
|
||||||
#### Snapshot tests (Google Chrome on Ubuntu only)
|
#### Snapshot tests (Google Chrome on Ubuntu only)
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ If the application needs to overwrite the known file on disk use this pattern. T
|
|||||||
- `npm run circular-deps:overwrite`
|
- `npm run circular-deps:overwrite`
|
||||||
- `npm run url-checker:overwrite`
|
- `npm run url-checker:overwrite`
|
||||||
|
|
||||||
#### Diff baseline and current
|
#### Diff baseline and current
|
||||||
|
|
||||||
These commands will write a /tmp/ file on disk and compare it to the known file in the repository. This command will also be used in the CI CD pipeline for automated checks
|
These commands will write a /tmp/ file on disk and compare it to the known file in the repository. This command will also be used in the CI CD pipeline for automated checks
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { expect, test } from '@e2e/playwright/zoo-test'
|
import { expect, test } from '@e2e/playwright/zoo-test'
|
||||||
|
|
||||||
// test file is for testing auth functionality
|
|
||||||
test.describe('Authentication tests', () => {
|
test.describe('Authentication tests', () => {
|
||||||
test(
|
test(
|
||||||
`The user can sign out and back in`,
|
`The user can sign out and back in`,
|
||||||
@ -13,22 +12,12 @@ test.describe('Authentication tests', () => {
|
|||||||
await page.setBodyDimensions({ width: 1000, height: 500 })
|
await page.setBodyDimensions({ width: 1000, height: 500 })
|
||||||
await homePage.projectSection.waitFor()
|
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 test.step('Click on sign out and expect sign in page', async () => {
|
||||||
await toolbar.userSidebarButton.click()
|
await toolbar.userSidebarButton.click()
|
||||||
await toolbar.signOutButton.click()
|
await toolbar.signOutButton.click()
|
||||||
await expect(signInPage.signInButton).toBeVisible()
|
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 test.step('Click on sign in and cancel, click again and expect different code', async () => {
|
||||||
await signInPage.signInButton.click()
|
await signInPage.signInButton.click()
|
||||||
await expect(signInPage.userCode).toBeVisible()
|
await expect(signInPage.userCode).toBeVisible()
|
||||||
|
@ -17,7 +17,7 @@ import dotenv from 'dotenv'
|
|||||||
|
|
||||||
const NODE_ENV = process.env.NODE_ENV || 'development'
|
const NODE_ENV = process.env.NODE_ENV || 'development'
|
||||||
dotenv.config({ path: [`.env.${NODE_ENV}.local`, `.env.${NODE_ENV}`] })
|
dotenv.config({ path: [`.env.${NODE_ENV}.local`, `.env.${NODE_ENV}`] })
|
||||||
export const token = process.env.token || ''
|
export const token = process.env.VITE_KITTYCAD_API_TOKEN || ''
|
||||||
|
|
||||||
import type { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
|
import type { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
|
||||||
|
|
||||||
|
7
interface.d.ts
vendored
7
interface.d.ts
vendored
@ -72,16 +72,13 @@ export interface IElectronAPI {
|
|||||||
}
|
}
|
||||||
process: {
|
process: {
|
||||||
env: {
|
env: {
|
||||||
BASE_URL: string
|
|
||||||
IS_PLAYWRIGHT: string
|
IS_PLAYWRIGHT: string
|
||||||
VITE_KC_DEV_TOKEN: string
|
VITE_KITTYCAD_API_TOKEN: string
|
||||||
VITE_KC_API_WS_MODELING_URL: string
|
VITE_KC_API_WS_MODELING_URL: string
|
||||||
VITE_KC_API_BASE_URL: string
|
VITE_KITTYCAD_API_BASE_URL: string
|
||||||
VITE_KC_SITE_BASE_URL: string
|
VITE_KC_SITE_BASE_URL: string
|
||||||
VITE_KC_SITE_APP_URL: string
|
VITE_KC_SITE_APP_URL: string
|
||||||
VITE_KC_SKIP_AUTH: string
|
|
||||||
VITE_KC_CONNECTION_TIMEOUT_MS: string
|
VITE_KC_CONNECTION_TIMEOUT_MS: string
|
||||||
VITE_KC_DEV_TOKEN: string
|
|
||||||
NODE_ENV: string
|
NODE_ENV: string
|
||||||
PROD: string
|
PROD: string
|
||||||
DEV: string
|
DEV: string
|
||||||
|
@ -10,71 +10,76 @@ DATA;
|
|||||||
NAMED_UNIT(*)
|
NAMED_UNIT(*)
|
||||||
SI_UNIT($, .METRE.)
|
SI_UNIT($, .METRE.)
|
||||||
);
|
);
|
||||||
#2 = UNCERTAINTY_MEASURE_WITH_UNIT(0.00001, #1, 'DISTANCE_ACCURACY_VALUE', $);
|
#2 = (
|
||||||
#3 = (
|
NAMED_UNIT(*)
|
||||||
|
PLANE_ANGLE_UNIT()
|
||||||
|
SI_UNIT($, .RADIAN.)
|
||||||
|
);
|
||||||
|
#3 = UNCERTAINTY_MEASURE_WITH_UNIT(0.00001, #1, 'DISTANCE_ACCURACY_VALUE', $);
|
||||||
|
#4 = (
|
||||||
GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
GEOMETRIC_REPRESENTATION_CONTEXT(3)
|
||||||
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#2))
|
GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#3))
|
||||||
GLOBAL_UNIT_ASSIGNED_CONTEXT((#1))
|
GLOBAL_UNIT_ASSIGNED_CONTEXT((#1, #2))
|
||||||
REPRESENTATION_CONTEXT('', '3D')
|
REPRESENTATION_CONTEXT('', '3D')
|
||||||
);
|
);
|
||||||
#4 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
|
#5 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
|
||||||
#5 = VERTEX_POINT('NONE', #4);
|
#6 = VERTEX_POINT('NONE', #5);
|
||||||
#6 = CARTESIAN_POINT('NONE', (0.015, 0, -0.005));
|
#7 = CARTESIAN_POINT('NONE', (0.015, 0, -0.005));
|
||||||
#7 = VERTEX_POINT('NONE', #6);
|
#8 = VERTEX_POINT('NONE', #7);
|
||||||
#8 = DIRECTION('NONE', (1, 0, -0));
|
#9 = DIRECTION('NONE', (1, 0, -0));
|
||||||
#9 = DIRECTION('NONE', (0, 1, 0));
|
#10 = DIRECTION('NONE', (0, 1, 0));
|
||||||
#10 = CARTESIAN_POINT('NONE', (0.005, -0.01, -0.005));
|
#11 = CARTESIAN_POINT('NONE', (0.005, -0.01, -0.005));
|
||||||
#11 = AXIS2_PLACEMENT_3D('NONE', #10, #9, #8);
|
#12 = AXIS2_PLACEMENT_3D('NONE', #11, #10, #9);
|
||||||
#12 = CIRCLE('NONE', #11, 0.01);
|
#13 = CIRCLE('NONE', #12, 0.01);
|
||||||
#13 = DIRECTION('NONE', (0, 1, 0));
|
#14 = DIRECTION('NONE', (0, 1, 0));
|
||||||
#14 = VECTOR('NONE', #13, 1);
|
#15 = VECTOR('NONE', #14, 1);
|
||||||
#15 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
|
#16 = CARTESIAN_POINT('NONE', (0.015, -0.01, -0.005));
|
||||||
#16 = LINE('NONE', #15, #14);
|
#17 = LINE('NONE', #16, #15);
|
||||||
#17 = DIRECTION('NONE', (1, 0, -0));
|
#18 = DIRECTION('NONE', (1, 0, -0));
|
||||||
#18 = DIRECTION('NONE', (0, 1, 0));
|
#19 = DIRECTION('NONE', (0, 1, 0));
|
||||||
#19 = CARTESIAN_POINT('NONE', (0.005, 0, -0.005));
|
#20 = CARTESIAN_POINT('NONE', (0.005, 0, -0.005));
|
||||||
#20 = AXIS2_PLACEMENT_3D('NONE', #19, #18, #17);
|
#21 = AXIS2_PLACEMENT_3D('NONE', #20, #19, #18);
|
||||||
#21 = CIRCLE('NONE', #20, 0.01);
|
#22 = CIRCLE('NONE', #21, 0.01);
|
||||||
#22 = EDGE_CURVE('NONE', #5, #5, #12, .T.);
|
#23 = EDGE_CURVE('NONE', #6, #6, #13, .T.);
|
||||||
#23 = EDGE_CURVE('NONE', #5, #7, #16, .T.);
|
#24 = EDGE_CURVE('NONE', #6, #8, #17, .T.);
|
||||||
#24 = EDGE_CURVE('NONE', #7, #7, #21, .T.);
|
#25 = EDGE_CURVE('NONE', #8, #8, #22, .T.);
|
||||||
#25 = CARTESIAN_POINT('NONE', (0.005, -0.005, -0.005));
|
#26 = CARTESIAN_POINT('NONE', (0.005, -0.005, -0.005));
|
||||||
#26 = DIRECTION('NONE', (0, 1, 0));
|
#27 = DIRECTION('NONE', (0, 1, 0));
|
||||||
#27 = DIRECTION('NONE', (1, 0, -0));
|
#28 = DIRECTION('NONE', (1, 0, -0));
|
||||||
#28 = AXIS2_PLACEMENT_3D('NONE', #25, #26, #27);
|
#29 = AXIS2_PLACEMENT_3D('NONE', #26, #27, #28);
|
||||||
#29 = CYLINDRICAL_SURFACE('NONE', #28, 0.01);
|
#30 = CYLINDRICAL_SURFACE('NONE', #29, 0.01);
|
||||||
#30 = CARTESIAN_POINT('NONE', (0, -0.01, -0));
|
#31 = CARTESIAN_POINT('NONE', (0, -0.01, -0));
|
||||||
#31 = DIRECTION('NONE', (0, 1, 0));
|
#32 = DIRECTION('NONE', (0, 1, 0));
|
||||||
#32 = AXIS2_PLACEMENT_3D('NONE', #30, #31, $);
|
#33 = AXIS2_PLACEMENT_3D('NONE', #31, #32, $);
|
||||||
#33 = PLANE('NONE', #32);
|
#34 = PLANE('NONE', #33);
|
||||||
#34 = CARTESIAN_POINT('NONE', (0, 0, -0));
|
#35 = CARTESIAN_POINT('NONE', (0, 0, -0));
|
||||||
#35 = DIRECTION('NONE', (0, 1, 0));
|
#36 = DIRECTION('NONE', (0, 1, 0));
|
||||||
#36 = AXIS2_PLACEMENT_3D('NONE', #34, #35, $);
|
#37 = AXIS2_PLACEMENT_3D('NONE', #35, #36, $);
|
||||||
#37 = PLANE('NONE', #36);
|
#38 = PLANE('NONE', #37);
|
||||||
#38 = ORIENTED_EDGE('NONE', *, *, #22, .T.);
|
#39 = ORIENTED_EDGE('NONE', *, *, #23, .T.);
|
||||||
#39 = ORIENTED_EDGE('NONE', *, *, #24, .F.);
|
#40 = ORIENTED_EDGE('NONE', *, *, #25, .F.);
|
||||||
#40 = EDGE_LOOP('NONE', (#38));
|
#41 = EDGE_LOOP('NONE', (#39));
|
||||||
#41 = FACE_BOUND('NONE', #40, .T.);
|
#42 = FACE_BOUND('NONE', #41, .T.);
|
||||||
#42 = EDGE_LOOP('NONE', (#39));
|
#43 = EDGE_LOOP('NONE', (#40));
|
||||||
#43 = FACE_BOUND('NONE', #42, .T.);
|
#44 = FACE_BOUND('NONE', #43, .T.);
|
||||||
#44 = ADVANCED_FACE('NONE', (#41, #43), #29, .T.);
|
#45 = ADVANCED_FACE('NONE', (#42, #44), #30, .T.);
|
||||||
#45 = ORIENTED_EDGE('NONE', *, *, #22, .F.);
|
#46 = ORIENTED_EDGE('NONE', *, *, #23, .F.);
|
||||||
#46 = EDGE_LOOP('NONE', (#45));
|
#47 = EDGE_LOOP('NONE', (#46));
|
||||||
#47 = FACE_BOUND('NONE', #46, .T.);
|
#48 = FACE_BOUND('NONE', #47, .T.);
|
||||||
#48 = ADVANCED_FACE('NONE', (#47), #33, .F.);
|
#49 = ADVANCED_FACE('NONE', (#48), #34, .F.);
|
||||||
#49 = ORIENTED_EDGE('NONE', *, *, #24, .T.);
|
#50 = ORIENTED_EDGE('NONE', *, *, #25, .T.);
|
||||||
#50 = EDGE_LOOP('NONE', (#49));
|
#51 = EDGE_LOOP('NONE', (#50));
|
||||||
#51 = FACE_BOUND('NONE', #50, .T.);
|
#52 = FACE_BOUND('NONE', #51, .T.);
|
||||||
#52 = ADVANCED_FACE('NONE', (#51), #37, .T.);
|
#53 = ADVANCED_FACE('NONE', (#52), #38, .T.);
|
||||||
#53 = CLOSED_SHELL('NONE', (#44, #48, #52));
|
#54 = CLOSED_SHELL('NONE', (#45, #49, #53));
|
||||||
#54 = MANIFOLD_SOLID_BREP('NONE', #53);
|
#55 = MANIFOLD_SOLID_BREP('NONE', #54);
|
||||||
#55 = APPLICATION_CONTEXT('configuration controlled 3D design of mechanical parts and assemblies');
|
#56 = APPLICATION_CONTEXT('configuration controlled 3D design of mechanical parts and assemblies');
|
||||||
#56 = PRODUCT_DEFINITION_CONTEXT('part definition', #55, 'design');
|
#57 = PRODUCT_DEFINITION_CONTEXT('part definition', #56, 'design');
|
||||||
#57 = PRODUCT('UNIDENTIFIED_PRODUCT', 'NONE', $, ());
|
#58 = PRODUCT('UNIDENTIFIED_PRODUCT', 'NONE', $, ());
|
||||||
#58 = PRODUCT_DEFINITION_FORMATION('', $, #57);
|
#59 = PRODUCT_DEFINITION_FORMATION('', $, #58);
|
||||||
#59 = PRODUCT_DEFINITION('design', $, #58, #56);
|
#60 = PRODUCT_DEFINITION('design', $, #59, #57);
|
||||||
#60 = PRODUCT_DEFINITION_SHAPE('NONE', $, #59);
|
#61 = PRODUCT_DEFINITION_SHAPE('NONE', $, #60);
|
||||||
#61 = ADVANCED_BREP_SHAPE_REPRESENTATION('NONE', (#54), #3);
|
#62 = ADVANCED_BREP_SHAPE_REPRESENTATION('NONE', (#55), #4);
|
||||||
#62 = SHAPE_DEFINITION_REPRESENTATION(#60, #61);
|
#63 = SHAPE_DEFINITION_REPRESENTATION(#61, #62);
|
||||||
ENDSEC;
|
ENDSEC;
|
||||||
END-ISO-10303-21;
|
END-ISO-10303-21;
|
||||||
|
@ -994,6 +994,39 @@ impl Node<MemberExpression> {
|
|||||||
|
|
||||||
// Check the property and object match -- e.g. ints for arrays, strs for objects.
|
// Check the property and object match -- e.g. ints for arrays, strs for objects.
|
||||||
match (object, property, self.computed) {
|
match (object, property, self.computed) {
|
||||||
|
(KclValue::Plane { value: plane }, Property::String(property), false) => match property.as_str() {
|
||||||
|
"yAxis" => {
|
||||||
|
let (p, u) = plane.info.y_axis.as_3_dims();
|
||||||
|
Ok(KclValue::array_from_point3d(
|
||||||
|
p,
|
||||||
|
NumericType::Known(crate::exec::UnitType::Length(u)),
|
||||||
|
vec![meta],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"xAxis" => {
|
||||||
|
let (p, u) = plane.info.x_axis.as_3_dims();
|
||||||
|
Ok(KclValue::array_from_point3d(
|
||||||
|
p,
|
||||||
|
NumericType::Known(crate::exec::UnitType::Length(u)),
|
||||||
|
vec![meta],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
"origin" => {
|
||||||
|
let (p, u) = plane.info.origin.as_3_dims();
|
||||||
|
Ok(KclValue::array_from_point3d(
|
||||||
|
p,
|
||||||
|
NumericType::Known(crate::exec::UnitType::Length(u)),
|
||||||
|
vec![meta],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
other => Err(KclError::new_undefined_value(
|
||||||
|
KclErrorDetails::new(
|
||||||
|
format!("Property '{other}' not found in plane"),
|
||||||
|
vec![self.clone().into()],
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
},
|
||||||
(KclValue::Object { value: map, meta: _ }, Property::String(property), false) => {
|
(KclValue::Object { value: map, meta: _ }, Property::String(property), false) => {
|
||||||
if let Some(value) = map.get(&property) {
|
if let Some(value) = map.get(&property) {
|
||||||
Ok(value.to_owned())
|
Ok(value.to_owned())
|
||||||
@ -1013,7 +1046,22 @@ impl Node<MemberExpression> {
|
|||||||
vec![self.clone().into()],
|
vec![self.clone().into()],
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
(KclValue::Object { .. }, p, _) => {
|
(KclValue::Object { value: map, .. }, p @ Property::UInt(i), _) => {
|
||||||
|
if i == 0
|
||||||
|
&& let Some(value) = map.get("x")
|
||||||
|
{
|
||||||
|
return Ok(value.to_owned());
|
||||||
|
}
|
||||||
|
if i == 1
|
||||||
|
&& let Some(value) = map.get("y")
|
||||||
|
{
|
||||||
|
return Ok(value.to_owned());
|
||||||
|
}
|
||||||
|
if i == 2
|
||||||
|
&& let Some(value) = map.get("z")
|
||||||
|
{
|
||||||
|
return Ok(value.to_owned());
|
||||||
|
}
|
||||||
let t = p.type_name();
|
let t = p.type_name();
|
||||||
let article = article_for(t);
|
let article = article_for(t);
|
||||||
Err(KclError::new_semantic(KclErrorDetails::new(
|
Err(KclError::new_semantic(KclErrorDetails::new(
|
||||||
@ -2205,4 +2253,12 @@ y = x[0mm + 1]
|
|||||||
"#;
|
"#;
|
||||||
parse_execute(ast).await.unwrap_err();
|
parse_execute(ast).await.unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn getting_property_of_plane() {
|
||||||
|
// let ast = include_str!("../../tests/inputs/planestuff.kcl");
|
||||||
|
let ast = std::fs::read_to_string("tests/inputs/planestuff.kcl").unwrap();
|
||||||
|
|
||||||
|
parse_execute(&ast).await.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -921,6 +921,12 @@ impl Point3d {
|
|||||||
units: UnitLen::Unknown,
|
units: UnitLen::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_3_dims(&self) -> ([f64; 3], UnitLen) {
|
||||||
|
let p = [self.x, self.y, self.z];
|
||||||
|
let u = self.units;
|
||||||
|
(p, u)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<[TyF64; 3]> for Point3d {
|
impl From<[TyF64; 3]> for Point3d {
|
||||||
|
@ -458,6 +458,31 @@ impl KclValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Put the point into a KCL point.
|
||||||
|
pub fn array_from_point3d(p: [f64; 3], ty: NumericType, meta: Vec<Metadata>) -> Self {
|
||||||
|
let [x, y, z] = p;
|
||||||
|
Self::HomArray {
|
||||||
|
value: vec![
|
||||||
|
Self::Number {
|
||||||
|
value: x,
|
||||||
|
meta: meta.clone(),
|
||||||
|
ty,
|
||||||
|
},
|
||||||
|
Self::Number {
|
||||||
|
value: y,
|
||||||
|
meta: meta.clone(),
|
||||||
|
ty,
|
||||||
|
},
|
||||||
|
Self::Number {
|
||||||
|
value: z,
|
||||||
|
meta: meta.clone(),
|
||||||
|
ty,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
ty: ty.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn as_usize(&self) -> Option<usize> {
|
pub(crate) fn as_usize(&self) -> Option<usize> {
|
||||||
match self {
|
match self {
|
||||||
KclValue::Number { value, .. } => crate::try_f64_to_usize(*value),
|
KclValue::Number { value, .. } => crate::try_f64_to_usize(*value),
|
||||||
|
60
rust/kcl-lib/tests/inputs/planestuff.kcl
Normal file
60
rust/kcl-lib/tests/inputs/planestuff.kcl
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// There are 3 ways to define a plane in KCL, according to https://zoo.dev/docs/kcl-std/types/std-types-Plane
|
||||||
|
// - A default plane
|
||||||
|
// - Modifying a default plane e.g. via offsetPlane
|
||||||
|
// - Defining your own struct
|
||||||
|
// This file tests they all work equivalently.
|
||||||
|
|
||||||
|
// Define a plane using struct representation.
|
||||||
|
myPlane = {
|
||||||
|
origin = { x = 0, y = 0, z = 0 },
|
||||||
|
xAxis = { x = 1, y = 0, z = 0 },
|
||||||
|
yAxis = { x = 0, y = 1, z = 0 },
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prove we can get its axes and origin.
|
||||||
|
ax = myPlane.xAxis
|
||||||
|
assert(ax[0], isEqualTo = 1)
|
||||||
|
assert(ax[1], isEqualTo = 0)
|
||||||
|
assert(ax[2], isEqualTo = 0)
|
||||||
|
ay = myPlane.yAxis
|
||||||
|
assert(ay[0], isEqualTo = 0)
|
||||||
|
assert(ay[1], isEqualTo = 1)
|
||||||
|
assert(ay[2], isEqualTo = 0)
|
||||||
|
aorigin = myPlane.origin
|
||||||
|
assert(aorigin[0], isEqualTo = 0)
|
||||||
|
assert(aorigin[1], isEqualTo = 0)
|
||||||
|
assert(aorigin[2], isEqualTo = 0)
|
||||||
|
|
||||||
|
// Define a plane using standard planes.
|
||||||
|
myOtherPlane = XY
|
||||||
|
|
||||||
|
// Prove we can get its axes and origin.
|
||||||
|
axOther = myOtherPlane.xAxis
|
||||||
|
assert(axOther[0], isEqualTo = 1)
|
||||||
|
assert(axOther[1], isEqualTo = 0)
|
||||||
|
assert(axOther[2], isEqualTo = 0)
|
||||||
|
ayOther = myOtherPlane.yAxis
|
||||||
|
assert(ayOther[0], isEqualTo = 0)
|
||||||
|
assert(ayOther[1], isEqualTo = 1)
|
||||||
|
assert(ayOther[2], isEqualTo = 0)
|
||||||
|
aoriginOther = myOtherPlane.origin
|
||||||
|
assert(aoriginOther[0], isEqualTo = 0)
|
||||||
|
assert(aoriginOther[1], isEqualTo = 0)
|
||||||
|
assert(aoriginOther[2], isEqualTo = 0)
|
||||||
|
|
||||||
|
// Define a plane using a plane-modifying function like offsetPlane.
|
||||||
|
myAlternatePlane = offsetPlane(XY, offset = 0)
|
||||||
|
|
||||||
|
// Prove we can get its axes and origin.
|
||||||
|
axAlternate = myAlternatePlane.xAxis
|
||||||
|
assert(axAlternate[0], isEqualTo = 1)
|
||||||
|
assert(axAlternate[1], isEqualTo = 0)
|
||||||
|
assert(axAlternate[2], isEqualTo = 0)
|
||||||
|
ayAlternate = myAlternatePlane.yAxis
|
||||||
|
assert(ayAlternate[0], isEqualTo = 0)
|
||||||
|
assert(ayAlternate[1], isEqualTo = 1)
|
||||||
|
assert(ayAlternate[2], isEqualTo = 0)
|
||||||
|
aoriginAlternate = myAlternatePlane.origin
|
||||||
|
assert(aoriginAlternate[0], isEqualTo = 0)
|
||||||
|
assert(aoriginAlternate[1], isEqualTo = 0)
|
||||||
|
assert(aoriginAlternate[2], isEqualTo = 0)
|
@ -4,6 +4,11 @@
|
|||||||
|
|
||||||
URL STATUS
|
URL STATUS
|
||||||
000 https://${BASE_URL}
|
000 https://${BASE_URL}
|
||||||
|
405 https://api.dev.zoo.dev/oauth2/token/revoke
|
||||||
|
401 https://api.dev.zoo.dev/users
|
||||||
|
401 https://dev.zoo.dev
|
||||||
|
401 https://dev.zoo.dev/docs
|
||||||
|
401 https://dev.zoo.dev/docs/kcl-samples/car-wheel-assembly
|
||||||
301 https://discord.gg/JQEpHR7Nt2
|
301 https://discord.gg/JQEpHR7Nt2
|
||||||
404 https://github.com/KittyCAD/engine/issues/3528
|
404 https://github.com/KittyCAD/engine/issues/3528
|
||||||
404 https://github.com/KittyCAD/modeling-app/commit/${ref}
|
404 https://github.com/KittyCAD/modeling-app/commit/${ref}
|
||||||
@ -17,5 +22,4 @@ URL STATUS
|
|||||||
302 https://stackoverflow.com/a/58436959/22753272
|
302 https://stackoverflow.com/a/58436959/22753272
|
||||||
303 https://text-to-cad.zoo.dev/dashboard
|
303 https://text-to-cad.zoo.dev/dashboard
|
||||||
307 https://zoo.dev/
|
307 https://zoo.dev/
|
||||||
308 https://zoo.dev/docs/api/ml/generate-a-cad-model-from-text
|
|
||||||
308 https://zoo.dev/docs/kcl
|
308 https://zoo.dev/docs/kcl
|
||||||
|
@ -53,7 +53,6 @@ import {
|
|||||||
WASM_INIT_FAILED_TOAST_ID,
|
WASM_INIT_FAILED_TOAST_ID,
|
||||||
} from '@src/lib/constants'
|
} from '@src/lib/constants'
|
||||||
import { isPlaywright } from '@src/lib/isPlaywright'
|
import { isPlaywright } from '@src/lib/isPlaywright'
|
||||||
import { VITE_KC_SITE_BASE_URL } from '@src/env'
|
|
||||||
import { useNetworkHealthStatus } from '@src/components/NetworkHealthIndicator'
|
import { useNetworkHealthStatus } from '@src/components/NetworkHealthIndicator'
|
||||||
import { useNetworkMachineStatus } from '@src/components/NetworkMachineIndicator'
|
import { useNetworkMachineStatus } from '@src/components/NetworkMachineIndicator'
|
||||||
import {
|
import {
|
||||||
@ -65,6 +64,7 @@ import { useModelingContext } from '@src/hooks/useModelingContext'
|
|||||||
import { xStateValueToString } from '@src/lib/xStateValueToString'
|
import { xStateValueToString } from '@src/lib/xStateValueToString'
|
||||||
import { getSelectionTypeDisplayText } from '@src/lib/selections'
|
import { getSelectionTypeDisplayText } from '@src/lib/selections'
|
||||||
import type { StatusBarItemType } from '@src/components/StatusBar/statusBarTypes'
|
import type { StatusBarItemType } from '@src/components/StatusBar/statusBarTypes'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
// CYCLIC REF
|
// CYCLIC REF
|
||||||
sceneInfra.camControls.engineStreamActor = engineStreamActor
|
sceneInfra.camControls.engineStreamActor = engineStreamActor
|
||||||
@ -189,7 +189,8 @@ export function App() {
|
|||||||
() =>
|
() =>
|
||||||
DownloadAppToast({
|
DownloadAppToast({
|
||||||
onAccept: () => {
|
onAccept: () => {
|
||||||
openWindow(`${VITE_KC_SITE_BASE_URL}/${APP_DOWNLOAD_PATH}`)
|
const url = withSiteBaseURL(`/${APP_DOWNLOAD_PATH}`)
|
||||||
|
openWindow(url)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast.dismiss(DOWNLOAD_APP_TOAST_ID)
|
toast.dismiss(DOWNLOAD_APP_TOAST_ID)
|
||||||
})
|
})
|
||||||
|
@ -5,8 +5,8 @@ import {
|
|||||||
BillingRemaining,
|
BillingRemaining,
|
||||||
BillingRemainingMode,
|
BillingRemainingMode,
|
||||||
} from '@src/components/BillingRemaining'
|
} from '@src/components/BillingRemaining'
|
||||||
|
|
||||||
import { type BillingActor } from '@src/machines/billingMachine'
|
import { type BillingActor } from '@src/machines/billingMachine'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export const BillingDialog = (props: { billingActor: BillingActor }) => {
|
export const BillingDialog = (props: { billingActor: BillingActor }) => {
|
||||||
const billingContext = useSelector(
|
const billingContext = useSelector(
|
||||||
@ -42,7 +42,7 @@ export const BillingDialog = (props: { billingActor: BillingActor }) => {
|
|||||||
{!hasUnlimited && (
|
{!hasUnlimited && (
|
||||||
<a
|
<a
|
||||||
className="bg-ml-black text-ml-white rounded-lg text-center p-1 cursor-pointer"
|
className="bg-ml-black text-ml-white rounded-lg text-center p-1 cursor-pointer"
|
||||||
href="https://zoo.dev/design-studio-pricing"
|
href={withSiteBaseURL('/design-studio-pricing')}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
data-testid="billing-upgrade-button"
|
data-testid="billing-upgrade-button"
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
import { onboardingStartPath } from '@src/lib/onboardingPaths'
|
import { onboardingStartPath } from '@src/lib/onboardingPaths'
|
||||||
import { reportRejection } from '@src/lib/trap'
|
import { reportRejection } from '@src/lib/trap'
|
||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
const HelpMenuDivider = () => (
|
const HelpMenuDivider = () => (
|
||||||
<div className="h-[1px] bg-chalkboard-110 dark:bg-chalkboard-80" />
|
<div className="h-[1px] bg-chalkboard-110 dark:bg-chalkboard-80" />
|
||||||
@ -89,7 +90,7 @@ export function HelpMenu() {
|
|||||||
<HelpMenuDivider />
|
<HelpMenuDivider />
|
||||||
<HelpMenuItem
|
<HelpMenuItem
|
||||||
as="a"
|
as="a"
|
||||||
href="https://zoo.dev/docs/kcl-samples"
|
href={withSiteBaseURL('/docs/kcl-samples')}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
@ -97,7 +98,7 @@ export function HelpMenu() {
|
|||||||
</HelpMenuItem>
|
</HelpMenuItem>
|
||||||
<HelpMenuItem
|
<HelpMenuItem
|
||||||
as="a"
|
as="a"
|
||||||
href="https://zoo.dev/docs/kcl-lang"
|
href={withSiteBaseURL('/docs/kcl-lang')}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
|
@ -7,7 +7,7 @@ import {
|
|||||||
LanguageServerClient,
|
LanguageServerClient,
|
||||||
LspWorkerEventType,
|
LspWorkerEventType,
|
||||||
} from '@kittycad/codemirror-lsp-client'
|
} from '@kittycad/codemirror-lsp-client'
|
||||||
import { TEST, VITE_KC_API_BASE_URL } from '@src/env'
|
import env from '@src/env'
|
||||||
import React, { createContext, useContext, useMemo, useState } from 'react'
|
import React, { createContext, useContext, useMemo, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import type * as LSP from 'vscode-languageserver-protocol'
|
import type * as LSP from 'vscode-languageserver-protocol'
|
||||||
@ -28,6 +28,7 @@ import type { FileEntry } from '@src/lib/project'
|
|||||||
import { codeManager } from '@src/lib/singletons'
|
import { codeManager } from '@src/lib/singletons'
|
||||||
import { err } from '@src/lib/trap'
|
import { err } from '@src/lib/trap'
|
||||||
import { useToken } from '@src/lib/singletons'
|
import { useToken } from '@src/lib/singletons'
|
||||||
|
import { withAPIBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
|
function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
|
||||||
return []
|
return []
|
||||||
@ -77,7 +78,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
// But the server happens async so we break this into two parts.
|
// But the server happens async so we break this into two parts.
|
||||||
// Below is the client and server promise.
|
// Below is the client and server promise.
|
||||||
const { lspClient: kclLspClient } = useMemo(() => {
|
const { lspClient: kclLspClient } = useMemo(() => {
|
||||||
if (!token || token === '' || TEST) {
|
if (!token || token === '' || env().TEST) {
|
||||||
return { lspClient: null }
|
return { lspClient: null }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
const initEvent: KclWorkerOptions = {
|
const initEvent: KclWorkerOptions = {
|
||||||
wasmUrl: wasmUrl(),
|
wasmUrl: wasmUrl(),
|
||||||
token: token,
|
token: token,
|
||||||
apiBaseUrl: VITE_KC_API_BASE_URL,
|
apiBaseUrl: withAPIBaseURL(''),
|
||||||
}
|
}
|
||||||
lspWorker.postMessage({
|
lspWorker.postMessage({
|
||||||
worker: LspWorker.Kcl,
|
worker: LspWorker.Kcl,
|
||||||
@ -136,7 +137,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
// We do not want to restart the server, its just wasteful.
|
// We do not want to restart the server, its just wasteful.
|
||||||
const kclLSP = useMemo(() => {
|
const kclLSP = useMemo(() => {
|
||||||
let plugin = null
|
let plugin = null
|
||||||
if (isKclLspReady && !TEST && kclLspClient) {
|
if (isKclLspReady && !env().TEST && kclLspClient) {
|
||||||
// Set up the lsp plugin.
|
// Set up the lsp plugin.
|
||||||
const lsp = kcl({
|
const lsp = kcl({
|
||||||
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
||||||
@ -170,7 +171,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
}, [kclLspClient, isKclLspReady])
|
}, [kclLspClient, isKclLspReady])
|
||||||
|
|
||||||
const { lspClient: copilotLspClient } = useMemo(() => {
|
const { lspClient: copilotLspClient } = useMemo(() => {
|
||||||
if (!token || token === '' || TEST) {
|
if (!token || token === '' || env().TEST) {
|
||||||
return { lspClient: null }
|
return { lspClient: null }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
const initEvent: CopilotWorkerOptions = {
|
const initEvent: CopilotWorkerOptions = {
|
||||||
wasmUrl: wasmUrl(),
|
wasmUrl: wasmUrl(),
|
||||||
token: token,
|
token: token,
|
||||||
apiBaseUrl: VITE_KC_API_BASE_URL,
|
apiBaseUrl: withAPIBaseURL(''),
|
||||||
}
|
}
|
||||||
lspWorker.postMessage({
|
lspWorker.postMessage({
|
||||||
worker: LspWorker.Copilot,
|
worker: LspWorker.Copilot,
|
||||||
@ -212,7 +213,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
|
|||||||
// We do not want to restart the server, its just wasteful.
|
// We do not want to restart the server, its just wasteful.
|
||||||
const copilotLSP = useMemo(() => {
|
const copilotLSP = useMemo(() => {
|
||||||
let plugin = null
|
let plugin = null
|
||||||
if (isCopilotLspReady && !TEST && copilotLspClient) {
|
if (isCopilotLspReady && !env().TEST && copilotLspClient) {
|
||||||
// Set up the lsp plugin.
|
// Set up the lsp plugin.
|
||||||
const lsp = copilotPlugin({
|
const lsp = copilotPlugin({
|
||||||
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
|
||||||
|
@ -12,6 +12,7 @@ import { reportRejection } from '@src/lib/trap'
|
|||||||
import { commandBarActor, settingsActor } from '@src/lib/singletons'
|
import { commandBarActor, settingsActor } from '@src/lib/singletons'
|
||||||
|
|
||||||
import styles from './KclEditorMenu.module.css'
|
import styles from './KclEditorMenu.module.css'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export const KclEditorMenu = ({ children }: PropsWithChildren) => {
|
export const KclEditorMenu = ({ children }: PropsWithChildren) => {
|
||||||
const { enable: convertToVarEnabled, handleClick: handleConvertToVarClick } =
|
const { enable: convertToVarEnabled, handleClick: handleConvertToVarClick } =
|
||||||
@ -67,7 +68,7 @@ export const KclEditorMenu = ({ children }: PropsWithChildren) => {
|
|||||||
<Menu.Item>
|
<Menu.Item>
|
||||||
<a
|
<a
|
||||||
className={styles.button}
|
className={styles.button}
|
||||||
href="https://zoo.dev/docs/kcl-lang"
|
href={withSiteBaseURL('/docs/kcl-lang')}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
onClick={openExternalBrowserIfDesktop()}
|
onClick={openExternalBrowserIfDesktop()}
|
||||||
@ -108,7 +109,7 @@ export const KclEditorMenu = ({ children }: PropsWithChildren) => {
|
|||||||
<Menu.Item>
|
<Menu.Item>
|
||||||
<a
|
<a
|
||||||
className={styles.button}
|
className={styles.button}
|
||||||
href="https://zoo.dev/docs/kcl-samples"
|
href={withSiteBaseURL('/docs/kcl-samples')}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
onClick={openExternalBrowserIfDesktop()}
|
onClick={openExternalBrowserIfDesktop()}
|
||||||
|
@ -35,7 +35,7 @@ import {
|
|||||||
rectangularSelection,
|
rectangularSelection,
|
||||||
} from '@codemirror/view'
|
} from '@codemirror/view'
|
||||||
import interact from '@replit/codemirror-interact'
|
import interact from '@replit/codemirror-interact'
|
||||||
import { TEST } from '@src/env'
|
import env from '@src/env'
|
||||||
import { useSelector } from '@xstate/react'
|
import { useSelector } from '@xstate/react'
|
||||||
import { useEffect, useMemo, useRef } from 'react'
|
import { useEffect, useMemo, useRef } from 'react'
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ export const KclEditorPane = () => {
|
|||||||
if (copilotLSP) extensions.push(copilotLSP)
|
if (copilotLSP) extensions.push(copilotLSP)
|
||||||
|
|
||||||
// These extensions have proven to mess with vitest
|
// These extensions have proven to mess with vitest
|
||||||
if (!TEST) {
|
if (!env().TEST) {
|
||||||
extensions.push(
|
extensions.push(
|
||||||
lintGutter(),
|
lintGutter(),
|
||||||
lineNumbers(),
|
lineNumbers(),
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Transition } from '@headlessui/react'
|
import { Transition } from '@headlessui/react'
|
||||||
import { VITE_KC_SITE_BASE_URL } from '@src/env'
|
|
||||||
import { useSearchParams } from 'react-router-dom'
|
import { useSearchParams } from 'react-router-dom'
|
||||||
import { base64ToString } from '@src/lib/base64'
|
import { base64ToString } from '@src/lib/base64'
|
||||||
|
|
||||||
@ -16,6 +15,7 @@ import { platform } from '@src/lib/utils'
|
|||||||
import { codeManager } from '@src/lib/singletons'
|
import { codeManager } from '@src/lib/singletons'
|
||||||
import { Logo } from '@src/components/Logo'
|
import { Logo } from '@src/components/Logo'
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component is a handler that checks if a certain query parameter
|
* This component is a handler that checks if a certain query parameter
|
||||||
@ -98,7 +98,7 @@ export const OpenInDesktopAppHandler = (props: React.PropsWithChildren) => {
|
|||||||
>
|
>
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as="div"
|
as="div"
|
||||||
className={`max-w-3xl py-6 px-10 flex flex-col items-center gap-12
|
className={`max-w-3xl py-6 px-10 flex flex-col items-center gap-12
|
||||||
mx-auto border rounded-lg shadow-lg bg-chalkboard-10 dark:bg-chalkboard-100`}
|
mx-auto border rounded-lg shadow-lg bg-chalkboard-10 dark:bg-chalkboard-100`}
|
||||||
enter="ease-out duration-300"
|
enter="ease-out duration-300"
|
||||||
enterFrom="opacity-0 scale-95"
|
enterFrom="opacity-0 scale-95"
|
||||||
@ -133,7 +133,7 @@ export const OpenInDesktopAppHandler = (props: React.PropsWithChildren) => {
|
|||||||
buttonClasses +
|
buttonClasses +
|
||||||
' text-sm border-transparent justify-center dark:bg-transparent'
|
' text-sm border-transparent justify-center dark:bg-transparent'
|
||||||
}
|
}
|
||||||
to={`${VITE_KC_SITE_BASE_URL}/${APP_DOWNLOAD_PATH}`}
|
to={withSiteBaseURL(`/${APP_DOWNLOAD_PATH}`)}
|
||||||
iconEnd={{ icon: 'link', bgClassName: '!bg-transparent' }}
|
iconEnd={{ icon: 'link', bgClassName: '!bg-transparent' }}
|
||||||
>
|
>
|
||||||
Download desktop app
|
Download desktop app
|
||||||
|
@ -12,9 +12,9 @@ import { Popover } from '@headlessui/react'
|
|||||||
import Tooltip from '@src/components/Tooltip'
|
import Tooltip from '@src/components/Tooltip'
|
||||||
import { HelpMenu } from '@src/components/HelpMenu'
|
import { HelpMenu } from '@src/components/HelpMenu'
|
||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
import { VITE_KC_SITE_BASE_URL } from '@src/env'
|
|
||||||
import { APP_DOWNLOAD_PATH } from '@src/lib/constants'
|
import { APP_DOWNLOAD_PATH } from '@src/lib/constants'
|
||||||
import { desktopAppPitchMessage } from '@src/components/DownloadAppToast'
|
import { desktopAppPitchMessage } from '@src/components/DownloadAppToast'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export const defaultGlobalStatusBarItems = ({
|
export const defaultGlobalStatusBarItems = ({
|
||||||
location,
|
location,
|
||||||
@ -37,7 +37,7 @@ export const defaultGlobalStatusBarItems = ({
|
|||||||
id: 'download-desktop-app',
|
id: 'download-desktop-app',
|
||||||
element: 'externalLink',
|
element: 'externalLink',
|
||||||
label: 'Download the app',
|
label: 'Download the app',
|
||||||
href: `${VITE_KC_SITE_BASE_URL}/${APP_DOWNLOAD_PATH}`,
|
href: withSiteBaseURL(`/${APP_DOWNLOAD_PATH}`),
|
||||||
icon: 'download',
|
icon: 'download',
|
||||||
toolTip: {
|
toolTip: {
|
||||||
children: desktopAppPitchMessage,
|
children: desktopAppPitchMessage,
|
||||||
|
@ -13,6 +13,7 @@ import { isDesktop } from '@src/lib/isDesktop'
|
|||||||
import { PATHS } from '@src/lib/paths'
|
import { PATHS } from '@src/lib/paths'
|
||||||
import { authActor } from '@src/lib/singletons'
|
import { authActor } from '@src/lib/singletons'
|
||||||
import { reportRejection } from '@src/lib/trap'
|
import { reportRejection } from '@src/lib/trap'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
type User = Models['User_type']
|
type User = Models['User_type']
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ const UserSidebarMenu = ({ user }: { user?: User }) => {
|
|||||||
{
|
{
|
||||||
id: 'account',
|
id: 'account',
|
||||||
Element: 'externalLink',
|
Element: 'externalLink',
|
||||||
to: 'https://zoo.dev/account',
|
to: withSiteBaseURL('/account'),
|
||||||
children: (
|
children: (
|
||||||
<>
|
<>
|
||||||
<span className="flex-1">Manage account</span>
|
<span className="flex-1">Manage account</span>
|
||||||
|
126
src/env.test.ts
Normal file
126
src/env.test.ts
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import env from '@src/env'
|
||||||
|
import { vi } from 'vitest'
|
||||||
|
import { viteEnv, windowElectronProcessEnv, processEnv } from '@src/env'
|
||||||
|
|
||||||
|
describe('@src/env', () => {
|
||||||
|
describe('default export', () => {
|
||||||
|
it('should run the process.env workflow', () => {
|
||||||
|
// vite > node.js
|
||||||
|
const expected = {
|
||||||
|
NODE_ENV: 'test',
|
||||||
|
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_SITE_BASE_URL: 'https://dev.zoo.dev',
|
||||||
|
VITE_KC_SITE_APP_URL: 'https://app.dev.zoo.dev',
|
||||||
|
VITE_KC_CONNECTION_TIMEOUT_MS: '5000',
|
||||||
|
VITE_KITTYCAD_API_TOKEN: 'redacted',
|
||||||
|
PROD: undefined,
|
||||||
|
TEST: 'true',
|
||||||
|
DEV: '1',
|
||||||
|
CI: 'true',
|
||||||
|
}
|
||||||
|
const actual = env()
|
||||||
|
expect(typeof actual.VITE_KITTYCAD_API_TOKEN).toBe('string')
|
||||||
|
//@ts-ignore I do not want this token in our logs for any reason.
|
||||||
|
actual.VITE_KITTYCAD_API_TOKEN = 'redacted'
|
||||||
|
//@ts-ignore need to hard code this for localhost and CI
|
||||||
|
actual.CI = 'true'
|
||||||
|
expect(actual).toStrictEqual(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('viteEnv', () => {
|
||||||
|
it('should match the EnvironmentVariables key types*', () => {
|
||||||
|
// Do not print entire object or compare, it contains a ton of ENV vars.
|
||||||
|
// We only need to match against EnvironmentVariables
|
||||||
|
const actual = viteEnv()
|
||||||
|
expect(typeof actual.NODE_ENV).toBe('string')
|
||||||
|
// Not passed in during tests?
|
||||||
|
expect(typeof actual.VITE_KC_WS_MODELING_URL).toBe('undefined')
|
||||||
|
expect(typeof actual.VITE_KITTYCAD_API_BASE_URL).toBe('string')
|
||||||
|
expect(typeof actual.VITE_KC_SITE_BASE_URL).toBe('string')
|
||||||
|
// Not passed in during tests?
|
||||||
|
expect(typeof actual.VITE_KC_SITE_API_URL).toBe('undefined')
|
||||||
|
expect(typeof actual.VITE_KC_CONNECTION_TIMEOUT_MS).toBe('string')
|
||||||
|
expect(typeof actual.VITE_KITTYCAD_API_TOKEN).toBe('string')
|
||||||
|
expect(typeof actual.PROD).toBe('boolean')
|
||||||
|
expect(typeof actual.TEST).toBe('string')
|
||||||
|
expect(typeof actual.DEV).toBe('boolean')
|
||||||
|
// Don't check CI...
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('windowElectronProcessEnv', () => {
|
||||||
|
it('should return undefined in vitest runtime', () => {
|
||||||
|
const expected = undefined
|
||||||
|
const actual = windowElectronProcessEnv()
|
||||||
|
expect(actual).toBe(expected)
|
||||||
|
})
|
||||||
|
describe('When mocking window', () => {
|
||||||
|
it('should match the EnvironmentVariable key types*', () => {
|
||||||
|
vi.stubGlobal('electron', {
|
||||||
|
process: {
|
||||||
|
env: {
|
||||||
|
NODE_ENV: 'test',
|
||||||
|
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_SITE_BASE_URL: 'https://dev.zoo.dev',
|
||||||
|
VITE_KC_SITE_APP_URL: 'https://app.dev.zoo.dev',
|
||||||
|
VITE_KC_CONNECTION_TIMEOUT_MS: '5000',
|
||||||
|
VITE_KITTYCAD_API_TOKEN: 'redacted',
|
||||||
|
PROD: undefined,
|
||||||
|
TEST: 'true',
|
||||||
|
DEV: '1',
|
||||||
|
CI: undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const expected = {
|
||||||
|
NODE_ENV: 'test',
|
||||||
|
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_SITE_BASE_URL: 'https://dev.zoo.dev',
|
||||||
|
VITE_KC_SITE_APP_URL: 'https://app.dev.zoo.dev',
|
||||||
|
VITE_KC_CONNECTION_TIMEOUT_MS: '5000',
|
||||||
|
VITE_KITTYCAD_API_TOKEN: 'redacted',
|
||||||
|
PROD: undefined,
|
||||||
|
TEST: 'true',
|
||||||
|
DEV: '1',
|
||||||
|
CI: undefined,
|
||||||
|
}
|
||||||
|
const actual = windowElectronProcessEnv()
|
||||||
|
expect(actual).toStrictEqual(expected)
|
||||||
|
vi.unstubAllGlobals()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
it('should fail on missing window.electron', () => {
|
||||||
|
// someone didn't clean up their test if this fails!
|
||||||
|
const expected = undefined
|
||||||
|
const actual = windowElectronProcessEnv()
|
||||||
|
expect(actual).toBe(expected)
|
||||||
|
expect(window.electron).toBe(expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('processEnv', () => {
|
||||||
|
it('should match the EnvironmentVariables key types*', () => {
|
||||||
|
// Do not print entire object or compare, it contains a ton of ENV vars.
|
||||||
|
// We only need to match against EnvironmentVariables
|
||||||
|
const actual = processEnv()
|
||||||
|
expect(!!actual).toBe(true)
|
||||||
|
expect(typeof actual?.NODE_ENV).toBe('string')
|
||||||
|
// Not passed in during tests?
|
||||||
|
expect(typeof actual?.VITE_KC_WS_MODELING_URL).toBe('undefined')
|
||||||
|
expect(typeof actual?.VITE_KITTYCAD_API_BASE_URL).toBe('string')
|
||||||
|
expect(typeof actual?.VITE_KC_SITE_BASE_URL).toBe('string')
|
||||||
|
// Not passed in during tests?
|
||||||
|
expect(typeof actual?.VITE_KC_SITE_API_URL).toBe('undefined')
|
||||||
|
expect(typeof actual?.VITE_KC_CONNECTION_TIMEOUT_MS).toBe('string')
|
||||||
|
expect(typeof actual?.VITE_KITTYCAD_API_TOKEN).toBe('string')
|
||||||
|
expect(typeof actual?.PROD).toBe('string')
|
||||||
|
expect(typeof actual?.TEST).toBe('string')
|
||||||
|
expect(typeof actual?.DEV).toBe('string')
|
||||||
|
// Don't check CI...
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
107
src/env.ts
107
src/env.ts
@ -1,21 +1,88 @@
|
|||||||
// It turns out import.meta.env is a really fucky env var passing method.
|
type EnvironmentVariables = {
|
||||||
// It's purely generated by Vite and nothing else.
|
readonly NODE_ENV: string | undefined
|
||||||
// For Jest tests, we use babel to deal with it (it's a Syntax error otherwise)
|
readonly VITE_KC_API_WS_MODELING_URL: string | undefined
|
||||||
// @ts-ignore: TS1343
|
readonly VITE_KITTYCAD_API_BASE_URL: string | undefined
|
||||||
const env = window.electron?.process.env ?? import.meta.env
|
readonly VITE_KC_SITE_BASE_URL: string | undefined
|
||||||
|
readonly VITE_KC_SITE_APP_URL: string | undefined
|
||||||
|
readonly VITE_KC_CONNECTION_TIMEOUT_MS: string | undefined
|
||||||
|
readonly VITE_KITTYCAD_API_TOKEN: string | undefined
|
||||||
|
readonly PROD: string | undefined
|
||||||
|
readonly TEST: string | undefined
|
||||||
|
readonly DEV: string | undefined
|
||||||
|
readonly CI: string | undefined
|
||||||
|
}
|
||||||
|
|
||||||
export const NODE_ENV = env.NODE_ENV as string | undefined
|
export const viteEnv = () => {
|
||||||
export const VITE_KC_API_WS_MODELING_URL = env.VITE_KC_API_WS_MODELING_URL as
|
// It turns out import.meta.env is a really fucky env var passing method.
|
||||||
| string
|
// It's purely generated by Vite and nothing else.
|
||||||
| undefined
|
// For Jest tests, we use babel to deal with it (it's a Syntax error otherwise)
|
||||||
export const VITE_KC_API_BASE_URL = env.VITE_KC_API_BASE_URL
|
// @ts-ignore: TS1343
|
||||||
export const VITE_KC_SITE_BASE_URL = env.VITE_KC_SITE_BASE_URL
|
return import.meta.env
|
||||||
export const VITE_KC_SITE_APP_URL = env.VITE_KC_SITE_APP_URL
|
}
|
||||||
export const VITE_KC_SKIP_AUTH = env.VITE_KC_SKIP_AUTH as string | undefined
|
|
||||||
export const VITE_KC_CONNECTION_TIMEOUT_MS =
|
export const windowElectronProcessEnv = () => {
|
||||||
env.VITE_KC_CONNECTION_TIMEOUT_MS as string | undefined
|
return typeof window !== 'undefined' && typeof window.electron !== 'undefined'
|
||||||
export const VITE_KC_DEV_TOKEN = env.VITE_KC_DEV_TOKEN as string | undefined
|
? window?.electron?.process?.env
|
||||||
export const PROD = env.PROD as string | undefined
|
: undefined
|
||||||
export const TEST = env.TEST as string | undefined
|
}
|
||||||
export const DEV = env.DEV as string | undefined
|
|
||||||
export const CI = env.CI as string | undefined
|
export const processEnv = () => {
|
||||||
|
if (typeof process === 'undefined') {
|
||||||
|
// Web, no window.process or process
|
||||||
|
return undefined
|
||||||
|
} else if (
|
||||||
|
typeof process !== 'undefined' &&
|
||||||
|
typeof window !== 'undefined' &&
|
||||||
|
process.env.TEST === 'false'
|
||||||
|
) {
|
||||||
|
// Web, you made window.process, why :(, need process.env.TEST to make sure the frontend gets evaluated.
|
||||||
|
// The frontend can spoof this too :(
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.env
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will work in any runtime. Note that we shouldn't be using this for any values outside of the
|
||||||
|
* EnvironmentVariables type. This is not going to replace process.env.
|
||||||
|
*
|
||||||
|
* Vite -> node.js -> bridge -> javascript
|
||||||
|
* We want to have the node.js and javascript runtime share the same code for getting these important configurations.
|
||||||
|
*/
|
||||||
|
export default (): EnvironmentVariables => {
|
||||||
|
// Compute the possible environment variables, order operation is important
|
||||||
|
// runtime (TODO) > process.env > window.electron.process.env > import.meta.env
|
||||||
|
|
||||||
|
const viteOnly = viteEnv()
|
||||||
|
const windowElectronProcessEnvOnly = windowElectronProcessEnv()
|
||||||
|
const processEnvOnly = processEnv()
|
||||||
|
const env = processEnvOnly || windowElectronProcessEnvOnly || viteOnly
|
||||||
|
// Vite uses Booleans and process.env uses strings
|
||||||
|
let PROD = env.PROD
|
||||||
|
if (typeof PROD === 'boolean') {
|
||||||
|
PROD = Number(PROD).toString()
|
||||||
|
}
|
||||||
|
let DEV = env.DEV
|
||||||
|
if (typeof DEV === 'boolean') {
|
||||||
|
DEV = Number(DEV).toString()
|
||||||
|
}
|
||||||
|
const environmentVariables: EnvironmentVariables = {
|
||||||
|
NODE_ENV: (env.NODE_ENV as string) || undefined,
|
||||||
|
VITE_KC_API_WS_MODELING_URL:
|
||||||
|
(env.VITE_KC_API_WS_MODELING_URL as string) || undefined,
|
||||||
|
VITE_KITTYCAD_API_BASE_URL:
|
||||||
|
(env.VITE_KITTYCAD_API_BASE_URL as string) || undefined,
|
||||||
|
VITE_KC_SITE_BASE_URL: (env.VITE_KC_SITE_BASE_URL as string) || undefined,
|
||||||
|
VITE_KC_SITE_APP_URL: (env.VITE_KC_SITE_APP_URL as string) || undefined,
|
||||||
|
VITE_KC_CONNECTION_TIMEOUT_MS:
|
||||||
|
(env.VITE_KC_CONNECTION_TIMEOUT_MS as string) || undefined,
|
||||||
|
VITE_KITTYCAD_API_TOKEN:
|
||||||
|
(env.VITE_KITTYCAD_API_TOKEN as string) || undefined,
|
||||||
|
PROD: PROD || undefined,
|
||||||
|
TEST: (env.TEST as string) || undefined,
|
||||||
|
DEV: DEV || undefined,
|
||||||
|
CI: (env.CI as string) || undefined,
|
||||||
|
}
|
||||||
|
return environmentVariables
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { VITE_KC_DEV_TOKEN } from '@src/env'
|
import env from '@src/env'
|
||||||
|
|
||||||
import { createLiteral } from '@src/lang/create'
|
import { createLiteral } from '@src/lang/create'
|
||||||
import type {
|
import type {
|
||||||
@ -40,10 +40,9 @@ import { isOverlap } from '@src/lib/utils'
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await initPromise
|
await initPromise
|
||||||
|
|
||||||
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
|
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
engineCommandManager.start({
|
engineCommandManager.start({
|
||||||
token: VITE_KC_DEV_TOKEN,
|
token: env().VITE_KITTYCAD_API_TOKEN,
|
||||||
width: 256,
|
width: 256,
|
||||||
height: 256,
|
height: 256,
|
||||||
setMediaStream: () => {},
|
setMediaStream: () => {},
|
||||||
|
@ -4,16 +4,15 @@ import { initPromise } from '@src/lang/wasmUtils'
|
|||||||
import { err } from '@src/lib/trap'
|
import { err } from '@src/lib/trap'
|
||||||
import type { Selection } from '@src/lib/selections'
|
import type { Selection } from '@src/lib/selections'
|
||||||
import { engineCommandManager, kclManager } from '@src/lib/singletons'
|
import { engineCommandManager, kclManager } from '@src/lib/singletons'
|
||||||
import { VITE_KC_DEV_TOKEN } from '@src/env'
|
import env from '@src/env'
|
||||||
import { modifyAstWithTagsForSelection } from '@src/lang/modifyAst/tagManagement'
|
import { modifyAstWithTagsForSelection } from '@src/lang/modifyAst/tagManagement'
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await initPromise
|
await initPromise
|
||||||
|
|
||||||
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
|
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
engineCommandManager.start({
|
engineCommandManager.start({
|
||||||
token: VITE_KC_DEV_TOKEN,
|
token: env().VITE_KITTYCAD_API_TOKEN,
|
||||||
width: 256,
|
width: 256,
|
||||||
height: 256,
|
height: 256,
|
||||||
setMediaStream: () => {},
|
setMediaStream: () => {},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { Models } from '@kittycad/lib'
|
import type { Models } from '@kittycad/lib'
|
||||||
import { VITE_KC_API_WS_MODELING_URL, VITE_KC_DEV_TOKEN } from '@src/env'
|
import env from '@src/env'
|
||||||
import { jsAppSettings } from '@src/lib/settings/settingsUtils'
|
import { jsAppSettings } from '@src/lib/settings/settingsUtils'
|
||||||
import { BSON } from 'bson'
|
import { BSON } from 'bson'
|
||||||
|
|
||||||
@ -387,7 +387,7 @@ class EngineConnection extends EventTarget {
|
|||||||
|
|
||||||
// SHOULD ONLY BE USED FOR VITESTS
|
// SHOULD ONLY BE USED FOR VITESTS
|
||||||
connectLite(callback: () => void) {
|
connectLite(callback: () => void) {
|
||||||
const url = `${VITE_KC_API_WS_MODELING_URL}?video_res_width=${256}&video_res_height=${256}`
|
const url = `${env().VITE_KC_API_WS_MODELING_URL}?video_res_width=${256}&video_res_height=${256}`
|
||||||
|
|
||||||
this.websocket = new WebSocket(url, [])
|
this.websocket = new WebSocket(url, [])
|
||||||
this.websocket.binaryType = 'arraybuffer'
|
this.websocket.binaryType = 'arraybuffer'
|
||||||
@ -400,7 +400,7 @@ class EngineConnection extends EventTarget {
|
|||||||
this.send({
|
this.send({
|
||||||
type: 'headers',
|
type: 'headers',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${VITE_KC_DEV_TOKEN}`,
|
Authorization: `Bearer ${env().VITE_KITTYCAD_API_TOKEN}`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1531,7 +1531,7 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
additionalSettings +=
|
additionalSettings +=
|
||||||
'&show_grid=' + (this.settings.showScaleGrid ? 'true' : 'false')
|
'&show_grid=' + (this.settings.showScaleGrid ? 'true' : 'false')
|
||||||
const pool = !this.settings.pool ? '' : `&pool=${this.settings.pool}`
|
const pool = !this.settings.pool ? '' : `&pool=${this.settings.pool}`
|
||||||
const url = `${VITE_KC_API_WS_MODELING_URL}?video_res_width=${width}&video_res_height=${height}${additionalSettings}${pool}`
|
const url = `${env().VITE_KC_API_WS_MODELING_URL}?video_res_width=${width}&video_res_height=${height}${additionalSettings}${pool}`
|
||||||
this.engineConnection = new EngineConnection({
|
this.engineConnection = new EngineConnection({
|
||||||
engineCommandManager: this,
|
engineCommandManager: this,
|
||||||
url,
|
url,
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { VITE_KC_API_BASE_URL } from '@src/env'
|
|
||||||
import { UAParser } from 'ua-parser-js'
|
import { UAParser } from 'ua-parser-js'
|
||||||
|
|
||||||
import type { OsInfo } from '@rust/kcl-lib/bindings/OsInfo'
|
import type { OsInfo } from '@rust/kcl-lib/bindings/OsInfo'
|
||||||
@ -11,6 +10,7 @@ import { isDesktop } from '@src/lib/isDesktop'
|
|||||||
import type RustContext from '@src/lib/rustContext'
|
import type RustContext from '@src/lib/rustContext'
|
||||||
import screenshot from '@src/lib/screenshot'
|
import screenshot from '@src/lib/screenshot'
|
||||||
import { APP_VERSION } from '@src/routes/utils'
|
import { APP_VERSION } from '@src/routes/utils'
|
||||||
|
import { withAPIBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
/* eslint-disable suggest-no-throw/suggest-no-throw --
|
/* eslint-disable suggest-no-throw/suggest-no-throw --
|
||||||
* All the throws in CoreDumpManager are intentional and should be caught and handled properly
|
* All the throws in CoreDumpManager are intentional and should be caught and handled properly
|
||||||
@ -35,7 +35,7 @@ export class CoreDumpManager {
|
|||||||
codeManager: CodeManager
|
codeManager: CodeManager
|
||||||
rustContext: RustContext
|
rustContext: RustContext
|
||||||
token: string | undefined
|
token: string | undefined
|
||||||
baseUrl: string = VITE_KC_API_BASE_URL
|
baseUrl: string = withAPIBaseURL('')
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
engineCommandManager: EngineCommandManager,
|
engineCommandManager: EngineCommandManager,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { DEV } from '@src/env'
|
import env from '@src/env'
|
||||||
import type {
|
import type {
|
||||||
Actor,
|
Actor,
|
||||||
AnyStateMachine,
|
AnyStateMachine,
|
||||||
@ -89,7 +89,8 @@ export function createMachineCommand<
|
|||||||
} else if ('status' in commandConfig) {
|
} else if ('status' in commandConfig) {
|
||||||
const { status } = commandConfig
|
const { status } = commandConfig
|
||||||
if (status === 'inactive') return null
|
if (status === 'inactive') return null
|
||||||
if (status === 'development' && !(DEV || IS_STAGING_OR_DEBUG)) return null
|
if (status === 'development' && !(env().DEV || IS_STAGING_OR_DEBUG))
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const icon = ('icon' in commandConfig && commandConfig.icon) || undefined
|
const icon = ('icon' in commandConfig && commandConfig.icon) || undefined
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { DEV } from '@src/env'
|
import env from '@src/env'
|
||||||
import isomorphicFetch from 'isomorphic-fetch'
|
import isomorphicFetch from 'isomorphic-fetch'
|
||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ export default async function crossPlatformFetch<T>(
|
|||||||
// Add credentials: 'include' to options
|
// Add credentials: 'include' to options
|
||||||
// We send the token with the headers only in development mode, DO NOT
|
// We send the token with the headers only in development mode, DO NOT
|
||||||
// DO THIS IN PRODUCTION, as it is a security risk.
|
// DO THIS IN PRODUCTION, as it is a security risk.
|
||||||
opts.headers = headers(DEV ? token : undefined)
|
opts.headers = headers(env().DEV ? token : undefined)
|
||||||
opts.credentials = 'include'
|
opts.credentials = 'include'
|
||||||
response = await fetch(url, opts)
|
response = await fetch(url, opts)
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ import { err } from '@src/lib/trap'
|
|||||||
import type { DeepPartial } from '@src/lib/types'
|
import type { DeepPartial } from '@src/lib/types'
|
||||||
import { getInVariableCase } from '@src/lib/utils'
|
import { getInVariableCase } from '@src/lib/utils'
|
||||||
import { IS_STAGING } from '@src/routes/utils'
|
import { IS_STAGING } from '@src/routes/utils'
|
||||||
|
import { withAPIBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export async function renameProjectDirectory(
|
export async function renameProjectDirectory(
|
||||||
projectPath: string,
|
projectPath: string,
|
||||||
@ -697,7 +698,9 @@ export const readTokenFile = async () => {
|
|||||||
export const writeTokenFile = async (token: string) => {
|
export const writeTokenFile = async (token: string) => {
|
||||||
const tokenFilePath = await getTokenFilePath()
|
const tokenFilePath = await getTokenFilePath()
|
||||||
if (err(token)) return Promise.reject(token)
|
if (err(token)) return Promise.reject(token)
|
||||||
return window.electron.writeFile(tokenFilePath, token)
|
const result = window.electron.writeFile(tokenFilePath, token)
|
||||||
|
console.log('token written to disk')
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export const writeTelemetryFile = async (content: string) => {
|
export const writeTelemetryFile = async (content: string) => {
|
||||||
@ -722,12 +725,9 @@ export const setState = async (state: Project | undefined): Promise<void> => {
|
|||||||
appStateStore = state
|
appStateStore = state
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUser = async (
|
export const getUser = async (token: string): Promise<Models['User_type']> => {
|
||||||
token: string,
|
|
||||||
hostname: string
|
|
||||||
): Promise<Models['User_type']> => {
|
|
||||||
try {
|
try {
|
||||||
const user = await fetch(`${hostname}/users/me`, {
|
const user = await fetch(withAPIBaseURL('/users/me'), {
|
||||||
headers: new Headers({
|
headers: new Headers({
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
}),
|
}),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { VITE_KC_SITE_APP_URL } from '@src/env'
|
import env from '@src/env'
|
||||||
|
|
||||||
import { createCreateFileUrl } from '@src/lib/links'
|
import { createCreateFileUrl } from '@src/lib/links'
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ describe(`link creation tests`, () => {
|
|||||||
|
|
||||||
// Converted with external online tools
|
// Converted with external online tools
|
||||||
const expectedEncodedCode = `ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D`
|
const expectedEncodedCode = `ZXh0cnVzaW9uRGlzdGFuY2UgPSAxMg%3D%3D`
|
||||||
const expectedLink = `${VITE_KC_SITE_APP_URL}/?create-file=true&name=test&code=${expectedEncodedCode}&ask-open-desktop=true`
|
const expectedLink = `${env().VITE_KC_SITE_APP_URL}/?create-file=true&name=test&code=${expectedEncodedCode}&ask-open-desktop=true`
|
||||||
|
|
||||||
const result = createCreateFileUrl({ code, name, isRestrictedToOrg: false })
|
const result = createCreateFileUrl({ code, name, isRestrictedToOrg: false })
|
||||||
expect(result.toString()).toBe(expectedLink)
|
expect(result.toString()).toBe(expectedLink)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { VITE_KC_API_BASE_URL, VITE_KC_SITE_APP_URL } from '@src/env'
|
import env from '@src/env'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
|
|
||||||
import { stringToBase64 } from '@src/lib/base64'
|
import { stringToBase64 } from '@src/lib/base64'
|
||||||
@ -7,6 +7,7 @@ import {
|
|||||||
CREATE_FILE_URL_PARAM,
|
CREATE_FILE_URL_PARAM,
|
||||||
} from '@src/lib/constants'
|
} from '@src/lib/constants'
|
||||||
import { err } from '@src/lib/trap'
|
import { err } from '@src/lib/trap'
|
||||||
|
import { withAPIBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export interface FileLinkParams {
|
export interface FileLinkParams {
|
||||||
code: string
|
code: string
|
||||||
@ -57,7 +58,7 @@ export async function copyFileShareLink(
|
|||||||
* open the URL in the desktop app.
|
* open the URL in the desktop app.
|
||||||
*/
|
*/
|
||||||
export function createCreateFileUrl({ code, name }: FileLinkParams) {
|
export function createCreateFileUrl({ code, name }: FileLinkParams) {
|
||||||
let origin = VITE_KC_SITE_APP_URL
|
let origin = env().VITE_KC_SITE_APP_URL
|
||||||
const searchParams = new URLSearchParams({
|
const searchParams = new URLSearchParams({
|
||||||
[CREATE_FILE_URL_PARAM]: String(true),
|
[CREATE_FILE_URL_PARAM]: String(true),
|
||||||
name,
|
name,
|
||||||
@ -96,7 +97,7 @@ export async function createShortlink(
|
|||||||
if (password) {
|
if (password) {
|
||||||
body.password = password
|
body.password = password
|
||||||
}
|
}
|
||||||
const response = await fetch(`${VITE_KC_API_BASE_URL}/user/shortlinks`, {
|
const response = await fetch(withAPIBaseURL('/user/shortlinks'), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-type': 'application/json',
|
'Content-type': 'application/json',
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import type { SelectionRange } from '@codemirror/state'
|
import type { SelectionRange } from '@codemirror/state'
|
||||||
import { EditorSelection, Transaction } from '@codemirror/state'
|
import { EditorSelection, Transaction } from '@codemirror/state'
|
||||||
import type { Models } from '@kittycad/lib'
|
import type { Models } from '@kittycad/lib'
|
||||||
import { VITE_KC_API_BASE_URL, VITE_KC_SITE_BASE_URL } from '@src/env'
|
|
||||||
import { diffLines } from 'diff'
|
import { diffLines } from 'diff'
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import type { TextToCadMultiFileIteration_type } from '@kittycad/lib/dist/types/src/models'
|
import type { TextToCadMultiFileIteration_type } from '@kittycad/lib/dist/types/src/models'
|
||||||
@ -28,6 +27,8 @@ import { uuidv4 } from '@src/lib/utils'
|
|||||||
import type { File as KittyCadLibFile } from '@kittycad/lib/dist/types/src/models'
|
import type { File as KittyCadLibFile } from '@kittycad/lib/dist/types/src/models'
|
||||||
import type { FileMeta } from '@src/lib/types'
|
import type { FileMeta } from '@src/lib/types'
|
||||||
import type { RequestedKCLFile } from '@src/machines/systemIO/utils'
|
import type { RequestedKCLFile } from '@src/machines/systemIO/utils'
|
||||||
|
import { withAPIBaseURL, withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
import env from '@src/env'
|
||||||
|
|
||||||
type KclFileMetaMap = {
|
type KclFileMetaMap = {
|
||||||
[execStateFileNamesIndex: number]: Extract<FileMeta, { type: 'kcl' }>
|
[execStateFileNamesIndex: number]: Extract<FileMeta, { type: 'kcl' }>
|
||||||
@ -77,7 +78,7 @@ async function submitTextToCadRequest(
|
|||||||
})
|
})
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${VITE_KC_API_BASE_URL}/ml/text-to-cad/multi-file/iteration`,
|
withAPIBaseURL('/ml/text-to-cad/multi-file/iteration'),
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -304,7 +305,7 @@ export async function getPromptToEditResult(
|
|||||||
id: string,
|
id: string,
|
||||||
token?: string
|
token?: string
|
||||||
): Promise<Models['TextToCadMultiFileIteration_type'] | Error> {
|
): Promise<Models['TextToCadMultiFileIteration_type'] | Error> {
|
||||||
const url = VITE_KC_API_BASE_URL + '/async/operations/' + id
|
const url = withAPIBaseURL(`/async/operations/${id}`)
|
||||||
const data: Models['TextToCadMultiFileIteration_type'] | Error =
|
const data: Models['TextToCadMultiFileIteration_type'] | Error =
|
||||||
await crossPlatformFetch(
|
await crossPlatformFetch(
|
||||||
url,
|
url,
|
||||||
@ -340,7 +341,7 @@ export async function doPromptEdit({
|
|||||||
;(window as any).process = {
|
;(window as any).process = {
|
||||||
env: {
|
env: {
|
||||||
ZOO_API_TOKEN: token,
|
ZOO_API_TOKEN: token,
|
||||||
ZOO_HOST: VITE_KC_API_BASE_URL,
|
ZOO_HOST: withAPIBaseURL(''),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -438,7 +439,7 @@ export async function promptToEditFlow({
|
|||||||
return Promise.reject(result)
|
return Promise.reject(result)
|
||||||
}
|
}
|
||||||
const oldCodeWebAppOnly = codeManager.code
|
const oldCodeWebAppOnly = codeManager.code
|
||||||
const downloadLink = `${VITE_KC_SITE_BASE_URL}/${APP_DOWNLOAD_PATH}`
|
const downloadLink = withSiteBaseURL(`/${APP_DOWNLOAD_PATH}`)
|
||||||
|
|
||||||
if (!isDesktop() && Object.values(result.outputs).length > 1) {
|
if (!isDesktop() && Object.values(result.outputs).length > 1) {
|
||||||
const toastId = uuidv4()
|
const toastId = uuidv4()
|
||||||
|
@ -2,7 +2,7 @@ import type { Configuration } from '@rust/kcl-lib/bindings/Configuration'
|
|||||||
import type { NamedView } from '@rust/kcl-lib/bindings/NamedView'
|
import type { NamedView } from '@rust/kcl-lib/bindings/NamedView'
|
||||||
import type { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
|
import type { ProjectConfiguration } from '@rust/kcl-lib/bindings/ProjectConfiguration'
|
||||||
import { default_app_settings } from '@rust/kcl-wasm-lib/pkg/kcl_wasm_lib'
|
import { default_app_settings } from '@rust/kcl-wasm-lib/pkg/kcl_wasm_lib'
|
||||||
import { TEST } from '@src/env'
|
import env from '@src/env'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
defaultAppSettings,
|
defaultAppSettings,
|
||||||
@ -545,7 +545,7 @@ export function getSettingInputType(setting: Setting) {
|
|||||||
|
|
||||||
export const jsAppSettings = async (): Promise<DeepPartial<Configuration>> => {
|
export const jsAppSettings = async (): Promise<DeepPartial<Configuration>> => {
|
||||||
let jsAppSettings = default_app_settings()
|
let jsAppSettings = default_app_settings()
|
||||||
if (!TEST) {
|
if (!env().TEST) {
|
||||||
// TODO: https://github.com/KittyCAD/modeling-app/issues/6445
|
// TODO: https://github.com/KittyCAD/modeling-app/issues/6445
|
||||||
const settings = await import('@src/lib/singletons').then((module) =>
|
const settings = await import('@src/lib/singletons').then((module) =>
|
||||||
module.getSettings()
|
module.getSettings()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { VITE_KC_API_BASE_URL } from '@src/env'
|
import { withAPIBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
import EditorManager from '@src/editor/manager'
|
import EditorManager from '@src/editor/manager'
|
||||||
import { KclManager } from '@src/lang/KclSingleton'
|
import { KclManager } from '@src/lang/KclSingleton'
|
||||||
@ -171,7 +171,7 @@ const appMachine = setup({
|
|||||||
systemId: BILLING,
|
systemId: BILLING,
|
||||||
input: {
|
input: {
|
||||||
...BILLING_CONTEXT_DEFAULTS,
|
...BILLING_CONTEXT_DEFAULTS,
|
||||||
urlUserService: VITE_KC_API_BASE_URL,
|
urlUserService: withAPIBaseURL(''),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import type { Models } from '@kittycad/lib'
|
import type { Models } from '@kittycad/lib'
|
||||||
import { VITE_KC_API_BASE_URL } from '@src/env'
|
|
||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import type { NavigateFunction } from 'react-router-dom'
|
import type { NavigateFunction } from 'react-router-dom'
|
||||||
import {
|
import {
|
||||||
@ -19,6 +18,7 @@ import { err, reportRejection } from '@src/lib/trap'
|
|||||||
import { toSync } from '@src/lib/utils'
|
import { toSync } from '@src/lib/utils'
|
||||||
import { getAllSubDirectoriesAtProjectRoot } from '@src/machines/systemIO/snapshotContext'
|
import { getAllSubDirectoriesAtProjectRoot } from '@src/machines/systemIO/snapshotContext'
|
||||||
import { joinOSPaths } from '@src/lib/paths'
|
import { joinOSPaths } from '@src/lib/paths'
|
||||||
|
import { withAPIBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export async function submitTextToCadPrompt(
|
export async function submitTextToCadPrompt(
|
||||||
prompt: string,
|
prompt: string,
|
||||||
@ -32,7 +32,7 @@ export async function submitTextToCadPrompt(
|
|||||||
kcl_version: kclManager.kclVersion,
|
kcl_version: kclManager.kclVersion,
|
||||||
}
|
}
|
||||||
// Glb has a smaller footprint than gltf, should we want to render it.
|
// Glb has a smaller footprint than gltf, should we want to render it.
|
||||||
const url = VITE_KC_API_BASE_URL + '/ai/text-to-cad/glb?kcl=true'
|
const url = withAPIBaseURL('/ai/text-to-cad/glb?kcl=true')
|
||||||
const data: Models['TextToCad_type'] | Error = await crossPlatformFetch(
|
const data: Models['TextToCad_type'] | Error = await crossPlatformFetch(
|
||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
@ -58,7 +58,7 @@ export async function getTextToCadResult(
|
|||||||
id: string,
|
id: string,
|
||||||
token?: string
|
token?: string
|
||||||
): Promise<Models['TextToCad_type'] | Error> {
|
): Promise<Models['TextToCad_type'] | Error> {
|
||||||
const url = VITE_KC_API_BASE_URL + '/user/text-to-cad/' + id
|
const url = withAPIBaseURL(`/user/text-to-cad/${id}`)
|
||||||
const data: Models['TextToCad_type'] | Error = await crossPlatformFetch(
|
const data: Models['TextToCad_type'] | Error = await crossPlatformFetch(
|
||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import type { Models } from '@kittycad/lib/dist/types/src'
|
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 crossPlatformFetch from '@src/lib/crossPlatformFetch'
|
||||||
|
import { withAPIBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export async function sendTelemetry(
|
export async function sendTelemetry(
|
||||||
id: string,
|
id: string,
|
||||||
feedback: Models['MlFeedback_type'],
|
feedback: Models['MlFeedback_type'],
|
||||||
token?: string
|
token?: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const url =
|
const url = withAPIBaseURL(`/user/text-to-cad/${id}?feedback=${feedback}`)
|
||||||
VITE_KC_API_BASE_URL + '/user/text-to-cad/' + id + '?feedback=' + feedback
|
|
||||||
await crossPlatformFetch(
|
await crossPlatformFetch(
|
||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
pipeHasCircle,
|
pipeHasCircle,
|
||||||
} from '@src/machines/modelingMachine'
|
} from '@src/machines/modelingMachine'
|
||||||
import { IS_ML_EXPERIMENTAL } from '@src/lib/constants'
|
import { IS_ML_EXPERIMENTAL } from '@src/lib/constants'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export type ToolbarModeName = 'modeling' | 'sketching'
|
export type ToolbarModeName = 'modeling' | 'sketching'
|
||||||
|
|
||||||
@ -105,7 +106,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-sketch-startSketchOn',
|
url: withSiteBaseURL(
|
||||||
|
'/docs/kcl-std/functions/std-sketch-startSketchOn'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -125,7 +128,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-sketch-extrude',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-sketch-extrude'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -145,7 +148,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-sketch-sweep',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-sketch-sweep'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -165,7 +168,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-sketch-loft',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-sketch-loft'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -185,11 +188,11 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-sketch-revolve',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-sketch-revolve'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'KCL example',
|
label: 'KCL example',
|
||||||
url: 'https://zoo.dev/docs/kcl-samples/ball-bearing',
|
url: withSiteBaseURL('/docs/kcl-samples/ball-bearing'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -209,7 +212,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-solid-fillet',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-solid-fillet'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -234,7 +237,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-solid-chamfer',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-solid-chamfer'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -253,7 +256,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-solid-shell',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-solid-shell'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -275,7 +278,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-solid-union',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-solid-union'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -293,7 +296,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-solid-subtract',
|
url: withSiteBaseURL(
|
||||||
|
'/docs/kcl-std/functions/std-solid-subtract'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -311,7 +316,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-solid-intersect',
|
url: withSiteBaseURL(
|
||||||
|
'/docs/kcl-std/functions/std-solid-intersect'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -337,7 +344,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-offsetPlane',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-offsetPlane'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -368,7 +375,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-helix',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-helix'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -389,7 +396,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'API docs',
|
label: 'API docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-lang/modules',
|
url: withSiteBaseURL('/docs/kcl-lang/modules'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -410,7 +417,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'API docs',
|
label: 'API docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-transform-translate',
|
url: withSiteBaseURL(
|
||||||
|
'/docs/kcl-std/functions/std-transform-translate'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -428,7 +437,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'API docs',
|
label: 'API docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-transform-rotate',
|
url: withSiteBaseURL(
|
||||||
|
'/docs/kcl-std/functions/std-transform-rotate'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -446,7 +457,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'API docs',
|
label: 'API docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-clone',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-clone'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -482,7 +493,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'API docs',
|
label: 'API docs',
|
||||||
url: 'https://zoo.dev/docs/api/ml/generate-a-cad-model-from-text',
|
url: withSiteBaseURL(
|
||||||
|
'/docs/api/ml/generate-a-cad-model-from-text'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -739,7 +752,7 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-sketch-polygon',
|
url: withSiteBaseURL('/docs/kcl-std/functions/std-sketch-polygon'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -755,7 +768,9 @@ export const toolbarConfig: Record<ToolbarModeName, ToolbarMode> = {
|
|||||||
links: [
|
links: [
|
||||||
{
|
{
|
||||||
label: 'KCL docs',
|
label: 'KCL docs',
|
||||||
url: 'https://zoo.dev/docs/kcl-std/functions/std-transform-mirror2d',
|
url: withSiteBaseURL(
|
||||||
|
'/docs/kcl-std/functions/std-transform-mirror2d'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
61
src/lib/withBaseURL.test.ts
Normal file
61
src/lib/withBaseURL.test.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { withAPIBaseURL, withSiteBaseURL } 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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('withSiteBaseURL', () => {
|
||||||
|
it('should return base url', () => {
|
||||||
|
const expected = 'https://dev.zoo.dev'
|
||||||
|
const actual = withSiteBaseURL('')
|
||||||
|
expect(actual).toBe(expected)
|
||||||
|
})
|
||||||
|
it('should return base url with /docs', () => {
|
||||||
|
const expected = 'https://dev.zoo.dev/docs'
|
||||||
|
const actual = withSiteBaseURL('/docs')
|
||||||
|
expect(actual).toBe(expected)
|
||||||
|
})
|
||||||
|
it('should return a longer base base url with /docs/kcl-samples/car-wheel-assembly', () => {
|
||||||
|
const expected = 'https://dev.zoo.dev/docs/kcl-samples/car-wheel-assembly'
|
||||||
|
const actual = withSiteBaseURL('/docs/kcl-samples/car-wheel-assembly')
|
||||||
|
expect(actual).toBe(expected)
|
||||||
|
})
|
||||||
|
it('should ensure base url does not have ending slash', () => {
|
||||||
|
const expected = 'https://dev.zoo.dev'
|
||||||
|
const actual = withSiteBaseURL('')
|
||||||
|
expect(actual).toBe(expected)
|
||||||
|
const expectedEndsWith = expected[expected.length - 1]
|
||||||
|
const actualEndsWith = actual[actual.length - 1]
|
||||||
|
expect(actual).toBe(expected)
|
||||||
|
expect(actualEndsWith).toBe(expectedEndsWith)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -1,5 +1,9 @@
|
|||||||
import { VITE_KC_API_BASE_URL } from '@src/env'
|
import env from '@src/env'
|
||||||
|
|
||||||
export default function withBaseUrl(path: string): string {
|
export function withAPIBaseURL(path: string): string {
|
||||||
return VITE_KC_API_BASE_URL + path
|
return env().VITE_KITTYCAD_API_BASE_URL + path
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withSiteBaseURL(path: string): string {
|
||||||
|
return env().VITE_KC_SITE_BASE_URL + path
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
import type { Models } from '@kittycad/lib'
|
import type { Models } from '@kittycad/lib'
|
||||||
import {
|
import env from '@src/env'
|
||||||
DEV,
|
|
||||||
VITE_KC_API_BASE_URL,
|
|
||||||
VITE_KC_DEV_TOKEN,
|
|
||||||
VITE_KC_SKIP_AUTH,
|
|
||||||
} from '@src/env'
|
|
||||||
import { assign, fromPromise, setup } from 'xstate'
|
import { assign, fromPromise, setup } from 'xstate'
|
||||||
|
|
||||||
import { COOKIE_NAME, OAUTH2_DEVICE_CLIENT_ID } from '@src/lib/constants'
|
import { COOKIE_NAME, OAUTH2_DEVICE_CLIENT_ID } from '@src/lib/constants'
|
||||||
@ -15,32 +10,9 @@ import {
|
|||||||
} from '@src/lib/desktop'
|
} from '@src/lib/desktop'
|
||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
import { markOnce } from '@src/lib/performance'
|
import { markOnce } from '@src/lib/performance'
|
||||||
import {
|
import { withAPIBaseURL } from '@src/lib/withBaseURL'
|
||||||
default as withBaseURL,
|
|
||||||
default as withBaseUrl,
|
|
||||||
} from '@src/lib/withBaseURL'
|
|
||||||
import { ACTOR_IDS } from '@src/machines/machineConstants'
|
import { ACTOR_IDS } from '@src/machines/machineConstants'
|
||||||
|
|
||||||
const SKIP_AUTH = VITE_KC_SKIP_AUTH === 'true' && DEV
|
|
||||||
|
|
||||||
const LOCAL_USER: Models['User_type'] = {
|
|
||||||
id: '8675309',
|
|
||||||
name: 'Test User',
|
|
||||||
email: 'kittycad.sidebar.test@example.com',
|
|
||||||
image: 'https://placekitten.com/200/200',
|
|
||||||
created_at: 'yesteryear',
|
|
||||||
updated_at: 'today',
|
|
||||||
company: 'Test Company',
|
|
||||||
discord: 'Test User#1234',
|
|
||||||
github: 'testuser',
|
|
||||||
phone: '555-555-5555',
|
|
||||||
first_name: 'Test',
|
|
||||||
last_name: 'User',
|
|
||||||
can_train_on_data: false,
|
|
||||||
is_service_account: false,
|
|
||||||
deletion_scheduled: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserContext {
|
export interface UserContext {
|
||||||
user?: Models['User_type']
|
user?: Models['User_type']
|
||||||
token: string
|
token: string
|
||||||
@ -56,11 +28,21 @@ export type Events =
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const TOKEN_PERSIST_KEY = 'TOKEN_PERSIST_KEY'
|
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 = env().VITE_KITTYCAD_API_TOKEN
|
||||||
export const persistedToken =
|
export const persistedToken =
|
||||||
VITE_KC_DEV_TOKEN ||
|
persistedDevToken || persistedCookie || persistedLocalStorage
|
||||||
getCookie(COOKIE_NAME) ||
|
console.log('Initial persisted token')
|
||||||
localStorage?.getItem(TOKEN_PERSIST_KEY) ||
|
console.table([
|
||||||
''
|
['cookie', !!persistedCookie],
|
||||||
|
['local storage', !!persistedLocalStorage],
|
||||||
|
['api token', !!persistedDevToken],
|
||||||
|
])
|
||||||
|
|
||||||
export const authMachine = setup({
|
export const authMachine = setup({
|
||||||
types: {} as {
|
types: {} as {
|
||||||
@ -157,7 +139,7 @@ export const authMachine = setup({
|
|||||||
|
|
||||||
async function getUser(input: { token?: string }) {
|
async function getUser(input: { token?: string }) {
|
||||||
const token = await getAndSyncStoredToken(input)
|
const token = await getAndSyncStoredToken(input)
|
||||||
const url = withBaseURL('/user')
|
const url = withAPIBaseURL('/user')
|
||||||
const headers: { [key: string]: string } = {
|
const headers: { [key: string]: string } = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
}
|
}
|
||||||
@ -165,21 +147,8 @@ async function getUser(input: { token?: string }) {
|
|||||||
if (!token && isDesktop()) return Promise.reject(new Error('No token found'))
|
if (!token && isDesktop()) return Promise.reject(new Error('No token found'))
|
||||||
if (token) headers['Authorization'] = `Bearer ${token}`
|
if (token) headers['Authorization'] = `Bearer ${token}`
|
||||||
|
|
||||||
if (SKIP_AUTH) {
|
|
||||||
// For local tests
|
|
||||||
if (localStorage.getItem('FORCE_NO_IMAGE')) {
|
|
||||||
LOCAL_USER.image = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
markOnce('code/didAuth')
|
|
||||||
return {
|
|
||||||
user: LOCAL_USER,
|
|
||||||
token,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const userPromise = isDesktop()
|
const userPromise = isDesktop()
|
||||||
? getUserDesktop(token, VITE_KC_API_BASE_URL)
|
? getUserDesktop(token)
|
||||||
: fetch(url, {
|
: fetch(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
@ -228,12 +197,25 @@ async function getAndSyncStoredToken(input: {
|
|||||||
token?: string
|
token?: string
|
||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
// dev mode
|
// dev mode
|
||||||
if (VITE_KC_DEV_TOKEN) return VITE_KC_DEV_TOKEN
|
const VITE_KITTYCAD_API_TOKEN = env().VITE_KITTYCAD_API_TOKEN
|
||||||
|
if (VITE_KITTYCAD_API_TOKEN) {
|
||||||
|
console.log('Token used for authentication')
|
||||||
|
console.table([['api token', !!VITE_KITTYCAD_API_TOKEN]])
|
||||||
|
return VITE_KITTYCAD_API_TOKEN
|
||||||
|
}
|
||||||
|
|
||||||
const token =
|
const inputToken = input.token && input.token !== '' ? input.token : ''
|
||||||
input.token && input.token !== ''
|
const cookieToken = getCookie(COOKIE_NAME)
|
||||||
? input.token
|
const localStorageToken = localStorage?.getItem(TOKEN_PERSIST_KEY) || ''
|
||||||
: getCookie(COOKIE_NAME) || 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],
|
||||||
|
])
|
||||||
if (token) {
|
if (token) {
|
||||||
// has just logged in, update storage
|
// has just logged in, update storage
|
||||||
localStorage.setItem(TOKEN_PERSIST_KEY, token)
|
localStorage.setItem(TOKEN_PERSIST_KEY, token)
|
||||||
@ -259,7 +241,7 @@ async function logout() {
|
|||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
try {
|
try {
|
||||||
await fetch(withBaseUrl('/oauth2/token/revoke'), {
|
await fetch(withAPIBaseURL('/oauth2/token/revoke'), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
headers: {
|
headers: {
|
||||||
@ -282,7 +264,7 @@ async function logout() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(withBaseUrl('/logout'), {
|
return fetch(withAPIBaseURL('/logout'), {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
credentials: 'include',
|
credentials: 'include',
|
||||||
})
|
})
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
engineCommandManager,
|
engineCommandManager,
|
||||||
kclManager,
|
kclManager,
|
||||||
} from '@src/lib/singletons'
|
} from '@src/lib/singletons'
|
||||||
import { VITE_KC_DEV_TOKEN } from '@src/env'
|
import env from '@src/env'
|
||||||
import { getConstraintInfoKw } from '@src/lang/std/sketch'
|
import { getConstraintInfoKw } from '@src/lang/std/sketch'
|
||||||
import { getNodeFromPath } from '@src/lang/queryAst'
|
import { getNodeFromPath } from '@src/lang/queryAst'
|
||||||
import type { Node } from '@rust/kcl-lib/bindings/Node'
|
import type { Node } from '@rust/kcl-lib/bindings/Node'
|
||||||
@ -29,10 +29,9 @@ import { removeSingleConstraintInfo } from '@src/lang/modifyAst'
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await initPromise
|
await initPromise
|
||||||
|
|
||||||
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
|
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
engineCommandManager.start({
|
engineCommandManager.start({
|
||||||
token: VITE_KC_DEV_TOKEN,
|
token: env().VITE_KITTYCAD_API_TOKEN,
|
||||||
width: 256,
|
width: 256,
|
||||||
height: 256,
|
height: 256,
|
||||||
setMediaStream: () => {},
|
setMediaStream: () => {},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { engineCommandManager, kclManager } from '@src/lib/singletons'
|
import { engineCommandManager, kclManager } from '@src/lib/singletons'
|
||||||
import { VITE_KC_DEV_TOKEN } from '@src/env'
|
import env from '@src/env'
|
||||||
import { getModuleIdByFileName, isArray } from '@src/lib/utils'
|
import { getModuleIdByFileName, isArray } from '@src/lib/utils'
|
||||||
import { vi, inject } from 'vitest'
|
import { vi, inject } from 'vitest'
|
||||||
import { assertParse } from '@src/lang/wasm'
|
import { assertParse } from '@src/lang/wasm'
|
||||||
@ -355,10 +355,9 @@ cases.push(
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await initPromise
|
await initPromise
|
||||||
|
|
||||||
// THESE TEST WILL FAIL without VITE_KC_DEV_TOKEN set in .env.development.local
|
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
engineCommandManager.start({
|
engineCommandManager.start({
|
||||||
token: VITE_KC_DEV_TOKEN,
|
token: env().VITE_KITTYCAD_API_TOKEN,
|
||||||
width: 256,
|
width: 256,
|
||||||
height: 256,
|
height: 256,
|
||||||
setMediaStream: () => {},
|
setMediaStream: () => {},
|
||||||
|
@ -70,12 +70,10 @@ dotenv.config({ path: [`.env.${NODE_ENV}.local`, `.env.${NODE_ENV}`] })
|
|||||||
|
|
||||||
// default vite values based on mode
|
// default vite values based on mode
|
||||||
process.env.NODE_ENV ??= viteEnv.MODE
|
process.env.NODE_ENV ??= viteEnv.MODE
|
||||||
process.env.BASE_URL ??= viteEnv.VITE_KC_API_BASE_URL
|
|
||||||
process.env.VITE_KC_API_WS_MODELING_URL ??= viteEnv.VITE_KC_API_WS_MODELING_URL
|
process.env.VITE_KC_API_WS_MODELING_URL ??= viteEnv.VITE_KC_API_WS_MODELING_URL
|
||||||
process.env.VITE_KC_API_BASE_URL ??= viteEnv.VITE_KC_API_BASE_URL
|
process.env.VITE_KITTYCAD_API_BASE_URL ??= viteEnv.VITE_KITTYCAD_API_BASE_URL
|
||||||
process.env.VITE_KC_SITE_BASE_URL ??= viteEnv.VITE_KC_SITE_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_SITE_APP_URL ??= viteEnv.VITE_KC_SITE_APP_URL
|
||||||
process.env.VITE_KC_SKIP_AUTH ??= viteEnv.VITE_KC_SKIP_AUTH
|
|
||||||
process.env.VITE_KC_CONNECTION_TIMEOUT_MS ??=
|
process.env.VITE_KC_CONNECTION_TIMEOUT_MS ??=
|
||||||
viteEnv.VITE_KC_CONNECTION_TIMEOUT_MS
|
viteEnv.VITE_KC_CONNECTION_TIMEOUT_MS
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { reportRejection } from '@src/lib/trap'
|
|||||||
import { typeSafeWebContentsSend } from '@src/menu/channels'
|
import { typeSafeWebContentsSend } from '@src/menu/channels'
|
||||||
import type { ZooMenuItemConstructorOptions } from '@src/menu/roles'
|
import type { ZooMenuItemConstructorOptions } from '@src/menu/roles'
|
||||||
import { getAutoUpdater } from '@src/updater'
|
import { getAutoUpdater } from '@src/updater'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
export const helpRole = (
|
export const helpRole = (
|
||||||
mainWindow: BrowserWindow
|
mainWindow: BrowserWindow
|
||||||
@ -26,14 +27,16 @@ export const helpRole = (
|
|||||||
id: 'Help.KCL code samples',
|
id: 'Help.KCL code samples',
|
||||||
click: () => {
|
click: () => {
|
||||||
shell
|
shell
|
||||||
.openExternal('https://zoo.dev/docs/kcl-samples')
|
.openExternal(withSiteBaseURL('/docs/kcl-samples'))
|
||||||
.catch(reportRejection)
|
.catch(reportRejection)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'KCL Docs',
|
label: 'KCL Docs',
|
||||||
click: () => {
|
click: () => {
|
||||||
shell.openExternal('https://zoo.dev/docs/kcl').catch(reportRejection)
|
shell
|
||||||
|
.openExternal(withSiteBaseURL('/docs/kcl'))
|
||||||
|
.catch(reportRejection)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -116,7 +119,7 @@ export const helpRole = (
|
|||||||
{
|
{
|
||||||
label: 'Manage Account',
|
label: 'Manage Account',
|
||||||
click: () => {
|
click: () => {
|
||||||
shell.openExternal('https://zoo.dev/account').catch(reportRejection)
|
shell.openExternal(withSiteBaseURL('/account')).catch(reportRejection)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -289,12 +289,11 @@ contextBridge.exposeInMainWorld('electron', {
|
|||||||
exposeProcessEnvs([
|
exposeProcessEnvs([
|
||||||
'NODE_ENV',
|
'NODE_ENV',
|
||||||
'VITE_KC_API_WS_MODELING_URL',
|
'VITE_KC_API_WS_MODELING_URL',
|
||||||
'VITE_KC_API_BASE_URL',
|
'VITE_KITTYCAD_API_BASE_URL',
|
||||||
'VITE_KC_SITE_BASE_URL',
|
'VITE_KC_SITE_BASE_URL',
|
||||||
'VITE_KC_SITE_APP_URL',
|
'VITE_KC_SITE_APP_URL',
|
||||||
'VITE_KC_SKIP_AUTH',
|
|
||||||
'VITE_KC_CONNECTION_TIMEOUT_MS',
|
'VITE_KC_CONNECTION_TIMEOUT_MS',
|
||||||
'VITE_KC_DEV_TOKEN',
|
'VITE_KITTYCAD_API_TOKEN',
|
||||||
|
|
||||||
'IS_PLAYWRIGHT',
|
'IS_PLAYWRIGHT',
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ import {
|
|||||||
defaultGlobalStatusBarItems,
|
defaultGlobalStatusBarItems,
|
||||||
} from '@src/components/StatusBar/defaultStatusBarItems'
|
} from '@src/components/StatusBar/defaultStatusBarItems'
|
||||||
import { useSelector } from '@xstate/react'
|
import { useSelector } from '@xstate/react'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
type ReadWriteProjectState = {
|
type ReadWriteProjectState = {
|
||||||
value: boolean
|
value: boolean
|
||||||
@ -367,9 +368,9 @@ const Home = () => {
|
|||||||
<li className="contents">
|
<li className="contents">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
to="https://zoo.dev/docs"
|
to={withSiteBaseURL('/account')}
|
||||||
onClick={openExternalBrowserIfDesktop(
|
onClick={openExternalBrowserIfDesktop(
|
||||||
'https://zoo.dev/account'
|
withSiteBaseURL('/account')
|
||||||
)}
|
)}
|
||||||
className={sidebarButtonClasses}
|
className={sidebarButtonClasses}
|
||||||
iconStart={{
|
iconStart={{
|
||||||
@ -384,8 +385,8 @@ const Home = () => {
|
|||||||
<li className="contents">
|
<li className="contents">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
to="https://zoo.dev/blog"
|
to={withSiteBaseURL('/blog')}
|
||||||
onClick={openExternalBrowserIfDesktop('https://zoo.dev/blog')}
|
onClick={openExternalBrowserIfDesktop(withSiteBaseURL('/blog'))}
|
||||||
className={sidebarButtonClasses}
|
className={sidebarButtonClasses}
|
||||||
iconStart={{
|
iconStart={{
|
||||||
icon: 'glasses',
|
icon: 'glasses',
|
||||||
|
@ -25,12 +25,12 @@ import { systemIOActor, commandBarActor } from '@src/lib/singletons'
|
|||||||
import type { IndexLoaderData } from '@src/lib/types'
|
import type { IndexLoaderData } from '@src/lib/types'
|
||||||
import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
|
import { SystemIOMachineEvents } from '@src/machines/systemIO/utils'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { VITE_KC_SITE_BASE_URL } from '@src/env'
|
|
||||||
import { openExternalBrowserIfDesktop } from '@src/lib/openWindow'
|
import { openExternalBrowserIfDesktop } from '@src/lib/openWindow'
|
||||||
import {
|
import {
|
||||||
browserAxialFan,
|
browserAxialFan,
|
||||||
browserAxialFanAfterTextToCad,
|
browserAxialFanAfterTextToCad,
|
||||||
} from '@src/lib/exampleKcl'
|
} from '@src/lib/exampleKcl'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
type BrowserOnboaringRoute = RouteObject & {
|
type BrowserOnboaringRoute = RouteObject & {
|
||||||
path: keyof typeof browserOnboardingPaths
|
path: keyof typeof browserOnboardingPaths
|
||||||
@ -461,7 +461,7 @@ function PromptToEditResult() {
|
|||||||
function OnboardingConclusion() {
|
function OnboardingConclusion() {
|
||||||
// Close the panes on mount, close on unmount
|
// Close the panes on mount, close on unmount
|
||||||
useOnboardingPanes()
|
useOnboardingPanes()
|
||||||
const downloadLink = `${VITE_KC_SITE_BASE_URL}/${APP_DOWNLOAD_PATH}`
|
const downloadLink = withSiteBaseURL(`/${APP_DOWNLOAD_PATH}`)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="cursor-not-allowed fixed inset-0 z-50 p-16 grid justify-center items-center">
|
<div className="cursor-not-allowed fixed inset-0 z-50 p-16 grid justify-center items-center">
|
||||||
|
@ -27,8 +27,8 @@ import {
|
|||||||
modifiedFanHousingBrowser,
|
modifiedFanHousingBrowser,
|
||||||
modifiedParametersDesktop,
|
modifiedParametersDesktop,
|
||||||
} from '@src/lib/exampleKcl'
|
} from '@src/lib/exampleKcl'
|
||||||
import { VITE_KC_SITE_BASE_URL } from '@src/env'
|
|
||||||
import { openExternalBrowserIfDesktop } from '@src/lib/openWindow'
|
import { openExternalBrowserIfDesktop } from '@src/lib/openWindow'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
type DesktopOnboardingRoute = RouteObject & {
|
type DesktopOnboardingRoute = RouteObject & {
|
||||||
path: keyof typeof desktopOnboardingPaths
|
path: keyof typeof desktopOnboardingPaths
|
||||||
@ -642,10 +642,8 @@ function OnboardingConclusion() {
|
|||||||
project, click the Zoo button in the top left. To learn more detailed
|
project, click the Zoo button in the top left. To learn more detailed
|
||||||
and advanced techniques,{' '}
|
and advanced techniques,{' '}
|
||||||
<a
|
<a
|
||||||
onClick={openExternalBrowserIfDesktop(
|
onClick={openExternalBrowserIfDesktop(withSiteBaseURL('/docs'))}
|
||||||
`${VITE_KC_SITE_BASE_URL}/docs`
|
href={`${withSiteBaseURL('/docs')}`}
|
||||||
)}
|
|
||||||
href={`${VITE_KC_SITE_BASE_URL}/docs`}
|
|
||||||
>
|
>
|
||||||
check out our docs
|
check out our docs
|
||||||
</a>
|
</a>
|
||||||
|
@ -6,7 +6,6 @@ import { Link } from 'react-router-dom'
|
|||||||
import { ActionButton } from '@src/components/ActionButton'
|
import { ActionButton } from '@src/components/ActionButton'
|
||||||
import { CustomIcon } from '@src/components/CustomIcon'
|
import { CustomIcon } from '@src/components/CustomIcon'
|
||||||
import { Logo } from '@src/components/Logo'
|
import { Logo } from '@src/components/Logo'
|
||||||
import { VITE_KC_API_BASE_URL, VITE_KC_SITE_BASE_URL } from '@src/env'
|
|
||||||
import { APP_NAME } from '@src/lib/constants'
|
import { APP_NAME } from '@src/lib/constants'
|
||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
import { openExternalBrowserIfDesktop } from '@src/lib/openWindow'
|
import { openExternalBrowserIfDesktop } from '@src/lib/openWindow'
|
||||||
@ -15,6 +14,7 @@ import { reportRejection } from '@src/lib/trap'
|
|||||||
import { toSync } from '@src/lib/utils'
|
import { toSync } from '@src/lib/utils'
|
||||||
import { authActor, useSettings } from '@src/lib/singletons'
|
import { authActor, useSettings } from '@src/lib/singletons'
|
||||||
import { APP_VERSION, generateSignInUrl } from '@src/routes/utils'
|
import { APP_VERSION, generateSignInUrl } from '@src/routes/utils'
|
||||||
|
import { withAPIBaseURL, withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
const subtleBorder =
|
const subtleBorder =
|
||||||
'border border-solid border-chalkboard-30 dark:border-chalkboard-80'
|
'border border-solid border-chalkboard-30 dark:border-chalkboard-80'
|
||||||
@ -36,7 +36,7 @@ const SignIn = () => {
|
|||||||
app: { theme },
|
app: { theme },
|
||||||
} = useSettings()
|
} = useSettings()
|
||||||
const signInUrl = generateSignInUrl()
|
const signInUrl = generateSignInUrl()
|
||||||
const kclSampleUrl = `${VITE_KC_SITE_BASE_URL}/docs/kcl-samples/car-wheel-assembly`
|
const kclSampleUrl = withSiteBaseURL('/docs/kcl-samples/car-wheel-assembly')
|
||||||
|
|
||||||
const getThemeText = useCallback(
|
const getThemeText = useCallback(
|
||||||
(shouldContrast = true) =>
|
(shouldContrast = true) =>
|
||||||
@ -54,7 +54,7 @@ const SignIn = () => {
|
|||||||
const signInDesktop = async () => {
|
const signInDesktop = async () => {
|
||||||
// We want to invoke our command to login via device auth.
|
// We want to invoke our command to login via device auth.
|
||||||
const userCodeToDisplay = await window.electron
|
const userCodeToDisplay = await window.electron
|
||||||
.startDeviceFlow(VITE_KC_API_BASE_URL + location.search)
|
.startDeviceFlow(withAPIBaseURL(location.search))
|
||||||
.catch(reportError)
|
.catch(reportError)
|
||||||
if (!userCodeToDisplay) {
|
if (!userCodeToDisplay) {
|
||||||
console.error('No user code received while trying to log in')
|
console.error('No user code received while trying to log in')
|
||||||
@ -260,7 +260,7 @@ const SignIn = () => {
|
|||||||
<div className="flex gap-4 flex-wrap items-center">
|
<div className="flex gap-4 flex-wrap items-center">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
to="https://zoo.dev/docs/kcl-samples/pillow-block-bearing"
|
to={withSiteBaseURL('/docs/kcl-samples/pillow-block-bearing')}
|
||||||
iconStart={{
|
iconStart={{
|
||||||
icon: 'settings',
|
icon: 'settings',
|
||||||
bgClassName: '!bg-transparent',
|
bgClassName: '!bg-transparent',
|
||||||
@ -273,7 +273,7 @@ const SignIn = () => {
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
to="https://zoo.dev/docs/zoo-design-studio/text-to-cad"
|
to={withSiteBaseURL('/docs/zoo-design-studio/text-to-cad')}
|
||||||
iconStart={{
|
iconStart={{
|
||||||
icon: 'sparkles',
|
icon: 'sparkles',
|
||||||
bgClassName: '!bg-transparent',
|
bgClassName: '!bg-transparent',
|
||||||
@ -296,7 +296,7 @@ const SignIn = () => {
|
|||||||
<div className="flex gap-4 flex-wrap items-center">
|
<div className="flex gap-4 flex-wrap items-center">
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
to="https://zoo.dev/design-api"
|
to={withSiteBaseURL('/design-api')}
|
||||||
iconStart={{ icon: 'sketch', bgClassName: '!bg-transparent' }}
|
iconStart={{ icon: 'sketch', bgClassName: '!bg-transparent' }}
|
||||||
className="!bg-primary !text-chalkboard-10 !border-transarent"
|
className="!bg-primary !text-chalkboard-10 !border-transarent"
|
||||||
>
|
>
|
||||||
@ -304,7 +304,7 @@ const SignIn = () => {
|
|||||||
</ActionButton>
|
</ActionButton>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
Element="externalLink"
|
Element="externalLink"
|
||||||
to="https://zoo.dev/machine-learning-api"
|
to={withSiteBaseURL('/machine-learning-api')}
|
||||||
iconStart={{
|
iconStart={{
|
||||||
icon: 'elephant',
|
icon: 'elephant',
|
||||||
bgClassName: '!bg-transparent',
|
bgClassName: '!bg-transparent',
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import { NODE_ENV, VITE_KC_SITE_BASE_URL } from '@src/env'
|
import env from '@src/env'
|
||||||
import { isDesktop } from '@src/lib/isDesktop'
|
import { isDesktop } from '@src/lib/isDesktop'
|
||||||
import {
|
import {
|
||||||
IS_PLAYWRIGHT_KEY,
|
IS_PLAYWRIGHT_KEY,
|
||||||
IMMEDIATE_SIGN_IN_IF_NECESSARY_QUERY_PARAM,
|
IMMEDIATE_SIGN_IN_IF_NECESSARY_QUERY_PARAM,
|
||||||
} from '@src/lib/constants'
|
} from '@src/lib/constants'
|
||||||
import { PATHS } from '@src/lib/paths'
|
import { PATHS } from '@src/lib/paths'
|
||||||
|
import { withSiteBaseURL } from '@src/lib/withBaseURL'
|
||||||
|
|
||||||
const isTestEnv = window?.localStorage.getItem(IS_PLAYWRIGHT_KEY) === 'true'
|
const isTestEnv = window?.localStorage.getItem(IS_PLAYWRIGHT_KEY) === 'true'
|
||||||
|
|
||||||
export const APP_VERSION =
|
export const APP_VERSION =
|
||||||
isTestEnv && NODE_ENV === 'development'
|
isTestEnv && env().NODE_ENV === 'development'
|
||||||
? '11.22.33'
|
? '11.22.33'
|
||||||
: isDesktop()
|
: isDesktop()
|
||||||
? // @ts-ignore
|
? // @ts-ignore
|
||||||
@ -54,7 +55,7 @@ export function generateSignInUrl() {
|
|||||||
'?'
|
'?'
|
||||||
)
|
)
|
||||||
|
|
||||||
return `${VITE_KC_SITE_BASE_URL}${
|
return withSiteBaseURL(
|
||||||
PATHS.SIGN_IN
|
`${PATHS.SIGN_IN}?callbackUrl=${encodeURIComponent(finalURL)}`
|
||||||
}?callbackUrl=${encodeURIComponent(finalURL)}`
|
)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user