Compare commits

..

2 Commits

Author SHA1 Message Date
a01c517be5 Merge branch 'main' into update-snapshots 2024-05-20 17:52:29 +10:00
34e4c3e7b5 update snapshots 2024-05-20 16:32:02 +10:00
223 changed files with 771 additions and 6684 deletions

View File

@ -115,7 +115,7 @@ jobs:
git fetch origin
echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }}
# TODO when webkit works on ubuntu remove the os part of the commit message
# TODO when safari works on ubuntu remove the os part of the commit message
git commit -am "A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)" || true
git push
git push origin ${{ github.head_ref }}
@ -181,7 +181,7 @@ jobs:
- name: build web
run: yarn build:local
- name: Run macos/safari flow
# webkit doesn't work on Ubuntu because of the same reason tauri doesn't (webRTC issues)
# safari doesn't work on Ubuntu because of the same reason tauri doesn't (webRTC issues)
# TODO remove this and the matrix and run all tests on ubuntu when this is fixed
run: yarn playwright test --project="webkit" e2e/playwright/flow-tests.spec.ts
env:

View File

@ -59,9 +59,7 @@ followed by:
```
yarn build:wasm-dev
```
or if you have the gh cli installed
```
./get-latest-wasm-bundle.sh # this will download the latest main wasm bundle
```
@ -102,7 +100,6 @@ yarn test
Which will run our suite of [Vitest unit](https://vitest.dev/) and [React Testing Library E2E](https://testing-library.com/docs/react-testing-library/intro/) tests, in interactive mode by default.
For running the rust (not tauri rust though) only, you can
```bash
cd src/wasm-lib
cargo test
@ -165,7 +162,6 @@ console.log(
- `)
)
```
grab the md list and delete any that are older than the last bump
2. Merge the PR
@ -195,26 +191,23 @@ $ cargo +nightly fuzz run parser
For more information on fuzzing you can check out
[this guide](https://rust-fuzz.github.io/book/cargo-fuzz.html).
### Playwright
First time running plawright locally, you'll need to add the secrets file
```bash
touch ./e2e/playwright/playwright-secrets.env
printf 'token="your-token"\nsnapshottoken="your-snapshot-token"' > ./e2e/playwright/playwright-secrets.env
```
then replace "your-token" with a dev token from dev.zoo.dev/account/api-tokens
then:
run playwright
```
yarn playwright test
```
run a specific test suite
```
yarn playwright test src/e2e-tests/example.spec.ts
```
@ -223,17 +216,14 @@ run a specific test change the test from `test('...` to `test.only('...`
(note if you commit this, the tests will instantly fail without running any of the tests)
run headed
```
yarn playwright test --headed
```
run with step through debugger
```
PWDEBUG=1 yarn playwright test
```
However, if you want a debugger I recommend using VSCode and the `playwright` extension, as the above command is a cruder debugger that steps into every function call which is annoying.
With the extension you can set a breakpoint after `waitForDefaultPlanesVisibilityChange` in order to skip app loading, then the vscode debugger's "step over" is much better for being able to stay at the right level of abstraction as you debug the code.
@ -278,11 +268,12 @@ Where `./store` should look like this
</details>
However because much of our tests involve clicking in the stream at specific locations, it's code-gen looks `await page.locator('video').click();` when really we need to use a pixel coord, so I think it's of limited use.
#### Some notes on CI
The tests are broken into snapshot tests and non-snapshot tests, and they run in that order, they automatically commit new snap shots, so if you see an image commit check it was an intended change. If we have non-determinism in the snapshots such that they are always committing new images, hopefully this annoyance makes us fix them asap, if you notice this happening let Kurt know. But for the odd occasion `git reset --hard HEAD~ && git push -f` is your friend.
The tests are broken into snapshot tests and non-snapshot tests, and they run in that order, they automatically commit new snap shots, so if you see an image commit check it was an intended change. If we have non-determinism in the snapshots such that they are always committing new images, hopefully this annoyance makes us fix them asap, if you notice this happening let Kurt know. But for the odd occasion `git reset --hard HEAD~ && git push -f` is your friend.
How to interpret failing playwright tests?
If your tests fail, click through to the action and see that the tests failed on a line that includes `await page.getByTestId('loading').waitFor({ state: 'detached' })`, this means the test fail because the stream never started. It's you choice if you want to re-run the test, or ignore the failure.
@ -308,7 +299,3 @@ PS: for the debug panel, the following JSON is useful for snapping the camera
```
</details>
## KCL
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).

View File

@ -21,7 +21,7 @@ abs(num: number) -> number
```js
const myAngle = -120
const sketch001 = startSketchOn('XZ')
const sketch001 = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> line([8, 0], %)
|> angledLine({ angle: abs(myAngle), length: 5 }, %)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ angleToMatchLengthY(segment_name: string, to: number, sketch_group: SketchGroup)
### Examples
```js
const sketch001 = startSketchOn('XZ')
const sketch001 = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> line([1, 2], %, 'seg01')
|> angledLine({

View File

@ -15,7 +15,7 @@ angledLine(data: AngledLineData, sketch_group: SketchGroup, tag?: String) -> Ske
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> yLineTo(15, %)
|> angledLine({ angle: 30, length: 15 }, %)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ angledLineThatIntersects(data: AngledLineThatIntersectsData, sketch_group: Sketc
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> lineTo([5, 10], %)
|> lineTo([-10, 10], %, "lineToIntersect")

View File

@ -15,7 +15,7 @@ angledLineToX(data: AngledLineToData, sketch_group: SketchGroup, tag?: String) -
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> angledLineToX({ angle: 30, to: 10 }, %)
|> line([0, 10], %)

View File

@ -15,7 +15,7 @@ angledLineToY(data: AngledLineToData, sketch_group: SketchGroup, tag?: String) -
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> angledLineToY({ angle: 60, to: 20 }, %)
|> line([-20, 0], %)

View File

@ -15,7 +15,7 @@ arc(data: ArcData, sketch_group: SketchGroup, tag?: String) -> SketchGroup
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> line([10, 0], %)
|> arc({

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ bezierCurve(data: BezierData, sketch_group: SketchGroup, tag?: String) -> Sketch
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> line([0, 10], %)
|> bezierCurve({

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -56,9 +56,6 @@ layout: manual
* [`patternLinear3d`](kcl/patternLinear3d)
* [`pi`](kcl/pi)
* [`pow`](kcl/pow)
* [`profileStart`](kcl/profileStart)
* [`profileStartX`](kcl/profileStartX)
* [`profileStartY`](kcl/profileStartY)
* [`revolve`](kcl/revolve)
* [`segAng`](kcl/segAng)
* [`segEndX`](kcl/segEndX)

View File

@ -15,7 +15,7 @@ lastSegX(sketch_group: SketchGroup) -> number
### Examples
```js
const exampleSketch = startSketchOn("XZ")
const exampleSketch = startSketchOn("-XZ")
|> startProfileAt([0, 0], %)
|> line([5, 0], %)
|> line([20, 5], %)

View File

@ -15,7 +15,7 @@ lastSegY(sketch_group: SketchGroup) -> number
### Examples
```js
const exampleSketch = startSketchOn("XZ")
const exampleSketch = startSketchOn("-XZ")
|> startProfileAt([0, 0], %)
|> line([5, 0], %)
|> line([20, 5], %)

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ lineTo(to: [number], sketch_group: SketchGroup, tag?: String) -> SketchGroup
### Examples
```js
const exampleSketch = startSketchOn("XZ")
const exampleSketch = startSketchOn("-XZ")
|> startProfileAt([0, 0], %)
|> lineTo([10, 0], %)
|> lineTo([0, 10], %)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ patternCircular3d(data: CircularPattern3dData, extrude_group: ExtrudeGroup) -> [
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> circle([0, 0], 1, %)
const example = extrude(-5, exampleSketch)

View File

@ -15,7 +15,7 @@ patternLinear2d(data: LinearPattern2dData, sketch_group_set: SketchGroupSet) ->
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> circle([0, 0], 1, %)
|> patternLinear2d({
axis: [1, 0],

View File

@ -15,7 +15,7 @@ patternLinear3d(data: LinearPattern3dData, extrude_group: ExtrudeGroup) -> [Extr
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> line([0, 2], %)
|> line([3, 1], %)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ segAng(segment_name: string, sketch_group: SketchGroup) -> number
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> line([10, 0], %)
|> line([5, 10], %, 'seg01')

View File

@ -15,7 +15,7 @@ segEndX(segment_name: string, sketch_group: SketchGroup) -> number
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> line([20, 0], %, "thing")
|> line([0, 5], %)

View File

@ -15,7 +15,7 @@ segEndY(segment_name: string, sketch_group: SketchGroup) -> number
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> line([20, 0], %)
|> line([0, 3], %, "thing")

View File

@ -15,7 +15,7 @@ segLen(segment_name: string, sketch_group: SketchGroup) -> number
### Examples
```js
const exampleSketch = startSketchOn("XZ")
const exampleSketch = startSketchOn("-XZ")
|> startProfileAt([0, 0], %)
|> angledLine({ angle: 60, length: 10 }, %, "thing")
|> tangentialArc({ offset: -120, radius: 5 }, %)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ tangentialArc(data: TangentialArcData, sketch_group: SketchGroup, tag?: String)
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> angledLine({ angle: 60, length: 10 }, %)
|> tangentialArc({ radius: 10, offset: -120 }, %)

View File

@ -15,7 +15,7 @@ tangentialArcTo(to: [number], sketch_group: SketchGroup, tag?: String) -> Sketch
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> angledLine({ angle: 60, length: 10 }, %)
|> tangentialArcTo([15, 15], %)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ xLine(length: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> xLine(15, %)
|> angledLine({ angle: 80, length: 15 }, %)

View File

@ -15,7 +15,7 @@ xLineTo(to: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> xLineTo(15, %)
|> angledLine({ angle: 80, length: 15 }, %)

View File

@ -15,7 +15,7 @@ yLine(length: number, sketch_group: SketchGroup, tag?: String) -> SketchGroup
### Examples
```js
const exampleSketch = startSketchOn('XZ')
const exampleSketch = startSketchOn('-XZ')
|> startProfileAt([0, 0], %)
|> yLine(15, %)
|> angledLine({ angle: 30, length: 15 }, %)

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 KiB

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 165 KiB

View File

@ -80,7 +80,7 @@ test('Basic sketch', async ({ page }) => {
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('XZ')`
`const part001 = startSketchOn('-XZ')`
)
await u.closeDebugPanel()
@ -89,7 +89,7 @@ test('Basic sketch', async ({ page }) => {
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)`)
await page.waitForTimeout(100)
@ -97,20 +97,20 @@ test('Basic sketch', async ({ page }) => {
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)`)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)
@ -136,7 +136,7 @@ test('Basic sketch', async ({ page }) => {
await page.getByRole('button', { name: 'Equal Length' }).click()
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %, 'seg01')
|> line([0, ${commonPoints.num1}], %)
@ -348,15 +348,6 @@ test('if you use the format keyboard binding it formats your code', async ({
|> close(%)`)
})
test('ensure the Zoo logo is not a link in browser app', async ({ page }) => {
await page.setViewportSize({ width: 1000, height: 500 })
await page.goto('/')
const zooLogo = page.locator('[data-testid="app-logo"]')
// Make sure it's not a link
await expect(zooLogo).not.toHaveAttribute('href')
})
test('if you write invalid kcl you get inlined errors', async ({ page }) => {
const u = getUtils(page)
await page.setViewportSize({ width: 1000, height: 500 })
@ -424,80 +415,6 @@ test('if you write invalid kcl you get inlined errors', async ({ page }) => {
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
})
test('error with 2 source ranges gets 2 diagnostics', async ({ page }) => {
const u = getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const length = .750
const width = 0.500
const height = 0.500
const dia = 4
fn squareHole = (l, w) => {
const squareHoleSketch = startSketchOn('XY')
|> startProfileAt([-width / 2, -length / 2], %)
|> lineTo([width / 2, -length / 2], %)
|> lineTo([width / 2, length / 2], %)
|> lineTo([-width / 2, length / 2], %)
|> close(%)
return squareHoleSketch
}
`
)
})
await page.setViewportSize({ width: 1000, height: 500 })
await page.goto('/')
const lspStartPromise = page.waitForEvent('console', async (message) => {
// it would be better to wait for a message that the kcl lsp has started by looking for the message message.text().includes('[lsp] [window/logMessage]')
// but that doesn't seem to make it to the console for macos/safari :(
if (message.text().includes('start kcl lsp')) {
await new Promise((resolve) => setTimeout(resolve, 200))
return true
}
return false
})
await page.goto('/')
await u.waitForAuthSkipAppStart()
await lspStartPromise
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
// check no error to begin with
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// Click on the bottom of the code editor to add a new line
await page.click('.cm-content')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('Enter')
await page.keyboard.type(`const extrusion = startSketchOn('XY')
|> circle([0, 0], dia/2, %)
|> hole(squareHole(length, width, height), %)
|> extrude(height, %)`)
// error in gutter
await expect(page.locator('.cm-lint-marker-error').first()).toBeVisible()
await page.hover('.cm-lint-marker-error:first-child')
await expect(page.getByText('Expected 2 arguments, got 3')).toBeVisible()
// Make sure there are two diagnostics
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(2)
})
test('if your kcl gets an error from the engine it is inlined', async ({
page,
}) => {
@ -628,7 +545,7 @@ const sketchOnPlaneAndBackSideTest = async (
const camCmdBackSide: [number, number, number] = [-100, -100, -100]
let camPos: [number, number, number] = [100, 100, 100]
if (plane === '-XY' || plane === '-YZ' || plane === 'XZ') {
if (plane === '-XY' || plane === '-YZ' || plane === '-XZ') {
camPos = camCmdBackSide
}
@ -679,7 +596,7 @@ test.describe('Can create sketches on all planes and their back sides', () => {
})
test('XZ', async ({ page }) => {
await sketchOnPlaneAndBackSideTest(page, '-XZ', { x: 700, y: 80 }) // blue plane
await sketchOnPlaneAndBackSideTest(page, 'XZ', { x: 700, y: 80 }) // blue plane
})
test('-XY', async ({ page }) => {
@ -691,7 +608,7 @@ test.describe('Can create sketches on all planes and their back sides', () => {
})
test('-XZ', async ({ page }) => {
await sketchOnPlaneAndBackSideTest(page, 'XZ', { x: 700, y: 427 }) // back of blue plane
await sketchOnPlaneAndBackSideTest(page, '-XZ', { x: 700, y: 427 }) // back of blue plane
})
})
@ -720,8 +637,8 @@ test('Auto complete works', async ({ page }) => {
await page.click('.cm-content')
await page.keyboard.type('const part001 = start')
// expect there to be six auto complete options
await expect(page.locator('.cm-completionLabel')).toHaveCount(6)
// expect there to be three auto complete options
await expect(page.locator('.cm-completionLabel')).toHaveCount(3)
await page.getByText('startSketchOn').click()
await page.keyboard.type("'XZ'")
await page.keyboard.press('Tab')
@ -849,130 +766,6 @@ test('Project settings can be set and override user settings', async ({
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
})
test('Project settings can be opened with keybinding from the editor', async ({
page,
}) => {
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/', { waitUntil: 'domcontentloaded' })
await page
.getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' })
// Put the cursor in the editor
await page.click('.cm-content')
// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')
await expect(
page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible()
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('dark')
// Roll back to default "system" theme
await page
.getByText(
'themeRoll back themeRoll back to match defaultThe overall appearance of the appl'
)
.hover()
await page
.getByRole('button', {
name: 'Roll back theme ; Has tooltip: Roll back to match default',
})
.click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Check that the project setting did not change
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
})
test('Project and user settings can be reset', async ({ page }) => {
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/', { waitUntil: 'domcontentloaded' })
await page
.getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' })
// Put the cursor in the editor
await page.click('.cm-content')
// Open the settings modal with the browser keyboard shortcut
await page.keyboard.press('Meta+Shift+,')
await expect(
page.getByRole('heading', { name: 'Settings', exact: true })
).toBeVisible()
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
// Check that the user setting was not changed
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Set the user theme to light.
await page
.locator('select[name="app-theme"]')
.selectOption({ value: 'light' })
// Verify the toast appeared
await expect(
page.getByText(`Set theme to "light" as a user default`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
await page.getByRole('radio', { name: 'Project' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('light')
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
await page.getByRole('radio', { name: 'User' }).click()
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
// Click the reset settings button.
await page.getByRole('button', { name: 'Restore default settings' }).click()
// Verify it is now set to the default value
await expect(page.locator('select[name="app-theme"]')).toHaveValue('system')
})
test('Click through each onboarding step', async ({ page }) => {
const u = getUtils(page)
@ -1090,28 +883,28 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)
@ -1220,6 +1013,7 @@ test('Selections work on fresh and edited sketch', async ({ page }) => {
// wait for execution done
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.updateCamPosition([0, -1378.01, 0.06])
await u.closeDebugPanel()
// select a line
@ -1290,57 +1084,12 @@ test.describe('Command bar tests', () => {
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
})
test('Command bar keybinding works from code editor and can change a setting', async ({
page,
}) => {
// Brief boilerplate
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/', { waitUntil: 'domcontentloaded' })
let cmdSearchBar = page.getByPlaceholder('Search commands')
// Put the cursor in the code editor
await page.click('.cm-content')
// Now try the same, but with the keyboard shortcut, check focus
await page.keyboard.press('Meta+K')
await expect(cmdSearchBar).toBeVisible()
await expect(cmdSearchBar).toBeFocused()
// Try typing in the command bar
await page.keyboard.type('theme')
const themeOption = page.getByRole('option', {
name: 'Settings · app · theme',
})
await expect(themeOption).toBeVisible()
await themeOption.click()
const themeInput = page.getByPlaceholder('Select an option')
await expect(themeInput).toBeVisible()
await expect(themeInput).toBeFocused()
// Select dark theme
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await page.keyboard.press('ArrowDown')
await expect(page.getByRole('option', { name: 'system' })).toHaveAttribute(
'data-headlessui-state',
'active'
)
await page.keyboard.press('Enter')
// Check the toast appeared
await expect(
page.getByText(`Set theme to "system" for this project`)
).toBeVisible()
// Check that the theme changed
await expect(page.locator('body')).not.toHaveClass(`body-bg dark`)
})
test('Can extrude from the command bar', async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const distance = sqrt(20)
const part001 = startSketchOn('XZ')
const part001 = startSketchOn('-XZ')
|> startProfileAt([-6.95, 10.98], %)
|> line([25.1, 0.41], %)
|> line([0.73, -20.93], %)
@ -1410,7 +1159,7 @@ test.describe('Command bar tests', () => {
await expect(page.locator('.cm-content')).toHaveText(
`const distance = sqrt(20)
const distance001 = ${KCL_DEFAULT_LENGTH}
const part001 = startSketchOn('XZ')
const part001 = startSketchOn('-XZ')
|> startProfileAt([-6.95, 10.98], %)
|> line([25.1, 0.41], %)
|> line([0.73, -20.93], %)
@ -1446,7 +1195,7 @@ test('Can add multiple sketches', async ({ page }) => {
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('XZ')`
`const part001 = startSketchOn('-XZ')`
)
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
@ -1455,7 +1204,7 @@ test('Can add multiple sketches', async ({ page }) => {
await u.closeDebugPanel()
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)`)
await page.waitForTimeout(100)
@ -1463,19 +1212,19 @@ test('Can add multiple sketches', async ({ page }) => {
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)`)
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)`)
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
const finalCodeFirstSketch = `const part001 = startSketchOn('XZ')
const finalCodeFirstSketch = `const part001 = startSketchOn('-XZ')
|> startProfileAt(${commonPoints.startAt}, %)
|> line([${commonPoints.num1}, 0], %)
|> line([0, ${commonPoints.num1}], %)
@ -1496,6 +1245,7 @@ test('Can add multiple sketches', async ({ page }) => {
await u.clearCommandLogs()
await page.getByRole('button', { name: 'Start Sketch' }).click()
await page.waitForTimeout(400)
await u.updateCamPosition([583, 2000, 370])
await page.mouse.click(650, 450)
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
@ -1509,8 +1259,7 @@ test('Can add multiple sketches', async ({ page }) => {
await page.waitForTimeout(100)
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
const startAt2 =
process.platform === 'darwin' ? '[9.75, -13.16]' : '[0.93, -1.25]'
const startAt2 = '[22.65, -30.57]'
await expect(
(await page.locator('.cm-content').innerText()).replace(/\s/g, '')
).toBe(
@ -1524,7 +1273,7 @@ const part002 = startSketchOn('${plane}')
await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)
await page.waitForTimeout(100)
const num2 = process.platform === 'darwin' ? 9.84 : 0.94
const num2 = 22.87
await expect(
(await page.locator('.cm-content').innerText()).replace(/\s/g, '')
).toBe(
@ -1542,9 +1291,7 @@ const part002 = startSketchOn('${plane}')
const part002 = startSketchOn('${plane}')
|> startProfileAt(${startAt2}, %)
|> line([${num2}, 0], %)
|> line([0, ${roundOff(
num2 + (process.platform === 'darwin' ? 0.01 : -0.01)
)}], %)`.replace(/\s/g, '')
|> line([0, ${roundOff(num2)}], %)`.replace(/\s/g, '')
)
await page.waitForTimeout(100)
await page.mouse.click(startXPx, 500 - PUR * 20)
@ -1555,13 +1302,8 @@ const part002 = startSketchOn('${plane}')
const part002 = startSketchOn('${plane}')
|> startProfileAt(${startAt2}, %)
|> line([${num2}, 0], %)
|> line([0, ${roundOff(
num2 + (process.platform === 'darwin' ? 0.01 : -0.01)
)}], %)
|> line([-${process.platform === 'darwin' ? 19.59 : 1.87}, 0], %)`.replace(
/\s/g,
''
)
|> line([0, ${roundOff(num2)}], %)
|> line([-45.52, 0], %)`.replace(/\s/g, '')
)
})
@ -1609,7 +1351,7 @@ test('Hovering over 3d features highlights code', async ({ page }) => {
await page.addInitScript(async (KCL_DEFAULT_LENGTH) => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('XZ')
`const part001 = startSketchOn('-XZ')
|> startProfileAt([20, 0], %)
|> line([7.13, 4 + 0], %)
|> angledLine({ angle: 3 + 0, length: 3.14 + 0 }, %)
@ -1628,7 +1370,7 @@ test('Hovering over 3d features highlights code', async ({ page }) => {
}, %)
|> tangentialArcTo([13.14 + 0, 13.14], %)
|> close(%)
|> extrude(5 + 7, %)
|> extrude(5 + 7, %)
`
)
}, KCL_DEFAULT_LENGTH)
@ -1689,7 +1431,7 @@ test("Various pipe expressions should and shouldn't allow edit and or extrude",
}: any) => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('XZ')
`const part001 = startSketchOn('-XZ')
${extrudeAndEditBlocked}
|> line([25.96, 2.93], %)
|> line([5.25, -5.72], %)
@ -1697,14 +1439,14 @@ test("Various pipe expressions should and shouldn't allow edit and or extrude",
|> line([-27.65, -2.78], %)
|> close(%)
|> extrude(5, %)
const part002 = startSketchOn('XZ')
const part002 = startSketchOn('-XZ')
${extrudeAndEditAllowed}
|> line([10.32, 6.47], %)
|> line([9.71, -6.16], %)
|> line([-3.08, -9.86], %)
|> line([-12.02, -1.54], %)
|> close(%)
const part003 = startSketchOn('XZ')
const part003 = startSketchOn('-XZ')
${editOnly}
|> line([27.55, -1.65], %)
|> line([4.95, -8], %)
@ -1712,7 +1454,7 @@ const part003 = startSketchOn('XZ')
|> line([-15.79, 17.08], %)
fn yohey = (pos) => {
const part004 = startSketchOn('XZ')
const part004 = startSketchOn('-XZ')
${extrudeAndEditBlockedInFunction}
|> line([27.55, -1.65], %)
|> line([4.95, -10.53], %)
@ -1773,7 +1515,7 @@ fn yohey = (pos) => {
await page.mouse.click(700, 200)
// expect main content to contain `part005` i.e. started a new sketch
await expect(page.locator('.cm-content')).toHaveText(
/part005 = startSketchOn\('XZ'\)/
/part005 = startSketchOn\('-XZ'\)/
)
})
@ -1801,7 +1543,7 @@ test('Deselecting line tool should mean nothing happens on click', async ({
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('XZ')`
`const part001 = startSketchOn('-XZ')`
)
await page.waitForTimeout(600)
@ -1842,94 +1584,12 @@ test('Deselecting line tool should mean nothing happens on click', async ({
previousCodeContent = await page.locator('.cm-content').innerText()
})
test('multi-sketch file shows multiple Edit Sketch buttons', async ({
page,
context,
}) => {
const u = getUtils(page)
const selectionsSnippets = {
startProfileAt1:
'|> startProfileAt([-width / 4 + screwRadius, height / 2], %)',
startProfileAt2: '|> startProfileAt([-width / 2, 0], %)',
startProfileAt3: '|> startProfileAt([0, thickness], %)',
}
await context.addInitScript(
async ({ startProfileAt1, startProfileAt2, startProfileAt3 }: any) => {
localStorage.setItem(
'persistCode',
`
const width = 20
const height = 10
const thickness = 5
const screwRadius = 3
const wireRadius = 2
const wireOffset = 0.5
const screwHole = startSketchOn('XY')
${startProfileAt1}
|> arc({
radius: screwRadius,
angle_start: 0,
angle_end: 360
}, %)
const part001 = startSketchOn('XY')
${startProfileAt2}
|> xLine(width * .5, %)
|> yLine(height, %)
|> xLine(-width * .5, %)
|> close(%)
|> hole(screwHole, %)
|> extrude(thickness, %)
const part002 = startSketchOn('-XZ')
${startProfileAt3}
|> xLine(width / 4, %)
|> tangentialArcTo([width / 2, 0], %)
|> xLine(-width / 4 + wireRadius, %)
|> yLine(wireOffset, %)
|> arc({
radius: wireRadius,
angle_start: 0,
angle_end: 180
}, %)
|> yLine(-wireOffset, %)
|> xLine(-width / 4, %)
|> close(%)
|> extrude(-height, %)
`
)
},
selectionsSnippets
)
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()
// wait for execution done
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
await page.getByText(selectionsSnippets.startProfileAt1).click()
await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()
await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeVisible()
await page.getByText(selectionsSnippets.startProfileAt2).click()
await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()
await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeVisible()
await page.getByText(selectionsSnippets.startProfileAt3).click()
await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()
await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeVisible()
})
test('Can edit segments by dragging their handles', async ({ page }) => {
const u = getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('XZ')
`const part001 = startSketchOn('-XZ')
|> startProfileAt([4.61, -14.01], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %)`
@ -1989,7 +1649,7 @@ test('Can edit segments by dragging their handles', async ({ page }) => {
// expect the code to have changed
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([6.44, -12.07], %)
|> line([14.04, 2.03], %)
|> tangentialArcTo([27.19, -4.2], %)`)
@ -2007,7 +1667,7 @@ const doSnapAtDifferentScales = async (
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
const code = `const part001 = startSketchOn('-XZ')
const code = `const part001 = startSketchOn('XZ')
|> startProfileAt([${roundOff(scale * 87.68)}, ${roundOff(scale * 43.84)}], %)
|> line([${roundOff(scale * 175.36)}, 0], %)
|> line([0, -${roundOff(scale * 175.36) + fudge}], %)
@ -2029,7 +1689,7 @@ const doSnapAtDifferentScales = async (
// select a plane
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('-XZ')`
`const part001 = startSketchOn('XZ')`
)
let prevContent = await page.locator('.cm-content').innerText()
@ -2086,7 +1746,7 @@ test('Sketch on face', async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const part001 = startSketchOn('XZ')
`const part001 = startSketchOn('-XZ')
|> startProfileAt([3.29, 7.86], %)
|> line([2.48, 2.44], %)
|> line([2.66, 1.17], %)
@ -2295,105 +1955,3 @@ test('Extrude from command bar selects extrude line after', async ({
` |> extrude(${KCL_DEFAULT_LENGTH}, %)`
)
})
test('Basic default modeling and sketch hotkeys work', async ({ page }) => {
// This test can run long if it takes a little too long to load
// the engine.
test.setTimeout(90000)
// This test has a weird bug on ubuntu
test.skip(
process.platform === 'linux',
'weird playwright bug on ubuntu https://github.com/KittyCAD/modeling-app/issues/2444'
)
// Load the app with the code pane open
await page.addInitScript(async () => {
localStorage.setItem(
'store',
JSON.stringify({
state: {
openPanes: ['code'],
},
version: 0,
})
)
})
// Wait for the app to be ready for use
const u = getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
await page.goto('/')
await u.waitForAuthSkipAppStart()
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
const codePane = page.getByRole('textbox').locator('div')
const codePaneButton = page.getByRole('tab', { name: 'KCL Code' })
const lineButton = page.getByRole('button', { name: 'Line' })
const arcButton = page.getByRole('button', { name: 'Tangential Arc' })
const extrudeButton = page.getByRole('button', { name: 'Extrude' })
// Test that the hotkeys do nothing when
// focus is on the code pane
await codePane.click()
await page.keyboard.press('s')
await page.keyboard.press('l')
await page.keyboard.press('a')
await page.keyboard.press('e')
await expect(page.locator('.cm-content')).toHaveText('slae')
await page.keyboard.press('Meta+/')
// Test these hotkeys perform actions when
// focus is on the canvas
await page.mouse.move(600, 250)
await page.mouse.click(600, 250)
// Start a sketch
await page.keyboard.press('s')
await page.mouse.move(800, 300)
await page.mouse.click(800, 300)
await page.waitForTimeout(1000)
await expect(lineButton).toHaveAttribute('aria-pressed', 'true')
/**
* TODO: There is a bug somewhere that causes this test to fail
* if you toggle the codePane closed before your trigger the
* start of the sketch.
*/
await codePaneButton.click()
// Draw a line
await page.mouse.move(700, 200, { steps: 5 })
await page.mouse.click(700, 200)
await page.mouse.move(800, 250, { steps: 5 })
await page.mouse.click(800, 250)
// Unequip line tool
await page.keyboard.press('l')
await expect(lineButton).not.toHaveAttribute('aria-pressed', 'true')
// Equip arc tool
await page.keyboard.press('a')
await expect(arcButton).toHaveAttribute('aria-pressed', 'true')
await page.mouse.move(1000, 100, { steps: 5 })
await page.mouse.click(1000, 100)
await page.keyboard.press('Escape')
await page.keyboard.press('l')
await expect(lineButton).toHaveAttribute('aria-pressed', 'true')
// Close profile
await page.mouse.move(700, 200, { steps: 5 })
await page.mouse.click(700, 200)
// Unequip line tool
await page.keyboard.press('Escape')
// Exit sketch
await page.keyboard.press('Escape')
// Extrude
await page.mouse.click(750, 150)
await expect(extrudeButton).not.toBeDisabled()
await page.keyboard.press('e')
await page.mouse.move(850, 180, { steps: 5 })
await page.mouse.click(850, 180)
await page.waitForTimeout(100)
await page.getByRole('button', { name: 'Continue' }).click()
await page.getByRole('button', { name: 'Submit command' }).click()
await codePaneButton.click()
await expect(page.locator('.cm-content')).toContainText('extrude(')
})

View File

@ -273,8 +273,6 @@ const part001 = startSketchOn('-XZ')
for (let { modelPath, imagePath, outputType } of exportLocations) {
// May change depending on the file being dealt with
let cliCommand = `export ZOO_TOKEN=${secrets.snapshottoken} && zoo file snapshot --output-format=png --src-format=${outputType} ${modelPath} ${imagePath}`
const fileSize = (await fsp.stat(modelPath)).size
console.log(`Size of the file at ${modelPath}: ${fileSize} bytes`)
const parentPath = path.dirname(modelPath)
@ -447,7 +445,7 @@ test('Draft segments should look right', async ({ page, context }) => {
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('XZ')`
`const part001 = startSketchOn('-XZ')`
)
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
@ -455,7 +453,7 @@ test('Draft segments should look right', async ({ page, context }) => {
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([9.06, -12.22], %)`)
await page.waitForTimeout(100)
@ -469,7 +467,7 @@ test('Draft segments should look right', async ({ page, context }) => {
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([9.06, -12.22], %)
|> line([9.14, 0], %)`)
@ -506,7 +504,7 @@ test('Draft rectangles should look right', async ({ page, context }) => {
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('XZ')`
`const part001 = startSketchOn('-XZ')`
)
await page.waitForTimeout(500) // TODO detect animation ending, or disable animation
@ -555,7 +553,7 @@ test.describe('Client side scene scale should match engine scale', () => {
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('XZ')`
`const part001 = startSketchOn('-XZ')`
)
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
@ -563,7 +561,7 @@ test.describe('Client side scene scale should match engine scale', () => {
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([9.06, -12.22], %)`)
await page.waitForTimeout(100)
@ -573,7 +571,7 @@ test.describe('Client side scene scale should match engine scale', () => {
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([9.06, -12.22], %)
|> line([9.14, 0], %)`)
@ -583,7 +581,7 @@ test.describe('Client side scene scale should match engine scale', () => {
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([9.06, -12.22], %)
|> line([9.14, 0], %)
|> tangentialArcTo([27.34, -3.08], %)`)
@ -658,7 +656,7 @@ test.describe('Client side scene scale should match engine scale', () => {
await page.mouse.click(700, 200)
await expect(page.locator('.cm-content')).toHaveText(
`const part001 = startSketchOn('XZ')`
`const part001 = startSketchOn('-XZ')`
)
await page.waitForTimeout(300) // TODO detect animation ending, or disable animation
@ -666,7 +664,7 @@ test.describe('Client side scene scale should match engine scale', () => {
const startXPx = 600
await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([230.03, -310.32], %)`)
await page.waitForTimeout(100)
@ -676,7 +674,7 @@ test.describe('Client side scene scale should match engine scale', () => {
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([230.03, -310.32], %)
|> line([232.2, 0], %)`)
@ -686,7 +684,7 @@ test.describe('Client side scene scale should match engine scale', () => {
await page.mouse.click(startXPx + PUR * 30, 500 - PUR * 20)
await expect(page.locator('.cm-content'))
.toHaveText(`const part001 = startSketchOn('XZ')
.toHaveText(`const part001 = startSketchOn('-XZ')
|> startProfileAt([230.03, -310.32], %)
|> line([232.2, 0], %)
|> tangentialArcTo([694.43, -78.12], %)`)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -1,6 +1,6 @@
{
"name": "untitled-app",
"version": "0.21.7",
"version": "0.21.4",
"private": true,
"dependencies": {
"@codemirror/autocomplete": "^6.16.0",
@ -17,19 +17,19 @@
"@replit/codemirror-interact": "^6.3.1",
"@tauri-apps/api": "2.0.0-beta.8",
"@tauri-apps/plugin-dialog": "^2.0.0-beta.2",
"@tauri-apps/plugin-fs": "^2.0.0-beta.3",
"@tauri-apps/plugin-fs": "^2.0.0-beta.2",
"@tauri-apps/plugin-http": "^2.0.0-beta.2",
"@tauri-apps/plugin-os": "^2.0.0-beta.3",
"@tauri-apps/plugin-os": "^2.0.0-beta.2",
"@tauri-apps/plugin-process": "^2.0.0-beta.2",
"@tauri-apps/plugin-shell": "^2.0.0-beta.2",
"@tauri-apps/plugin-updater": "^2.0.0-beta.3",
"@tauri-apps/plugin-updater": "^2.0.0-beta.2",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^15.0.2",
"@testing-library/user-event": "^14.5.2",
"@ts-stack/markdown": "^1.5.0",
"@tweenjs/tween.js": "^23.1.1",
"@types/node": "^18.19.31",
"@types/react": "^18.3.2",
"@types/react": "^18.2.77",
"@types/react-dom": "^18.2.25",
"@uiw/react-codemirror": "^4.21.25",
"@xstate/inspect": "^0.8.0",
@ -45,22 +45,22 @@
"jszip": "^3.10.1",
"node-fetch": "^3.3.2",
"re-resizable": "^6.9.11",
"react": "^18.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-hotkeys-hook": "^4.5.0",
"react-json-view": "^1.21.3",
"react-modal": "^3.16.1",
"react-modal-promise": "^1.0.2",
"react-router-dom": "^6.23.1",
"react-router-dom": "^6.22.3",
"sketch-helpers": "^0.0.4",
"swr": "^2.2.5",
"three": "^0.164.1",
"three": "^0.163.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5",
"ua-parser-js": "^1.0.37",
"uuid": "^9.0.1",
"vitest": "^1.6.0",
"vitest": "^1.5.0",
"vscode-jsonrpc": "^8.1.0",
"vscode-languageserver-protocol": "^3.17.5",
"wasm-pack": "^0.12.1",

62
src-tauri/Cargo.lock generated
View File

@ -212,15 +212,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "arrayvec"
version = "0.7.4"
@ -1216,17 +1207,6 @@ dependencies = [
"syn 2.0.65",
]
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.65",
]
[[package]]
name = "derive_more"
version = "0.99.17"
@ -1278,17 +1258,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
[[package]]
name = "displaydoc"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.65",
]
[[package]]
name = "dlib"
version = "0.5.2"
@ -2567,7 +2536,7 @@ dependencies = [
[[package]]
name = "kcl-lib"
version = "0.1.57"
version = "0.1.55"
dependencies = [
"anyhow",
"approx",
@ -2610,7 +2579,7 @@ dependencies = [
"wasm-bindgen-futures",
"web-sys",
"winnow 0.5.40",
"zip 1.3.0",
"zip",
]
[[package]]
@ -5502,7 +5471,7 @@ dependencies = [
"tokio",
"url",
"windows-sys 0.52.0",
"zip 0.6.6",
"zip",
]
[[package]]
@ -6059,8 +6028,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "ts-rs"
version = "8.1.0"
source = "git+https://github.com/Aleph-Alpha/ts-rs#f898578d80d3e2a54080c1c046c45f9eaa2435c3"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2cae1fc5d05d47aa24b64f9a4f7cba24cdc9187a2084dd97ac57bef5eccae6"
dependencies = [
"chrono",
"thiserror",
@ -6071,9 +6041,11 @@ dependencies = [
[[package]]
name = "ts-rs-macros"
version = "8.1.0"
source = "git+https://github.com/Aleph-Alpha/ts-rs#f898578d80d3e2a54080c1c046c45f9eaa2435c3"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73f7f9b821696963053a89a7bd8b292dc34420aea8294d7b225274d488f3ec92"
dependencies = [
"Inflector",
"proc-macro2",
"quote",
"syn 2.0.65",
@ -7151,20 +7123,6 @@ dependencies = [
"zstd",
]
[[package]]
name = "zip"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f4a27345eb6f7aa7bd015ba7eb4175fa4e1b462a29874b779e0bbcf96c6ac7"
dependencies = [
"arbitrary",
"crc32fast",
"crossbeam-utils",
"displaydoc",
"indexmap 2.2.6",
"thiserror",
]
[[package]]
name = "zstd"
version = "0.11.2+zstd.1.5.2"

View File

@ -56,33 +56,6 @@
]
},
"shell:allow-open",
{
"identifier": "shell:allow-execute",
"allow": [
{
"name": "open",
"cmd": "open",
"args": [
"-R",
{
"validator": "\\S+"
}
],
"sidecar": false
},
{
"name": "explorer",
"cmd": "explorer",
"args": [
"/select",
{
"validator": "\\S+"
}
],
"sidecar": false
}
]
},
"dialog:allow-open",
"dialog:allow-save",
"dialog:allow-message",

View File

@ -18,21 +18,13 @@ use oauth2::TokenResponse;
use tauri::{ipc::InvokeError, Manager};
use tauri_plugin_cli::CliExt;
use tauri_plugin_shell::ShellExt;
use tokio::process::Command;
const DEFAULT_HOST: &str = "https://api.zoo.dev";
const SETTINGS_FILE_NAME: &str = "settings.toml";
const PROJECT_SETTINGS_FILE_NAME: &str = "project.toml";
const PROJECT_FOLDER: &str = "zoo-modeling-app-projects";
#[tauri::command]
async fn rename_project_directory(project_path: &str, new_name: &str) -> Result<PathBuf, InvokeError> {
let project_dir = std::path::Path::new(project_path);
kcl_lib::settings::types::file::rename_project_directory(project_dir, new_name)
.await
.map_err(InvokeError::from_anyhow)
}
#[tauri::command]
fn get_initial_default_dir(app: tauri::AppHandle) -> Result<PathBuf, InvokeError> {
let dir = match app.path().document_dir() {
@ -129,8 +121,11 @@ async fn write_app_settings_file(app: tauri::AppHandle, configuration: Configura
Ok(())
}
async fn get_project_settings_file_path(project_path: &str) -> Result<PathBuf, InvokeError> {
let project_dir = std::path::Path::new(project_path);
async fn get_project_settings_file_path(
app_settings: Configuration,
project_name: &str,
) -> Result<PathBuf, InvokeError> {
let project_dir = app_settings.settings.project.directory.join(project_name);
if !project_dir.exists() {
tokio::fs::create_dir_all(&project_dir)
@ -142,8 +137,11 @@ async fn get_project_settings_file_path(project_path: &str) -> Result<PathBuf, I
}
#[tauri::command]
async fn read_project_settings_file(project_path: &str) -> Result<ProjectConfiguration, InvokeError> {
let settings_path = get_project_settings_file_path(project_path).await?;
async fn read_project_settings_file(
app_settings: Configuration,
project_name: &str,
) -> Result<ProjectConfiguration, InvokeError> {
let settings_path = get_project_settings_file_path(app_settings, project_name).await?;
// Check if this file exists.
if !settings_path.exists() {
@ -161,10 +159,11 @@ async fn read_project_settings_file(project_path: &str) -> Result<ProjectConfigu
#[tauri::command]
async fn write_project_settings_file(
project_path: &str,
app_settings: Configuration,
project_name: &str,
configuration: ProjectConfiguration,
) -> Result<(), InvokeError> {
let settings_path = get_project_settings_file_path(project_path).await?;
let settings_path = get_project_settings_file_path(app_settings, project_name).await?;
let contents = toml::to_string_pretty(&configuration).map_err(|e| InvokeError::from_anyhow(e.into()))?;
tokio::fs::write(settings_path, contents.as_bytes())
.await
@ -331,20 +330,10 @@ async fn get_user(token: &str, hostname: &str) -> Result<kittycad::types::User,
/// From this GitHub comment: https://github.com/tauri-apps/tauri/issues/4062#issuecomment-1338048169
/// But with the Linux support removed since we don't need it for now.
#[tauri::command]
fn show_in_folder(app: tauri::AppHandle, path: &str) -> Result<(), InvokeError> {
// Check if the file exists.
// If it doesn't, return an error.
if !Path::new(path).exists() {
return Err(InvokeError::from_anyhow(anyhow::anyhow!(
"The file `{}` does not exist",
path
)));
}
fn show_in_folder(path: &str) -> Result<(), InvokeError> {
#[cfg(not(unix))]
{
app.shell()
.command("explorer")
Command::new("explorer")
.args(["/select,", path]) // The comma after select is not a typo
.spawn()
.map_err(|e| InvokeError::from_anyhow(e.into()))?;
@ -352,8 +341,7 @@ fn show_in_folder(app: tauri::AppHandle, path: &str) -> Result<(), InvokeError>
#[cfg(unix)]
{
app.shell()
.command("open")
Command::new("open")
.args(["-R", path])
.spawn()
.map_err(|e| InvokeError::from_anyhow(e.into()))?;
@ -408,7 +396,6 @@ fn main() -> Result<()> {
write_app_settings_file,
read_project_settings_file,
write_project_settings_file,
rename_project_directory,
])
.plugin(tauri_plugin_cli::init())
.plugin(tauri_plugin_deep_link::init())

View File

@ -74,5 +74,5 @@
}
},
"productName": "Zoo Modeling App",
"version": "0.21.7"
"version": "0.21.4"
}

View File

@ -23,7 +23,6 @@ import { useRefreshSettings } from 'hooks/useRefreshSettings'
import { ModelingSidebar } from 'components/ModelingSidebar/ModelingSidebar'
import { LowerRightControls } from 'components/LowerRightControls'
import ModalContainer from 'react-modal-promise'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
export function App() {
useRefreshSettings(paths.FILE + 'SETTINGS')
@ -58,13 +57,14 @@ export function App() {
const {
app: { onboardingStatus },
} = settings.context
const { state } = useModelingContext()
const { state, send } = useModelingContext()
useHotkeys('esc', () => send('Cancel'))
useHotkeys('backspace', (e) => {
e.preventDefault()
})
useHotkeyWrapper(
[isTauri() ? 'mod + ,' : 'shift + mod + ,'],
useHotkeys(
isTauri() ? 'mod + ,' : 'shift + mod + ,',
() => navigate(filePath + paths.SETTINGS),
{
splitKey: '|',

View File

@ -12,8 +12,6 @@ import {
} from 'components/NetworkHealthIndicator'
import { useStore } from 'useStore'
import { ActionButtonDropdown } from 'components/ActionButtonDropdown'
import { useHotkeys } from 'react-hotkeys-hook'
import Tooltip from 'components/Tooltip'
export const Toolbar = () => {
const { commandBarSend } = useCommandsContext()
@ -42,56 +40,6 @@ export const Toolbar = () => {
const disableAllButtons =
overallState !== NetworkHealthState.Ok || isExecuting || !isStreamReady
useHotkeys(
'l',
() =>
state.matches('Sketch.Line tool')
? send('CancelSketch')
: send('Equip Line tool'),
{ enabled: !disableAllButtons, scopes: ['sketch'] }
)
useHotkeys(
'a',
() =>
state.matches('Sketch.Tangential arc to')
? send('CancelSketch')
: send('Equip tangential arc to'),
{ enabled: !disableAllButtons, scopes: ['sketch'] }
)
useHotkeys(
'r',
() =>
state.matches('Sketch.Rectangle tool')
? send('CancelSketch')
: send('Equip rectangle tool'),
{ enabled: !disableAllButtons, scopes: ['sketch'] }
)
useHotkeys(
's',
() =>
state.nextEvents.includes('Enter sketch') && pathId
? send({ type: 'Enter sketch' })
: send({ type: 'Enter sketch', data: { forceNewSketch: true } }),
{ enabled: !disableAllButtons, scopes: ['modeling'] }
)
useHotkeys(
'esc',
() =>
state.matches('Sketch.SketchIdle')
? send('Cancel')
: send('CancelSketch'),
{ enabled: !disableAllButtons, scopes: ['sketch'] }
)
useHotkeys(
'e',
() =>
commandBarSend({
type: 'Find and select command',
data: { name: 'Extrude', ownerMachine: 'modeling' },
}),
{ enabled: !disableAllButtons, scopes: ['modeling'] }
)
function handleToolbarButtonsWheelEvent(ev: WheelEvent<HTMLSpanElement>) {
const span = toolbarButtonsRef.current
if (!span) {
@ -129,13 +77,6 @@ export const Toolbar = () => {
disabled={disableAllButtons}
>
<span data-testid="start-sketch">Start Sketch</span>
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: S
</Tooltip>
</ActionButton>
</li>
)}
@ -153,13 +94,6 @@ export const Toolbar = () => {
disabled={disableAllButtons}
>
Edit Sketch
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: S
</Tooltip>
</ActionButton>
</li>
)}
@ -177,13 +111,6 @@ export const Toolbar = () => {
disabled={disableAllButtons}
>
Exit Sketch
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: Esc
</Tooltip>
</ActionButton>
</li>
)}
@ -207,13 +134,6 @@ export const Toolbar = () => {
disabled={disableAllButtons}
>
Line
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: L
</Tooltip>
</ActionButton>
</li>
<li className="contents" key="tangential-arc-button">
@ -238,13 +158,6 @@ export const Toolbar = () => {
}
>
Tangential Arc
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: A
</Tooltip>
</ActionButton>
</li>
<li className="contents" key="rectangle-button">
@ -274,13 +187,6 @@ export const Toolbar = () => {
}
>
Rectangle
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: R
</Tooltip>
</ActionButton>
</li>
</>
@ -358,13 +264,6 @@ export const Toolbar = () => {
}}
>
Extrude
<Tooltip
delay={1250}
position="bottom"
className="!px-2 !text-xs"
>
Shortcut: E
</Tooltip>
</ActionButton>
</li>
)}

View File

@ -1396,7 +1396,7 @@ export class SceneEntities {
zAxis = posNorm ? [1, 0, 0] : [-1, 0, 0]
yAxis = [0, 0, 1]
} else if (type === XZ_PLANE) {
planeString = posNorm ? '-XZ' : 'XZ'
planeString = posNorm ? 'XZ' : '-XZ'
zAxis = posNorm ? [0, 1, 0] : [0, -1, 0]
yAxis = [0, 0, 1]
}

View File

@ -34,7 +34,7 @@ export const AppHeader = ({
}
>
<ProjectSidebarMenu
enableMenu={enableMenu}
renderAsLink={!enableMenu}
project={project?.project}
file={project?.file}
/>

View File

@ -1,11 +1,11 @@
import { Dialog, Popover, Transition } from '@headlessui/react'
import { Fragment, useEffect } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { useCommandsContext } from 'hooks/useCommandsContext'
import CommandBarArgument from './CommandBarArgument'
import CommandComboBox from '../CommandComboBox'
import CommandBarReview from './CommandBarReview'
import { useLocation } from 'react-router-dom'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
export const CommandBar = () => {
const { pathname } = useLocation()
@ -22,7 +22,7 @@ export const CommandBar = () => {
}, [pathname])
// Hook up keyboard shortcuts
useHotkeyWrapper(['mod+k', 'mod+/'], () => {
useHotkeys(['mod+k', 'mod+/'], () => {
if (commandBarState.context.commands.length === 0) return
if (commandBarState.matches('Closed')) {
commandBarSend({ type: 'Open' })

View File

@ -56,7 +56,7 @@ function CommandBarSelectionInput({
// In future the engine's edit mode will go away and this will be handled differently.
useEffect(() => {
kclManager.exitEditMode()
return () => kclManager.defaultSelectionFilter()
return () => kclManager.enterEditMode()
}, [])
// Fast-forward through this arg if it's marked as skippable

View File

@ -8,6 +8,7 @@ import { Dialog, Disclosure } from '@headlessui/react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faChevronRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { useFileContext } from 'hooks/useFileContext'
import { useHotkeys } from 'react-hotkeys-hook'
import styles from './FileTree.module.css'
import { sortProject } from 'lib/tauriFS'
import { FILE_EXT } from 'lib/constants'
@ -15,7 +16,6 @@ import { CustomIcon } from './CustomIcon'
import { codeManager, kclManager } from 'lib/singletons'
import { useDocumentHasFocus } from 'hooks/useDocumentHasFocus'
import { useLspContext } from './LspProvider'
import useHotkeyWrapper from 'lib/hotkeyWrapper'
function getIndentationCSS(level: number) {
return `calc(1rem * ${level + 1})`
@ -333,8 +333,8 @@ export const FileTreeMenu = () => {
send({ type: 'Create file', data: { name: '', makeDir: true } })
}
useHotkeyWrapper(['meta + n'], createFile)
useHotkeyWrapper(['meta + shift + n'], createFolder)
useHotkeys('meta + n', createFile)
useHotkeys('meta + shift + n', createFolder)
return (
<>

View File

@ -22,7 +22,8 @@ import {
LspWorker,
} from 'editor/plugins/lsp/types'
import { wasmUrl } from 'lang/wasm'
import { PROJECT_ENTRYPOINT } from 'lib/constants'
const DEFAULT_FILE_NAME: string = 'main.kcl'
function getWorkspaceFolders(): LSP.WorkspaceFolder[] {
return []
@ -136,7 +137,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (isKclLspServerReady && !TEST && kclLspClient) {
// Set up the lsp plugin.
const lsp = kclLanguage({
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
documentUri: `file:///${DEFAULT_FILE_NAME}`,
workspaceFolders: getWorkspaceFolders(),
client: kclLspClient,
})
@ -210,7 +211,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (isCopilotLspServerReady && !TEST && copilotLspClient) {
// Set up the lsp plugin.
const lsp = copilotPlugin({
documentUri: `file:///${PROJECT_ENTRYPOINT}`,
documentUri: `file:///${DEFAULT_FILE_NAME}`,
workspaceFolders: getWorkspaceFolders(),
client: copilotLspClient,
allowHTMLContent: true,
@ -235,7 +236,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
redirect: boolean
) => {
const currentFilePath = projectBasename(
file?.path || PROJECT_ENTRYPOINT,
file?.path || DEFAULT_FILE_NAME,
projectPath || ''
)
lspClients.forEach((lspClient) => {
@ -266,7 +267,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
if (file) {
// Send that the file was opened.
const filename = projectBasename(
file?.path || PROJECT_ENTRYPOINT,
file?.path || DEFAULT_FILE_NAME,
project?.path || ''
)
lspClients.forEach((lspClient) => {
@ -284,7 +285,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const onFileOpen = (filePath: string | null, projectPath: string | null) => {
const currentFilePath = projectBasename(
filePath || PROJECT_ENTRYPOINT,
filePath || DEFAULT_FILE_NAME,
projectPath || ''
)
lspClients.forEach((lspClient) => {
@ -301,7 +302,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
const onFileClose = (filePath: string | null, projectPath: string | null) => {
const currentFilePath = projectBasename(
filePath || PROJECT_ENTRYPOINT,
filePath || DEFAULT_FILE_NAME,
projectPath || ''
)
lspClients.forEach((lspClient) => {

Some files were not shown because too many files have changed in this diff Show More