Compare commits

...

26 Commits

Author SHA1 Message Date
bf36e62b97 Fmt 2024-08-20 15:41:38 +02:00
3e45d7ac4e A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu-latest) 2024-08-20 13:40:43 +00:00
259279fd53 Merge branch 'main' into franknoirot/fix-electron-use-sep 2024-08-20 09:37:13 -04:00
0ef6eac239 Fix existing: when engine fails export we handle the failure and alert the user (#3561)
Fix existing: when engine fails export we handle the failure and alert the user #3560
2024-08-20 20:29:15 +10:00
c674feb782 Update the Web Banner (#3563)
Update the Web Banner #3503
2024-08-20 20:28:39 +10:00
fba3d7c5c1 skip failing windows tests (#3558) 2024-08-20 06:37:16 +00:00
8b8fb696d0 Fix existing: Can edit a sketch that has been extruded in the same pipe (#3552)
Fix existing: Can edit a sketch that has been extruded in the same pipe #3551
2024-08-20 14:13:56 +10:00
d05f3c00b9 test keyboard shortcuts from help menu (#3553)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-08-19 20:17:23 -07:00
2541e0c0ea Electron test (regression): select all in code editor does not actually select all, just what is visiable (#3540)
* select all in code editor does not actually select all, just what is visible #3175

* whops

* fix test for linux
2024-08-20 11:23:32 +10:00
5e5a204244 move the file (#3544)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2024-08-19 17:55:26 -07:00
032c2fdd24 Add GitHub action to label issues opened by ZooSpiritWolf (#3543)
* Add GitHub action to label issues opened by ZooSpiritWolf

Fixes #3541

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/KittyCAD/modeling-app/issues/3541?shareId=XXXX-XXXX-XXXX-XXXX).

* Update label-issues.yml
2024-08-19 17:54:24 -07:00
27883e7800 Electron machine api tests (#3534)
* start

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

* updates

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

* fixes

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

* Look at this (photo)Graph *in the voice of Nickelback*

* updates

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

* fixes

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

* hide on webapp

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

* fixes

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

* fix machine-api

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-19 15:57:31 -07:00
1ccb810e23 Revert "electron test code with error loading" (#3533)
Revert "electron test code with error loading (#3531)"

This reverts commit c7f533b38e.
2024-08-19 14:23:01 -07:00
1c83f148d9 export on project/file pane load playwright test (#3489)
* export on project/file pane load

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

add desktop exxport

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

* updates

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

* Look at this (photo)Graph *in the voice of Nickelback*

* updates

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

* fix lint

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

* fixeds

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

* fixes

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

* fixups

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-19 14:21:34 -07:00
c7f533b38e electron test code with error loading (#3531)
* electron test code with error loading

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

* Look at this (photo)Graph *in the voice of Nickelback*

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-08-19 13:54:11 -07:00
2b711d216f Run eslint in CI (#3487)
* Run eslint in CI

* Add linting of e2e

* Fix formatting

* Fix new warnings in e2e

* Fix more new warnings
2024-08-19 12:36:18 -07:00
c67511f67c Electron test: (regression) you can scroll the file pane when ETOOMANYFILES to view in one view (#3520)
* can scroll files pane

* clean up
2024-08-20 05:34:26 +10:00
d9423219d1 Bump @csstools/postcss-oklab-function from 3.0.19 to 4.0.2 (#3517)
Bumps [@csstools/postcss-oklab-function](https://github.com/csstools/postcss-plugins/tree/HEAD/plugins/postcss-oklab-function) from 3.0.19 to 4.0.2.
- [Changelog](https://github.com/csstools/postcss-plugins/blob/main/plugins/postcss-oklab-function/CHANGELOG.md)
- [Commits](https://github.com/csstools/postcss-plugins/commits/HEAD/plugins/postcss-oklab-function)

---
updated-dependencies:
- dependency-name: "@csstools/postcss-oklab-function"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 12:29:10 -07:00
3f270d8bcf Bump react-router-dom from 6.26.0 to 6.26.1 (#3516)
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.26.0 to 6.26.1.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@6.26.1/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 12:28:59 -07:00
4c7b72329d Bump @playwright/test from 1.45.3 to 1.46.1 (#3514)
Bumps [@playwright/test](https://github.com/microsoft/playwright) from 1.45.3 to 1.46.1.
- [Release notes](https://github.com/microsoft/playwright/releases)
- [Commits](https://github.com/microsoft/playwright/compare/v1.45.3...v1.46.1)

---
updated-dependencies:
- dependency-name: "@playwright/test"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 12:27:12 -07:00
4c060f3d2f Bump electron from 31.3.1 to 31.4.0 (#3515)
Bumps [electron](https://github.com/electron/electron) from 31.3.1 to 31.4.0.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v31.3.1...v31.4.0)

---
updated-dependencies:
- dependency-name: electron
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 12:26:53 -07:00
f3afbe8a7b Bump @types/node from 18.19.42 to 22.4.1 (#3513)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.19.42 to 22.4.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 12:26:36 -07:00
dad7a84798 Bump tokio from 1.39.2 to 1.39.3 in /src/wasm-lib (#3511)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.39.2 to 1.39.3.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.39.2...tokio-1.39.3)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 12:26:03 -07:00
1a560fdc6a Bump syn from 2.0.74 to 2.0.75 in /src/wasm-lib (#3510)
Bumps [syn](https://github.com/dtolnay/syn) from 2.0.74 to 2.0.75.
- [Release notes](https://github.com/dtolnay/syn/releases)
- [Commits](https://github.com/dtolnay/syn/compare/2.0.74...2.0.75)

---
updated-dependencies:
- dependency-name: syn
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 12:25:53 -07:00
54eea741b5 Merge branch 'main' into franknoirot/fix-electron-use-sep 2024-08-19 12:24:01 -07:00
24cc00e9c5 Use sep utility instead of forward slash for path name parsing 2024-08-19 13:41:32 -04:00
44 changed files with 1124 additions and 315 deletions

View File

@ -25,6 +25,7 @@
"files": ["e2e/**/*.ts"], // Update the pattern based on your file structure
"rules": {
"@typescript-eslint/no-floating-promises": "warn",
"suggest-no-throw/suggest-no-throw": "off",
"testing-library/prefer-screen-queries": "off"
}
},

View File

@ -44,6 +44,8 @@ jobs:
- run: yarn build:wasm
- run: yarn xstate:typegen
- run: yarn tsc
- name: Lint
run: yarn eslint --max-warnings 0 src e2e
check-typos:

31
.github/workflows/label-issues.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: Label Issues
on:
issues:
types: [opened]
permissions:
issues: write
jobs:
label:
runs-on: ubuntu-latest
steps:
- name: Check if issue opener is ZooSpiritWolf
id: check_opener
uses: actions/github-script@v4
with:
script: |
const issueOpener = context.payload.issue.user.login;
return issueOpener === 'ZooSpiritWolf';
- name: Add labels
if: steps.check_opener.outputs.result == 'true'
uses: actions/github-script@v4
with:
script: |
github.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
labels: ['bug', 'regression', 'high-priority']
});

View File

@ -346,7 +346,7 @@ jobs:
run: yarn build:wasm
- name: build electron
shell: bash
run: yarn electron:package
run: yarn tron:package
- uses: actions/download-artifact@v4
if: ${{ !cancelled() && (success() || failure()) }}
continue-on-error: true

View File

@ -101,7 +101,7 @@ This will start the application and hot-reload on changed.
Devtools can be opened with the usual Cmd/Ctrl-Shift-I.
To build, run `yarn electron:package`.
To build, run `yarn tron:package`.
## Checking out commits / Bisecting

View File

@ -9,6 +9,7 @@ test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test.describe('Copilot ghost text', () => {
// eslint-disable-next-line jest/valid-title
test.skip(true, 'Needs to get covered again')
test('completes code in empty file', async ({ page }) => {

View File

@ -0,0 +1,188 @@
import { test, expect } from '@playwright/test'
import { getUtils, setupElectron, tearDown } from './test-utils'
import fsp from 'fs/promises'
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test(
'export works on the first try',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await Promise.all([fsp.mkdir(`${dir}/bracket`, { recursive: true })])
await Promise.all([
fsp.copyFile(
'src/wasm-lib/tests/executor/inputs/router-template-slate.kcl',
`${dir}/bracket/other.kcl`
),
fsp.copyFile(
'src/wasm-lib/tests/executor/inputs/focusrite_scarlett_mounting_braket.kcl',
`${dir}/bracket/main.kcl`
),
])
},
})
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await test.step('on open of project', async () => {
await expect(page.getByText(`bracket`)).toBeVisible()
// open the project
await page.getByText(`bracket`).click()
// wait for the project to load
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
// expect zero errors in guter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// export the model
const exportButton = page.getByTestId('export-pane-button')
await expect(exportButton).toBeVisible()
const gltfOption = page.getByText('glTF')
const submitButton = page.getByText('Confirm Export')
const exportingToastMessage = page.getByText(`Exporting...`)
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
// Click the export button
await exportButton.click()
await expect(gltfOption).toBeVisible()
await expect(page.getByText('STL')).toBeVisible()
await page.keyboard.press('Enter')
// Click the checkbox
await expect(submitButton).toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter')
// Find the toast.
// Look out for the toast message
await expect(exportingToastMessage).toBeVisible()
await expect(alreadyExportingToastMessage).not.toBeVisible()
// Expect it to succeed.
await expect(errorToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible()
const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible()
await expect(exportingToastMessage).not.toBeVisible()
await test.step('Check the export size', async () => {
await expect
.poll(
async () => {
try {
const outputGltf = await fsp.readFile('output.gltf')
return outputGltf.byteLength
} catch (e) {
return 0
}
},
{ timeout: 15_000 }
)
.toBe(477327)
// clean up output.gltf
await fsp.rm('output.gltf')
})
})
await test.step('on open of file in file pane', async () => {
const u = await getUtils(page)
await u.openFilePanel()
const otherKclButton = page.getByRole('button', { name: 'other.kcl' })
// Click the file
await otherKclButton.click()
// Close the file pane
await u.closeFilePanel()
// wait for it to finish executing (todo: make this more robust)
await page.waitForTimeout(1000)
// expect zero errors in guter
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// export the model
const exportButton = page.getByTestId('export-pane-button')
await expect(exportButton).toBeVisible()
const gltfOption = page.getByText('glTF')
const submitButton = page.getByText('Confirm Export')
const exportingToastMessage = page.getByText(`Exporting...`)
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
// Click the export button
await exportButton.click()
await expect(gltfOption).toBeVisible()
await expect(page.getByText('STL')).toBeVisible()
await page.keyboard.press('Enter')
// Click the checkbox
await expect(submitButton).toBeVisible()
await page.keyboard.press('Enter')
// Find the toast.
// Look out for the toast message
await expect(exportingToastMessage).toBeVisible()
await expect(alreadyExportingToastMessage).not.toBeVisible()
// Expect it to succeed.
await expect(errorToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible()
const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible()
await expect(exportingToastMessage).not.toBeVisible()
await test.step('Check the export size', async () => {
await expect
.poll(
async () => {
try {
const outputGltf = await fsp.readFile('output.gltf')
return outputGltf.byteLength
} catch (e) {
return 0
}
},
{ timeout: 15_000 }
)
.toBe(105022)
// clean up output.gltf
await fsp.rm('output.gltf')
})
await electronApp.close()
})
await electronApp.close()
}
)

View File

@ -714,17 +714,15 @@ test.describe('Editor tests', () => {
|> close(%)`)
})
// failing for the same reason as "Can edit a sketch that has been extruded in the same pipe"
// please fix together
test.fixme('Can undo a sketch modification with ctrl+z', async ({ page }) => {
test('Can undo a sketch modification with ctrl+z', async ({ page }) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %)
|> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %)
|> tangentialArcTo([24.95, -0.38], %)
|> close(%)
|> extrude(5, %)`
)
@ -759,11 +757,11 @@ test.describe('Editor tests', () => {
})
await page.waitForTimeout(100)
const startPX = [665, 458]
const startPX = [665, 397]
const dragPX = 40
await page.getByText('startProfileAt([4.61, -14.01], %)').click()
await page.getByText('startProfileAt([4.61, -10.01], %)').click()
await expect(
page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible()
@ -801,7 +799,7 @@ test.describe('Editor tests', () => {
// drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x, y: tangentEnd.y - 5 },
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
targetPosition: {
x: tangentEnd.x + dragPX,
y: tangentEnd.y + dragPX,
@ -813,12 +811,12 @@ test.describe('Editor tests', () => {
// expect the code to have changed
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -16.82], %)
|> line([15.4, -2.74], %)
|> tangentialArcTo([24.95, -5.38], %)
|> line([2.65, -2.69], %)
|> close(%)
|> extrude(5, %)`)
|> startProfileAt([7.12, -12.68], %)
|> line([15.39, -2.78], %)
|> tangentialArcTo([27.6, -3.05], %)
|> close(%)
|> extrude(5, %)
`)
// Hit undo
await page.keyboard.down('Control')
@ -827,11 +825,11 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -16.82], %)
|> line([15.4, -2.74], %)
|> tangentialArcTo([24.95, -5.38], %)
|> close(%)
|> extrude(5, %)`)
|> startProfileAt([7.12, -12.68], %)
|> line([15.39, -2.78], %)
|> tangentialArcTo([24.95, -0.38], %)
|> close(%)
|> extrude(5, %)`)
// Hit undo again.
await page.keyboard.down('Control')
@ -840,11 +838,12 @@ test.describe('Editor tests', () => {
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -16.82], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %)
|> close(%)
|> extrude(5, %)`)
|> startProfileAt([7.12, -12.68], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -0.38], %)
|> close(%)
|> extrude(5, %)
`)
// Hit undo again.
await page.keyboard.down('Control')
@ -854,9 +853,9 @@ test.describe('Editor tests', () => {
await page.waitForTimeout(100)
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %)
|> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %)
|> tangentialArcTo([24.95, -0.38], %)
|> close(%)
|> extrude(5, %)`)
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 71 KiB

View File

@ -0,0 +1,102 @@
import { test, expect } from '@playwright/test'
import { setupElectron, tearDown } from './test-utils'
import fsp from 'fs/promises'
test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test(
'When machine-api server not found butt is disabled and shows the reason',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(`${dir}/bracket`, { recursive: true })
await fsp.copyFile(
'src/wasm-lib/tests/executor/inputs/focusrite_scarlett_mounting_braket.kcl',
`${dir}/bracket/main.kcl`
)
},
})
await page.setViewportSize({ width: 1200, height: 500 })
await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
const notFoundText = 'Machine API server was not discovered'
await expect(page.getByText(notFoundText).first()).not.toBeVisible()
// Find the make button
const makeButton = page.getByRole('button', { name: 'Make' })
// Make sure the button is visible but disabled
await expect(makeButton).toBeVisible()
await expect(makeButton).toBeDisabled()
// When you hover over the button, the tooltip should show
// that the machine-api server is not found
await makeButton.hover()
await expect(page.getByText(notFoundText).first()).toBeVisible()
await electronApp.close()
}
)
test(
'When machine-api server not found home screen & project status shows the reason',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(`${dir}/bracket`, { recursive: true })
await fsp.copyFile(
'src/wasm-lib/tests/executor/inputs/focusrite_scarlett_mounting_braket.kcl',
`${dir}/bracket/main.kcl`
)
},
})
await page.setViewportSize({ width: 1200, height: 500 })
const notFoundText = 'Machine API server was not discovered'
await expect(page.getByText(notFoundText)).not.toBeVisible()
const networkMachineToggle = page.getByTestId('network-machine-toggle')
await networkMachineToggle.hover()
await expect(page.getByText(notFoundText)).toBeVisible()
await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await expect(page.getByText(notFoundText).nth(1)).not.toBeVisible()
await networkMachineToggle.hover()
await expect(page.getByText(notFoundText).nth(1)).toBeVisible()
await electronApp.close()
}
)

View File

@ -347,6 +347,10 @@ test(
'Restarting onboarding on desktop takes one attempt',
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {

View File

@ -2,6 +2,7 @@ import { test, expect } from '@playwright/test'
import {
doExport,
getUtils,
isOutOfViewInScrollContainer,
Paths,
setupElectron,
tearDown,
@ -14,10 +15,128 @@ test.afterEach(async ({ page }, testInfo) => {
await tearDown(page, testInfo)
})
test(
'click help/keybindings from home page',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async () => {},
})
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
// click ? button
await page.getByTestId('help-button').click()
await expect(page.getByTestId('keybindings-button')).toBeVisible()
// Click keyboard shortcuts button.
await page.getByTestId('keybindings-button').click()
// Make sure the keyboard shortcuts modal is visible.
await expect(page.getByText('Enter Sketch Mode')).toBeVisible()
await electronApp.close()
}
)
test(
'click help/keybindings from project page',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(`${dir}/bracket`, { recursive: true })
await fsp.copyFile(
'src/wasm-lib/tests/executor/inputs/focusrite_scarlett_mounting_braket.kcl',
`${dir}/bracket/main.kcl`
)
},
})
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
page.on('console', console.log)
// expect to see the text bracket
await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
// click ? button
await page.getByTestId('help-button').click()
await expect(page.getByTestId('keybindings-button')).toBeVisible()
// Click keyboard shortcuts button.
await page.getByTestId('keybindings-button').click()
// Make sure the keyboard shortcuts modal is visible.
await expect(page.getByText('Enter Sketch Mode')).toBeVisible()
await electronApp.close()
}
)
test(
'when code with error first loads you get errors in console',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(`${dir}/broken-code`, { recursive: true })
await fsp.copyFile(
'src/wasm-lib/tests/executor/inputs/broken-code-test.kcl',
`${dir}/broken-code/main.kcl`
)
},
})
await page.setViewportSize({ width: 1200, height: 500 })
await expect(page.getByText('broken-code')).toBeVisible()
await page.getByText('broken-code').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
// error in guter
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
// error text on hover
await page.hover('.cm-lint-marker-error')
const crypticErrorText = `Expected a tag declarator`
await expect(page.getByText(crypticErrorText).first()).toBeVisible()
await electronApp.close()
}
)
test(
'Can export from electron app',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
@ -106,6 +225,10 @@ test(
'Rename and delete projects, also spam arrow keys when renaming',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
@ -394,6 +517,10 @@ test(
'Deleting projects, can delete individual project, can still create projects after deleting all',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
})
@ -488,6 +615,10 @@ test(
'Can sort projects on home page',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
})
@ -610,6 +741,10 @@ test(
'When the project folder is empty, user can create new project and open it.',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({ testInfo })
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
@ -694,6 +829,10 @@ test(
'Opening a project should successfully load the stream, (regression test that this also works when switching between projects)',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
@ -907,6 +1046,10 @@ test(
'Search projects on desktop home',
{ tag: '@electron' },
async ({ browserName: _ }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const projectData = [
['basic bracket', 'focusrite_scarlett_mounting_braket.kcl'],
['basic-cube', 'basic_fillet_cube_end.kcl'],
@ -964,10 +1107,198 @@ test(
}
)
test(
'file pane is scrollable when there are many files',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
await fsp.mkdir(`${dir}/testProject`, { recursive: true })
const fileNames = [
'angled_line.kcl',
'basic_fillet_cube_close_opposite.kcl',
'basic_fillet_cube_end.kcl',
'basic_fillet_cube_next_adjacent.kcl',
'basic_fillet_cube_previous_adjacent.kcl',
'basic_fillet_cube_start.kcl',
'big_number_angle_to_match_length_x.kcl',
'big_number_angle_to_match_length_y.kcl',
'close_arc.kcl',
'computed_var.kcl',
'cube-embedded.gltf',
'cube.bin',
'cube.glb',
'cube.gltf',
'cube.kcl',
'cube.mtl',
'cube.obj',
'cylinder.kcl',
'dimensions_match.kcl',
'extrude-custom-plane.kcl',
'extrude-inside-fn-with-tags.kcl',
'fillet-and-shell.kcl',
'fillet_duplicate_tags.kcl',
'focusrite_scarlett_mounting_braket.kcl',
'function_sketch.kcl',
'function_sketch_with_position.kcl',
'global-tags.kcl',
'helix_ccw.kcl',
'helix_defaults.kcl',
'helix_defaults_negative_extrude.kcl',
'helix_with_length.kcl',
'i_shape.kcl',
'kittycad_svg.kcl',
'lego.kcl',
'math.kcl',
'member_expression_sketch_group.kcl',
'mike_stress_test.kcl',
'negative_args.kcl',
'order-sketch-extrude-in-order.kcl',
'order-sketch-extrude-out-of-order.kcl',
'parametric.kcl',
'parametric_with_tan_arc.kcl',
'pattern_vase.kcl',
'pentagon_fillet_sugar.kcl',
'pipe_as_arg.kcl',
'pipes_on_pipes.kcl',
'riddle.kcl',
'riddle_small.kcl',
'router-template-slate.kcl',
'scoped-tags.kcl',
'server-rack-heavy.kcl',
'server-rack-lite.kcl',
'sketch_on_face.kcl',
'sketch_on_face_circle_tagged.kcl',
'sketch_on_face_end.kcl',
'sketch_on_face_end_negative_extrude.kcl',
'sketch_on_face_start.kcl',
'tan_arc_x_line.kcl',
'tangential_arc.kcl',
]
for (const fileName of fileNames) {
await fsp.copyFile(
`src/wasm-lib/tests/executor/inputs/${fileName}`,
`${dir}/testProject/${fileName}`
)
}
},
})
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await test.step('setup, open file pane', async () => {
await page.getByText('testProject').click()
await expect(page.getByTestId('loading')).toBeAttached()
await expect(page.getByTestId('loading')).not.toBeAttached({
timeout: 20_000,
})
await page.getByTestId('files-pane-button').click()
})
await test.step('check the last file is out of view initially, and can be scrolled to', async () => {
const element = page.getByText('tangential_arc.kcl')
const container = page.getByTestId('file-pane-scroll-container')
await expect(await isOutOfViewInScrollContainer(element, container)).toBe(
true
)
await element.scrollIntoViewIfNeeded()
await expect(await isOutOfViewInScrollContainer(element, container)).toBe(
false
)
})
await electronApp.close()
}
)
test(
'select all in code editor does not actually select all, just what is visible (regression)',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
// src/wasm-lib/tests/executor/inputs/mike_stress_test.kcl
const name = 'mike_stress_test'
await fsp.mkdir(`${dir}/${name}`, { recursive: true })
await fsp.copyFile(
`src/wasm-lib/tests/executor/inputs/${name}.kcl`,
`${dir}/${name}/main.kcl`
)
},
})
const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 })
page.on('console', console.log)
await page.getByText('mike_stress_test').click()
const modifier =
process.platform === 'win32' || process.platform === 'linux'
? 'Control'
: 'Meta'
await test.step('select all in code editor, check its length', async () => {
await u.codeLocator.click()
// expect u.codeLocator to have some text
await expect(u.codeLocator).toContainText('line(')
await page.keyboard.down(modifier)
await page.keyboard.press('KeyA')
await page.keyboard.up(modifier)
// check the length of the selected text
const selectedText = await page.evaluate(() => {
const selection = window.getSelection()
return selection ? selection.toString() : ''
})
// even though if the user copied the text into their clipboard they would get the full text
// it seems that the selection is limited to what is visible
// we just want to check we did select something, and later we've verify it's empty
expect(selectedText.length).toBeGreaterThan(10)
})
await test.step('delete all the text, select again and verify there are no characters left', async () => {
await page.keyboard.press('Backspace')
await page.keyboard.down(modifier)
await page.keyboard.press('KeyA')
await page.keyboard.up(modifier)
// check the length of the selected text
const selectedText = await page.evaluate(() => {
const selection = window.getSelection()
return selection ? selection.toString() : ''
})
expect(selectedText.length).toBe(0)
await expect(u.codeLocator).toHaveText('')
})
await electronApp.close()
}
)
test(
'Settings persist across restarts',
{ tag: '@electron' },
async ({ browserName }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
await test.step('We can change a user setting like theme', async () => {
const { electronApp, page } = await setupElectron({
testInfo,

View File

@ -236,9 +236,13 @@ const sketch001 = startSketchAt([-0, -0])
page,
}) => {
const u = await getUtils(page)
await page.addInitScript(async (code) => {
localStorage.setItem('persistCode', code)
}, TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR)
await page.addInitScript(
async ({ code }) => {
localStorage.setItem('persistCode', code)
;(window as any).playwrightSkipFilePicker = true
},
{ code: TEST_CODE_TRIGGER_ENGINE_EXPORT_ERROR }
)
await page.setViewportSize({ width: 1000, height: 500 })
@ -325,7 +329,7 @@ const sketch001 = startSketchAt([-0, -0])
await expect(exportingToastMessage).toBeVisible()
// Expect it to succeed.
await expect(exportingToastMessage).not.toBeVisible()
await expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 })
await expect(errorToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible()
@ -337,6 +341,7 @@ const sketch001 = startSketchAt([-0, -0])
}) => {
// This is being weird on ubuntu and windows.
test.skip(
// eslint-disable-next-line jest/valid-title
process.platform === 'linux' || process.platform === 'win32',
'This test is being weird on ubuntu'
)
@ -420,6 +425,10 @@ const sketch001 = startSketchAt([-0, -0])
`Network health indicator only appears in modeling view`,
{ tag: '@electron' },
async ({ browserName: _ }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
@ -472,7 +481,7 @@ async function clickExportButton(page: Page) {
// Click the export button
await exportButton.click()
// Click the stl.
// Click the gltf.
const gltfOption = page.getByRole('option', { name: 'glTF' })
await expect(gltfOption).toBeVisible()

View File

@ -344,111 +344,108 @@ test.describe('Sketch tests', () => {
})
})
// failing for the same reason as "Can undo a sketch modification with ctrl+z"
// please fix together
test.fixme(
'Can edit a sketch that has been extruded in the same pipe',
async ({ page }) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -14.01], %)
test('Can edit a sketch that has been extruded in the same pipe', async ({
page,
}) => {
const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`const sketch001 = startSketchOn('XZ')
|> startProfileAt([4.61, -10.01], %)
|> line([12.73, -0.09], %)
|> tangentialArcTo([24.95, -5.38], %)
|> tangentialArcTo([24.95, -0.38], %)
|> close(%)
|> extrude(5, %)`
)
})
)
})
await page.setViewportSize({ width: 1200, height: 500 })
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await u.waitForAuthSkipAppStart()
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).not.toBeDisabled()
await page.waitForTimeout(100)
await u.openAndClearDebugPanel()
await u.sendCustomCmd({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
vantage: { x: 0, y: -1250, z: 580 },
center: { x: 0, y: 0, z: 0 },
up: { x: 0, y: 0, z: 1 },
},
})
await page.waitForTimeout(100)
await u.sendCustomCmd({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
})
await page.waitForTimeout(100)
await page.waitForTimeout(100)
await u.openAndClearDebugPanel()
await u.sendCustomCmd({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_look_at',
vantage: { x: 0, y: -1250, z: 580 },
center: { x: 0, y: 0, z: 0 },
up: { x: 0, y: 0, z: 1 },
},
})
await page.waitForTimeout(100)
await u.sendCustomCmd({
type: 'modeling_cmd_req',
cmd_id: uuidv4(),
cmd: {
type: 'default_camera_get_settings',
},
})
await page.waitForTimeout(100)
const startPX = [665, 458]
const startPX = [665, 397]
const dragPX = 40
const dragPX = 40
await page.getByText('startProfileAt([4.61, -14.01], %)').click()
await expect(
page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible()
await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(400)
let prevContent = await page.locator('.cm-content').innerText()
await page.getByText('startProfileAt([4.61, -10.01], %)').click()
await expect(
page.getByRole('button', { name: 'Edit Sketch' })
).toBeVisible()
await page.getByRole('button', { name: 'Edit Sketch' }).click()
await page.waitForTimeout(400)
let prevContent = await page.locator('.cm-content').innerText()
await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
await expect(page.getByTestId('segment-overlay')).toHaveCount(2)
// drag startProfieAt handle
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: startPX[0], y: startPX[1] },
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
})
await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText()
// drag startProfieAt handle
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: startPX[0], y: startPX[1] },
targetPosition: { x: startPX[0] + dragPX, y: startPX[1] + dragPX },
})
await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText()
// drag line handle
await page.waitForTimeout(100)
// drag line handle
await page.waitForTimeout(100)
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
await page.waitForTimeout(100)
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
})
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText()
const lineEnd = await u.getBoundingBox('[data-overlay-index="0"]')
await page.waitForTimeout(100)
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: lineEnd.x - 5, y: lineEnd.y },
targetPosition: { x: lineEnd.x + dragPX, y: lineEnd.y + dragPX },
})
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
prevContent = await page.locator('.cm-content').innerText()
// drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x, y: tangentEnd.y - 5 },
targetPosition: {
x: tangentEnd.x + dragPX,
y: tangentEnd.y + dragPX,
},
})
await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// drag tangentialArcTo handle
const tangentEnd = await u.getBoundingBox('[data-overlay-index="1"]')
await page.dragAndDrop('#stream', '#stream', {
sourcePosition: { x: tangentEnd.x + 10, y: tangentEnd.y - 5 },
targetPosition: {
x: tangentEnd.x + dragPX,
y: tangentEnd.y + dragPX,
},
})
await page.waitForTimeout(100)
await expect(page.locator('.cm-content')).not.toHaveText(prevContent)
// expect the code to have changed
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -16.82], %)
|> line([15.4, -2.74], %)
|> tangentialArcTo([24.95, -5.38], %)
|> line([2.65, -2.69], %)
|> close(%)
|> extrude(5, %)`)
}
)
// expect the code to have changed
await expect(page.locator('.cm-content'))
.toHaveText(`const sketch001 = startSketchOn('XZ')
|> startProfileAt([7.12, -12.68], %)
|> line([15.39, -2.78], %)
|> tangentialArcTo([27.6, -3.05], %)
|> close(%)
|> extrude(5, %)
`)
})
test('Can edit a sketch that has been revolved in the same pipe', async ({
page,
@ -602,7 +599,7 @@ test.describe('Sketch tests', () => {
await expect(u.codeLocator).toHaveText(codeStr)
// exit the sketch, reset relative clicker
click00r(undefined, undefined)
await click00r(undefined, undefined)
await u.openAndClearDebugPanel()
await page.getByRole('button', { name: 'Exit Sketch' }).click()
await u.expectCmdLog('[data-message-type="execution-done"]')

View File

@ -53,6 +53,7 @@ test(
async ({ page, context }) => {
// skip on macos and windows.
test.skip(
// eslint-disable-next-line jest/valid-title
process.platform === 'darwin' || process.platform === 'win32',
'Skip on macos and windows'
)

View File

@ -5,6 +5,7 @@ import {
TestInfo,
BrowserContext,
_electron as electron,
Locator,
} from '@playwright/test'
import { EngineCommand } from 'lang/std/artifactGraph'
import os from 'os'
@ -94,6 +95,8 @@ async function expectCmdLog(page: Page, locatorStr: string, timeout = 5000) {
await expect(page.locator(locatorStr).last()).toBeVisible({ timeout })
}
// Ignoring the lint since I assume someone will want to use this for a test.
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function waitForDefaultPlanesToBeVisible(page: Page) {
await page.waitForFunction(
() =>
@ -145,6 +148,27 @@ async function closeDebugPanel(page: Page) {
}
}
async function openFilePanel(page: Page) {
const fileLocator = page.getByTestId('files-pane-button')
await expect(fileLocator).toBeVisible()
const isOpen = (await fileLocator?.getAttribute('aria-pressed')) === 'true'
if (!isOpen) {
await fileLocator.click()
await expect(fileLocator).toHaveAttribute('aria-pressed', 'true')
}
}
async function closeFilePanel(page: Page) {
const fileLocator = page.getByTestId('files-pane-button')
await expect(fileLocator).toBeVisible()
const isOpen = (await fileLocator?.getAttribute('aria-pressed')) === 'true'
if (isOpen) {
await fileLocator.click()
await expect(fileLocator).not.toHaveAttribute('aria-pressed', 'true')
}
}
async function waitForCmdReceive(page: Page, commandType: string) {
return page
.locator(`[data-receive-command-type="${commandType}"]`)
@ -171,7 +195,8 @@ export const wiggleMove = async (
const isElVis = await page.locator(locator).isVisible()
if (isElVis) return
}
const [x1, y1] = [0, Math.sin((tau / steps) * j * freq) * amplitude]
// x1 is 0.
const y1 = Math.sin((tau / steps) * j * freq) * amplitude
const [x2, y2] = [
Math.cos(-ang * deg) * i - Math.sin(-ang * deg) * y1,
Math.sin(-ang * deg) * i + Math.cos(-ang * deg) * y1,
@ -317,6 +342,8 @@ export async function getUtils(page: Page) {
closeKclCodePanel: () => closeKclCodePanel(page),
openDebugPanel: () => openDebugPanel(page),
closeDebugPanel: () => closeDebugPanel(page),
openFilePanel: () => openFilePanel(page),
closeFilePanel: () => closeFilePanel(page),
openAndClearDebugPanel: async () => {
await openDebugPanel(page)
return clearCommandLogs(page)
@ -452,7 +479,10 @@ export async function getUtils(page: Page) {
return page.evaluate('window.tearDown()')
}
cdpSession?.send('Network.emulateNetworkConditions', networkOptions)
return cdpSession?.send(
'Network.emulateNetworkConditions',
networkOptions
)
},
}
}
@ -745,3 +775,22 @@ export async function setupElectron({
return { electronApp, page }
}
export async function isOutOfViewInScrollContainer(
element: Locator,
container: Locator
): Promise<boolean> {
const elementBox = await element.boundingBox({ timeout: 5_000 })
const containerBox = await container.boundingBox({ timeout: 5_000 })
let isOutOfView = false
if (elementBox && containerBox)
return (
elementBox.y + elementBox.height > containerBox.y + containerBox.height ||
elementBox.y < containerBox.y ||
elementBox.x + elementBox.width > containerBox.x + containerBox.width ||
elementBox.x < containerBox.x
)
return isOutOfView
}

View File

@ -72,7 +72,7 @@ test.describe('Testing constraints', () => {
page.getByRole('button', { name: 'Exit Sketch' })
).not.toBeVisible()
})
test(`Test remove constraints`, async ({ page }) => {
test(`Remove constraints`, async ({ page }) => {
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',

View File

@ -977,10 +977,6 @@ const part001 = startSketchOn('XZ')
const hoverPos = { x: segmentToDelete.x, y: segmentToDelete.y }
await page.mouse.move(0, 0)
await page.waitForTimeout(1000)
let x = 0,
y = 0
x = hoverPos.x + Math.cos(ang * deg) * 32
y = hoverPos.y - Math.sin(ang * deg) * 32
await page.mouse.move(hoverPos.x, hoverPos.y)
await wiggleMove(
page,

View File

@ -4,7 +4,6 @@ import { getUtils, setup, setupElectron, tearDown } from './test-utils'
import { SaveSettingsPayload } from 'lib/settings/settingsTypes'
import { TEST_SETTINGS_KEY, TEST_SETTINGS_CORRUPTED } from './storageStates'
import * as TOML from '@iarna/toml'
import { APP_NAME } from 'lib/constants'
test.beforeEach(async ({ context, page }) => {
await setup(context, page)
@ -193,6 +192,10 @@ test.describe('Testing settings', () => {
`Project settings override user settings on desktop`,
{ tag: '@electron' },
async ({ browser: _ }, testInfo) => {
test.skip(
process.platform === 'win32',
'TODO: remove this skip https://github.com/KittyCAD/modeling-app/issues/3557'
)
const { electronApp, page } = await setupElectron({
testInfo,
folderSetupFn: async (dir) => {
@ -205,7 +208,6 @@ test.describe('Testing settings', () => {
})
await page.setViewportSize({ width: 1200, height: 500 })
const u = await getUtils(page)
page.on('console', console.log)

View File

@ -1,7 +1,5 @@
import { test, expect, Page } from '@playwright/test'
import * as fsp from 'fs/promises'
import { getUtils, setup, setupElectron, tearDown } from './test-utils'
import { join } from 'path'
import { getUtils, setup, tearDown } from './test-utils'
test.beforeEach(async ({ context, page }) => {
await setup(context, page)

View File

@ -19,7 +19,7 @@
"@codemirror/search": "^6.5.6",
"@codemirror/state": "^6.4.1",
"@codemirror/theme-one-dark": "^6.1.2",
"@csstools/postcss-oklab-function": "^3.0.16",
"@csstools/postcss-oklab-function": "^4.0.2",
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2",
@ -53,7 +53,7 @@
"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.26.1",
"sketch-helpers": "^0.0.4",
"three": "^0.166.1",
"ua-parser-js": "^1.0.37",
@ -86,17 +86,17 @@
"build:wasm-clean": "yarn wasm-prep && yarn build:wasm",
"remove-importmeta": "sed -i 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\"; sed -i '' 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\" || echo \"sed for both mac and linux\"",
"wasm-prep": "rm -rf src/wasm-lib/pkg && mkdir src/wasm-lib/pkg && rm -rf src/wasm-lib/kcl/bindings",
"lint": "eslint --fix src",
"lint": "eslint --fix src e2e",
"bump-jsons": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json && echo \"$(jq --arg v \"$VERSION\" '.version=$v' src-tauri/tauri.conf.json --indent 2)\" > src-tauri/tauri.conf.json",
"postinstall": "yarn xstate:typegen",
"xstate:typegen": "yarn xstate typegen \"src/**/*.ts?(x)\"",
"make:dev": "make dev",
"generate:machine-api": "npx openapi-typescript ./openapi/machine-api.json -o src/lib/machine-api.d.ts",
"electron:start": "electron-forge start",
"electron:package": "electron-forge package",
"electron:make": "electron-forge make",
"electron:publish": "electron-forge publish",
"electron:e2e:local": "NODE_ENV=development yarn playwright test --config=playwright.electron.config.ts --grep=@electron"
"tron:start": "electron-forge start",
"tron:package": "electron-forge package",
"tron:make": "electron-forge make",
"tron:publish": "electron-forge publish",
"tron:test": "NODE_ENV=development yarn playwright test --config=playwright.electron.config.ts --grep=@electron"
},
"prettier": {
"trailingComma": "es5",
@ -130,14 +130,14 @@
"@electron/fuses": "^1.8.0",
"@iarna/toml": "^2.2.5",
"@lezer/generator": "^1.7.1",
"@playwright/test": "^1.45.1",
"@playwright/test": "^1.46.1",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^15.0.2",
"@types/d3-force": "^3.0.10",
"@types/electron": "^1.6.10",
"@types/isomorphic-fetch": "^0.0.39",
"@types/mocha": "^10.0.6",
"@types/node": "^18.19.31",
"@types/node": "^22.4.1",
"@types/pixelmatch": "^5.2.6",
"@types/pngjs": "^6.0.4",
"@types/react": "^18.3.2",
@ -156,7 +156,7 @@
"@xstate/cli": "^0.5.17",
"autoprefixer": "^10.4.19",
"d3-force": "^3.0.0",
"electron": "^31.2.1",
"electron": "^31.4.0",
"eslint": "^8.0.1",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-css-modules": "^2.12.0",

View File

@ -185,6 +185,8 @@ export function Toolbar({
maybeIconConfig[0].disabled
}
name={maybeIconConfig[0].title}
// aria-description is still in ARIA 1.3 draft.
// eslint-disable-next-line jsx-a11y/aria-props
aria-description={maybeIconConfig[0].description}
onClick={() =>
maybeIconConfig[0].onClick(configCallbackProps)
@ -225,6 +227,8 @@ export function Toolbar({
(!itemConfig.showTitle ? ' !px-0' : '')
}
name={itemConfig.title}
// aria-description is still in ARIA 1.3 draft.
// eslint-disable-next-line jsx-a11y/aria-props
aria-description={itemConfig.description}
aria-pressed={itemConfig.isActive}
disabled={

View File

@ -52,24 +52,21 @@ const DownloadAppBanner = () => {
</a>{' '}
to download the app for the best experience.
</p>
<p className="mt-6">
If you're on Linux and the browser is your only way to use the app,
you can permanently dismiss this banner by{' '}
<a
onClick={() => {
setIsBannerDismissed(true)
settings.send({
type: 'set.app.dismissWebBanner',
data: { level: 'user', value: true },
})
}}
href="/"
className="!text-warn-80 dark:!text-warn-80 dark:hover:!text-warn-70 underline"
>
toggling the App &gt; Dismiss Web Banner setting
</a>
.
</p>
{!navigator?.userAgent.includes('Chrome') && (
<p className="mt-6">
If you want to stay here on the web-app, we currently only support
Chrome. Please use{' '}
<a
href="https://www.google.com/chrome/"
rel="noopener noreferrer"
target="_blank"
className="!text-warn-80 dark:!text-warn-80 dark:hover:!text-warn-70 underline"
>
this link
</a>{' '}
to download it.
</p>
)}
</div>
</Dialog.Panel>
</Dialog>

View File

@ -464,7 +464,10 @@ export const FileTreeInner = ({
}, [documentHasFocus])
return (
<div className="overflow-auto pb-12 absolute inset-0">
<div
className="overflow-auto pb-12 absolute inset-0"
data-testid="file-pane-scroll-container"
>
<ul
className="m-0 p-0 text-sm"
onClickCapture={(e) => {

View File

@ -23,7 +23,10 @@ export function HelpMenu(props: React.PropsWithChildren) {
return (
<Popover className="relative">
<Popover.Button className="grid p-0 m-0 border-none rounded-full place-content-center">
<Popover.Button
className="grid p-0 m-0 border-none rounded-full place-content-center"
data-testid="help-button"
>
<CustomIcon
name="questionMark"
className="rounded-full w-7 h-7 bg-chalkboard-110 dark:bg-chalkboard-80 text-chalkboard-10"
@ -95,6 +98,7 @@ export function HelpMenu(props: React.PropsWithChildren) {
: PATHS.HOME + PATHS.SETTINGS_KEYBINDINGS
navigate(targetPath)
}}
data-testid="keybindings-button"
>
Keyboard shortcuts
</HelpMenuItem>

View File

@ -63,8 +63,10 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
data: { name: 'Make', groupId: 'modeling' },
})
},
hide: () => machineManager.machineCount() === 0,
hideOnPlatform: 'web',
hide: () => !isDesktop(),
disable: () => {
return machineManager.noMachinesReason()
},
},
]
const filteredActions: SidebarAction[] = sidebarActions.filter(
@ -186,6 +188,7 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
iconSize: 'md',
}}
onClick={action.action}
disabledText={action.disable?.()}
/>
))}
</ul>
@ -238,6 +241,7 @@ interface ModelingPaneButtonProps
onClick: () => void
paneIsOpen?: boolean
showBadge?: BadgeInfoComputed
disabledText?: string
}
function ModelingPaneButton({
@ -245,6 +249,7 @@ function ModelingPaneButton({
onClick,
paneIsOpen,
showBadge,
disabledText,
...props
}: ModelingPaneButtonProps) {
useHotkeys(paneConfig.keybinding, onClick, {
@ -258,6 +263,8 @@ function ModelingPaneButton({
onClick={onClick}
name={paneConfig.title}
data-testid={paneConfig.id + '-pane-button'}
disabled={disabledText !== undefined}
aria-disabled={disabledText !== undefined}
{...props}
>
<ActionIcon
@ -284,6 +291,7 @@ function ModelingPaneButton({
>
<span className="flex-1">
{paneConfig.title}
{disabledText !== undefined ? ` (${disabledText})` : ''}
{paneIsOpen !== undefined ? ` pane` : ''}
</span>
<kbd className="hotkey text-xs capitalize">
@ -326,4 +334,5 @@ export type SidebarAction = {
action: () => void
hideOnPlatform?: 'desktop' | 'web'
hide?: boolean | (() => boolean)
disable?: () => string | undefined
}

View File

@ -9,7 +9,9 @@ export const NetworkMachineIndicator = ({
}: {
className?: string
}) => {
const machineCount = Object.keys(machineManager.machines).length
const machineCount = machineManager.machineCount()
const reason = machineManager.noMachinesReason()
return isDesktop() ? (
<Popover className="relative">
<Popover.Button
@ -26,7 +28,7 @@ export const NetworkMachineIndicator = ({
</p>
)}
<Tooltip position="top-right" wrapperClassName="ui-open:hidden">
Network machines ({machineCount})
Network machines ({machineCount}) {reason && `: ${reason}`}
</Tooltip>
</Popover.Button>
<Popover.Panel

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 180 KiB

View File

@ -154,10 +154,6 @@ export function buildCommandArgument<
} satisfies Omit<CommandArgument<O, T>, 'inputType'>
if (arg.inputType === 'options') {
if (!(arg.options || arg.optionsFromContext)) {
throw new Error('Options must be provided for options input type')
}
return {
inputType: arg.inputType,
...baseCommandArgument,

View File

@ -38,7 +38,10 @@ export async function renameProjectDirectory(
// Make sure the new name does not exist.
const newPath = window.electron.path.join(
projectPath.split('/').slice(0, -1).join('/'),
projectPath
.split(window.electron.sep)
.slice(0, -1)
.join(window.electron.sep),
newName
)
try {
@ -179,7 +182,7 @@ const collectAllFilesRecursiveFrom = async (path: string) => {
return Promise.reject(new Error(`Path ${path} is not a directory`))
}
const pathParts = path.split('/')
const pathParts = path.split(window.electron.sep)
let entry: FileEntry = {
name: pathParts.slice(-1)[0],
path,

View File

@ -38,6 +38,9 @@ const bracket = startSketchOn('XY')
tags: [getPreviousAdjacentEdge(outerEdge)]
}, %)`
/**
* @throws Error if the search text is not found in the example code.
*/
function findLineInExampleCode({
searchText,
example = bracket,
@ -48,6 +51,8 @@ function findLineInExampleCode({
const lines = example.split('\n')
const lineNumber = lines.findIndex((l) => l.includes(searchText)) + 1
if (lineNumber === 0) {
// We are exporting a constant, so we don't want to return an Error.
// eslint-disable-next-line suggest-no-throw/suggest-no-throw
throw new Error(
`Could not find the line with search text "${searchText}" in the example code. Was it removed?`
)

View File

@ -51,6 +51,19 @@ export class MachineManager {
return this._machineApiIp
}
// Get the reason message for why there are no machines.
noMachinesReason(): string | undefined {
if (this.machineCount() > 0) {
return undefined
}
if (this.machineApiIp === null) {
return 'Machine API server was not discovered'
}
return 'Machine API server was discovered, but no machines are available'
}
get currentMachine(): components['schemas']['Machine'] | null {
return this._currentMachine
}

View File

@ -131,8 +131,6 @@ ipcMain.handle('kittycad', (event, data) => {
)(data.args)
})
const SERVICE_NAME = '_machine-api._tcp.local.'
ipcMain.handle('find_machine_api', () => {
const timeoutAfterMs = 5000
return new Promise((resolve, reject) => {
@ -144,8 +142,19 @@ ipcMain.handle('find_machine_api', () => {
resolve(null)
})
console.log('Looking for machine API...')
bonjourEt.find({ type: SERVICE_NAME }, (service: Service) => {
resolve(service.fqdn)
})
bonjourEt.find(
{ protocol: 'tcp', type: 'machine-api' },
(service: Service) => {
console.log('Found machine API!', JSON.stringify(service))
if (!service.addresses || service.addresses?.length === 0) {
console.log('No addresses found for machine API!')
return resolve(null)
}
const ip = service.addresses[0]
const port = service.port
// We want to return the ip address of the machine API.
resolve(`${ip}:${port}`)
}
)
})
})

View File

@ -169,7 +169,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -180,7 +180,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -191,7 +191,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -443,7 +443,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -643,7 +643,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim 0.10.0",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -654,7 +654,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [
"darling_core",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -709,7 +709,7 @@ checksum = "4078275de501a61ceb9e759d37bdd3d7210e654dbc167ac1a3678ef4435ed57b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
"synstructure",
]
@ -738,7 +738,7 @@ dependencies = [
"rustfmt-wrapper",
"serde",
"serde_tokenstream",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -749,7 +749,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -776,7 +776,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -948,7 +948,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -1038,7 +1038,7 @@ dependencies = [
"inflections",
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -1462,7 +1462,7 @@ dependencies = [
"pretty_assertions",
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -1841,7 +1841,7 @@ dependencies = [
"regex",
"regex-syntax 0.8.3",
"structmeta",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -1894,7 +1894,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2058,7 +2058,7 @@ dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2071,7 +2071,7 @@ dependencies = [
"proc-macro2",
"pyo3-build-config",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2533,7 +2533,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2607,7 +2607,7 @@ checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2618,7 +2618,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2642,7 +2642,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2663,7 +2663,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2800,7 +2800,7 @@ dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2811,7 +2811,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2855,9 +2855,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.74"
version = "2.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
dependencies = [
"proc-macro2",
"quote",
@ -2878,7 +2878,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -2985,7 +2985,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -3056,9 +3056,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.39.2"
version = "1.39.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1"
checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5"
dependencies = [
"backtrace",
"bytes",
@ -3080,7 +3080,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -3233,7 +3233,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -3261,7 +3261,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -3338,7 +3338,7 @@ checksum = "c88cc88fd23b5a04528f3a8436024f20010a16ec18eb23c164b1242f65860130"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
"termcolor",
]
@ -3502,7 +3502,7 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]
@ -3563,7 +3563,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
"wasm-bindgen-shared",
]
@ -3598,7 +3598,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -3924,7 +3924,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.74",
"syn 2.0.75",
]
[[package]]

View File

@ -17,7 +17,7 @@ gloo-utils = "0.2.0"
kcl-lib = { path = "kcl" }
kittycad.workspace = true
serde_json = "1.0.125"
tokio = { version = "1.39.2", features = ["sync"] }
tokio = { version = "1.39.3", features = ["sync"] }
toml = "0.8.19"
uuid = { version = "1.10.0", features = ["v4", "js", "serde"] }
wasm-bindgen = "0.2.91"
@ -30,7 +30,7 @@ image = { version = "0.25.1", default-features = false, features = ["png"] }
kittycad = { workspace = true, default-features = true }
pretty_assertions = "1.4.0"
reqwest = { version = "0.11.26", default-features = false }
tokio = { version = "1.39.2", features = ["rt-multi-thread", "macros", "time"] }
tokio = { version = "1.39.3", features = ["rt-multi-thread", "macros", "time"] }
twenty-twenty = "0.8"
uuid = { version = "1.10.0", features = ["v4", "js", "serde"] }

View File

@ -20,7 +20,7 @@ quote = "1"
regex = "1.10"
serde = { version = "1.0.208", features = ["derive"] }
serde_tokenstream = "0.2"
syn = { version = "2.0.74", features = ["full"] }
syn = { version = "2.0.75", features = ["full"] }
[dev-dependencies]
anyhow = "1.0.86"

View File

@ -15,7 +15,7 @@ databake = "0.1.8"
kcl-lib = { path = "../kcl" }
proc-macro2 = "1"
quote = "1"
syn = { version = "2.0.74", features = ["full"] }
syn = { version = "2.0.75", features = ["full"] }
[dev-dependencies]
pretty_assertions = "1.4.0"

View File

@ -12,4 +12,4 @@ kcl-lib = { version = "0.2", path = "../kcl" }
pico-args = "0.5.0"
serde = { version = "1.0.208", features = ["derive"] }
serde_json = "1.0.125"
tokio = { version = "1.39.2", features = ["macros", "rt-multi-thread"] }
tokio = { version = "1.39.3", features = ["macros", "rt-multi-thread"] }

View File

@ -50,7 +50,7 @@ zip = { version = "2.0.0", default-features = false }
[target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys = { version = "0.3.69" }
tokio = { version = "1.39.2", features = ["sync", "time"] }
tokio = { version = "1.39.3", features = ["sync", "time"] }
tower-lsp = { version = "0.20.0", default-features = false, features = ["runtime-agnostic"] }
wasm-bindgen = "0.2.91"
wasm-bindgen-futures = "0.4.42"
@ -59,7 +59,7 @@ web-sys = { version = "0.3.69", features = ["console"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
approx = "0.5"
bson = { version = "2.11.0", features = ["uuid-1", "chrono"] }
tokio = { version = "1.39.2", features = ["full"] }
tokio = { version = "1.39.3", features = ["full"] }
tokio-tungstenite = { version = "0.23.1", features = ["rustls-tls-native-roots"] }
tower-lsp = { version = "0.20.0", features = ["proposed"] }

View File

@ -0,0 +1,60 @@
// Shelf Bracket
// This is a shelf bracket made out of 6061-T6 aluminum sheet metal. The required thickness is calculated based on a point load of 300 lbs applied to the end of the shelf. There are two brackets holding up the shelf, so the moment experienced is divided by 2. The shelf is 1 foot long from the wall.
// Define our bracket feet lengths
const shelfMountL = 8 // The length of the bracket holding up the shelf is 6 inches
const wallMountL = 6 // the length of the bracket
// Define constants required to calculate the thickness needed to support 300 lbs
const sigmaAllow = 35000 // psi
const width = 6 // inch
const p = 300 // Force on shelf - lbs
const L = 12 // inches
const M = L * p / 2 // Moment experienced at fixed end of bracket
const FOS = 2 // Factor of safety of 2 to be conservative
// Calculate the thickness off the bending stress and factor of safety
const thickness = sqrt(6 * M * FOS / (width * sigmaAllow))
// 0.25 inch fillet radius
const filletR = 0.25
// Sketch the bracket and extrude with fillets
const bracket = startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([0, wallMountL], %, 'outerEdge')
|> line([-shelfMountL, 0], %)
|> line([0, -thickness], %)
|> line([shelfMountL - thickness, 0], %, 'innerEdge')
|> line([0, -wallMountL + thickness], %)
|> close(%)
|> extrude(width, %)
|> fillet({
radius: filletR,
tags: [
getPreviousAdjacentEdge('innerEdge', %)
]
}, %)
|> fillet({
radius: filletR + thickness,
tags: [
getPreviousAdjacentEdge('outerEdge', %)
]
}, %)

169
yarn.lock
View File

@ -1228,56 +1228,56 @@
dependencies:
"@jridgewell/trace-mapping" "0.3.9"
"@csstools/color-helpers@^4.2.1":
version "4.2.1"
resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-4.2.1.tgz#da573554220ccb59757f12de62bf70c6b15645d4"
integrity sha512-CEypeeykO9AN7JWkr1OEOQb0HRzZlPWGwV0Ya6DuVgFdDi6g3ma/cPZ5ZPZM4AWQikDpq/0llnGGlIL+j8afzw==
"@csstools/color-helpers@^5.0.1":
version "5.0.1"
resolved "https://registry.yarnpkg.com/@csstools/color-helpers/-/color-helpers-5.0.1.tgz#829f1c76f5800b79c51c709e2f36821b728e0e10"
integrity sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==
"@csstools/css-calc@^1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-1.2.4.tgz#9d9fb0dca33666cf97659f8f2c343ed0210e0e73"
integrity sha512-tfOuvUQeo7Hz+FcuOd3LfXVp+342pnWUJ7D2y8NUpu1Ww6xnTbHLpz018/y6rtbHifJ3iIEf9ttxXd8KG7nL0Q==
"@csstools/css-calc@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@csstools/css-calc/-/css-calc-2.0.1.tgz#1675297b19f0933c729fdd7f4f5279b855ae724f"
integrity sha512-e59V+sNp6e5m+9WnTUydA1DQO70WuKUdseflRpWmXxocF/h5wWGIxUjxfvLtajcmwstH0vm6l0reKMzcyI757Q==
"@csstools/css-color-parser@^2.0.4":
version "2.0.5"
resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-2.0.5.tgz#ce1fe52f23f35f37bea2cf61ac865115aa17880a"
integrity sha512-lRZSmtl+DSjok3u9hTWpmkxFZnz7stkbZxzKc08aDUsdrWwhSgWo8yq9rq9DaFUtbAyAq2xnH92fj01S+pwIww==
"@csstools/css-color-parser@^3.0.2":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@csstools/css-color-parser/-/css-color-parser-3.0.2.tgz#710abb97142d58bcefc3a5e032a55a246895351c"
integrity sha512-mNg7A6HnNjlm0we/pDS9dUafOuBxcanN0TBhEGeIk6zZincuk0+mAbnBqfVs29NlvWHZ8diwTG6g5FeU8246sA==
dependencies:
"@csstools/color-helpers" "^4.2.1"
"@csstools/css-calc" "^1.2.4"
"@csstools/color-helpers" "^5.0.1"
"@csstools/css-calc" "^2.0.1"
"@csstools/css-parser-algorithms@^2.7.1":
version "2.7.1"
resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.7.1.tgz#6d93a8f7d8aeb7cd9ed0868f946e46f021b6aa70"
integrity sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==
"@csstools/css-parser-algorithms@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.1.tgz#f14ade63bae5f6025ac85c7d03fe47a7ca0e58af"
integrity sha512-lSquqZCHxDfuTg/Sk2hiS0mcSFCEBuj49JfzPHJogDBT0mGCyY5A1AQzBWngitrp7i1/HAZpIgzF/VjhOEIJIg==
"@csstools/css-tokenizer@^2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-2.4.1.tgz#1d8b2e200197cf5f35ceb07ca2dade31f3a00ae8"
integrity sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==
"@csstools/css-tokenizer@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.1.tgz#9dd9b10084f3011290f96789598091e5bcb3c29a"
integrity sha512-UBqaiu7kU0lfvaP982/o3khfXccVlHPWp0/vwwiIgDF0GmqqqxoiXC/6FCjlS9u92f7CoEz6nXKQnrn1kIAkOw==
"@csstools/postcss-oklab-function@^3.0.16":
version "3.0.19"
resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-3.0.19.tgz#3bd0719914780fb53558af11958d0f4e6d2f952e"
integrity sha512-e3JxXmxjU3jpU7TzZrsNqSX4OHByRC3XjItV3Ieo/JEQmLg5rdOL4lkv/1vp27gXemzfNt44F42k/pn0FpE21Q==
"@csstools/postcss-oklab-function@^4.0.2":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-4.0.2.tgz#3d36974fbb7c3a589d52756e4eb029eaa29e4735"
integrity sha512-2iSK/T77PHMeorakBAk/WLxSodfIJ/lmi6nxEkuruXfhGH7fByZim4Fw6ZJf4B73SVieRSH2ep8zvYkA2ZfRtA==
dependencies:
"@csstools/css-color-parser" "^2.0.4"
"@csstools/css-parser-algorithms" "^2.7.1"
"@csstools/css-tokenizer" "^2.4.1"
"@csstools/postcss-progressive-custom-properties" "^3.3.0"
"@csstools/utilities" "^1.0.0"
"@csstools/css-color-parser" "^3.0.2"
"@csstools/css-parser-algorithms" "^3.0.1"
"@csstools/css-tokenizer" "^3.0.1"
"@csstools/postcss-progressive-custom-properties" "^4.0.0"
"@csstools/utilities" "^2.0.0"
"@csstools/postcss-progressive-custom-properties@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-3.3.0.tgz#20177d3fc61d8f170c4ee1686f3d2ab6eec27bbb"
integrity sha512-W2oV01phnILaRGYPmGFlL2MT/OgYjQDrL9sFlbdikMFi6oQkFki9B86XqEWR7HCsTZFVq7dbzr/o71B75TKkGg==
"@csstools/postcss-progressive-custom-properties@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-4.0.0.tgz#ecdb85bcdb1852d73970a214a376684a91f82bdc"
integrity sha512-XQPtROaQjomnvLUSy/bALTR5VCtTVUFwYs1SblvYgLSeTo2a/bMNwUwo2piXw5rTv/FEYiy5yPSXBqg9OKUx7Q==
dependencies:
postcss-value-parser "^4.2.0"
"@csstools/utilities@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@csstools/utilities/-/utilities-1.0.0.tgz#42f3c213f2fb929324d465684ab9f46a0febd4bb"
integrity sha512-tAgvZQe/t2mlvpNosA4+CkMiZ2azISW5WPAcdSalZlEjQvUfghHxfQcrCiK/7/CrfAWVxyM88kGFYO82heIGDg==
"@csstools/utilities@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@csstools/utilities/-/utilities-2.0.0.tgz#f7ff0fee38c9ffb5646d47b6906e0bc8868bde60"
integrity sha512-5VdOr0Z71u+Yp3ozOx8T11N703wIFGVRgOWbOZMKgglPJsWA54MRIoMNVMa7shUToIhx5J8vX4sOZgD2XiihiQ==
"@electron-forge/cli@^7.4.0":
version "7.4.0"
@ -2075,12 +2075,12 @@
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@playwright/test@^1.45.1":
version "1.45.3"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.45.3.tgz#22e9c38b3081d6674b28c6e22f784087776c72e5"
integrity sha512-UKF4XsBfy+u3MFWEH44hva1Q8Da28G6RFtR2+5saw+jgAFQV5yYnB1fu68Mz7fO+5GJF3wgwAIs0UelU8TxFrA==
"@playwright/test@^1.46.1":
version "1.46.1"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.46.1.tgz#a8dfdcd623c4c23bb1b7ea588058aad41055c188"
integrity sha512-Fq6SwLujA/DOIvNC2EL/SojJnkKf/rAwJ//APpJJHRyMi1PdKrY3Az+4XNQ51N4RTbItbIByQ0jgd1tayq1aeA==
dependencies:
playwright "1.45.3"
playwright "1.46.1"
"@react-hook/latest@^1.0.2":
version "1.0.3"
@ -2100,10 +2100,10 @@
"@react-hook/latest" "^1.0.2"
"@react-hook/passive-layout-effect" "^1.2.0"
"@remix-run/router@1.19.0":
version "1.19.0"
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.19.0.tgz#745dbffbce67f05386d57ca22c51dfd85c979593"
integrity sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==
"@remix-run/router@1.19.1":
version "1.19.1"
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.19.1.tgz#984771bfd1de2715f42394c87fb716c1349e014f"
integrity sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==
"@replit/codemirror-interact@^6.3.1":
version "6.3.1"
@ -2478,19 +2478,12 @@
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.7.tgz#4c620090f28ca7f905a94b706f74dc5b57b44f2f"
integrity sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==
"@types/node@*":
version "22.0.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.0.2.tgz#9fb1a2b31970871e8bf696f0e8a40d2e6d2bd04e"
integrity sha512-yPL6DyFwY5PiMVEwymNeqUTKsDczQBJ/5T7W/46RwLU/VH+AA8aT5TZkvBviLKLbbm0hlfftEkGrNzfRk/fofQ==
"@types/node@*", "@types/node@^22.4.1":
version "22.4.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.4.1.tgz#9b595d292c65b94c20923159e2ce947731b6fdce"
integrity sha512-1tbpb9325+gPnKK0dMm+/LMriX0vKxf6RnB0SZUqfyVkQ4fMgUSySqhxE/y8Jvs4NyF1yHzTfG9KlnkIODxPKg==
dependencies:
undici-types "~6.11.1"
"@types/node@^18.19.31":
version "18.19.42"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.42.tgz#b54ed4752c85427906aab40917b0f7f3d724bf72"
integrity sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg==
dependencies:
undici-types "~5.26.4"
undici-types "~6.19.2"
"@types/node@^20.9.0":
version "20.14.13"
@ -4203,10 +4196,10 @@ electron-winstaller@^5.3.0:
optionalDependencies:
"@electron/windows-sign" "^1.1.2"
electron@*, electron@^31.2.1:
version "31.3.1"
resolved "https://registry.yarnpkg.com/electron/-/electron-31.3.1.tgz#de5f21f10db1ba0568e0cdd7ae76ec40a4b800c3"
integrity sha512-9fiuWlRhBfygtcT+auRd/WdBK/f8LZZcrpx0RjpXhH2DPTP/PfnkC4JB1PW55qCbGbh4wAgkYbf4ExIag8oGCA==
electron@*, electron@^31.4.0:
version "31.4.0"
resolved "https://registry.yarnpkg.com/electron/-/electron-31.4.0.tgz#fd55fd882117b09fd68b2d182c8fda2dbb7ef454"
integrity sha512-YTwKoAA+nrJMlI1TTHnIXLYWoQLKnhbkz0qxZcI7Hadcy0UaFMFs9xzwvH2MnrRpVJy7RKo49kVGuvSdRl8zMA==
dependencies:
"@electron/get" "^2.0.0"
"@types/node" "^20.9.0"
@ -7226,17 +7219,17 @@ pkg-types@^1.0.3, pkg-types@^1.1.1:
mlly "^1.7.1"
pathe "^1.1.2"
playwright-core@1.45.3:
version "1.45.3"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.45.3.tgz#e77bc4c78a621b96c3e629027534ee1d25faac93"
integrity sha512-+ym0jNbcjikaOwwSZycFbwkWgfruWvYlJfThKYAlImbxUgdWFO2oW70ojPm4OpE4t6TAo2FY/smM+hpVTtkhDA==
playwright-core@1.46.1:
version "1.46.1"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.46.1.tgz#28f3ab35312135dda75b0c92a3e5c0e7edb9cc8b"
integrity sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A==
playwright@1.45.3:
version "1.45.3"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.45.3.tgz#75143f73093a6e1467f7097083d2f0846fb8dd2f"
integrity sha512-QhVaS+lpluxCaioejDZ95l4Y4jSFCsBvl2UZkpeXlzxmqS+aABr5c82YmfMHrL6x27nvrvykJAFpkzT2eWdJww==
playwright@1.46.1:
version "1.46.1"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.46.1.tgz#ea562bc48373648e10420a10c16842f0b227c218"
integrity sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng==
dependencies:
playwright-core "1.45.3"
playwright-core "1.46.1"
optionalDependencies:
fsevents "2.3.2"
@ -7560,20 +7553,20 @@ react-refresh@^0.14.2:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9"
integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==
react-router-dom@^6.23.1:
version "6.26.0"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.26.0.tgz#8debe13295c58605c04f93018d659a763245e58c"
integrity sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ==
react-router-dom@^6.26.1:
version "6.26.1"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.26.1.tgz#a408892b41767a49dc94b3564b0e7d8e3959f623"
integrity sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==
dependencies:
"@remix-run/router" "1.19.0"
react-router "6.26.0"
"@remix-run/router" "1.19.1"
react-router "6.26.1"
react-router@6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.26.0.tgz#d5af4c46835b202348ef2b7ddacd32a2db539fde"
integrity sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==
react-router@6.26.1:
version "6.26.1"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.26.1.tgz#88c64837e05ffab6899a49df2a1484a22471e4ce"
integrity sha512-kIwJveZNwp7teQRI5QmwWo39A5bXRyqpH0COKKmPnyD2vBvDwgFXSqDUYtt1h+FEyfnE8eXr7oe0MxRzVwCcvQ==
dependencies:
"@remix-run/router" "1.19.0"
"@remix-run/router" "1.19.1"
react-textarea-autosize@^8.3.2:
version "8.5.3"
@ -8765,10 +8758,10 @@ undici-types@~5.26.4:
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
undici-types@~6.11.1:
version "6.11.1"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.11.1.tgz#432ea6e8efd54a48569705a699e62d8f4981b197"
integrity sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==
undici-types@~6.19.2:
version "6.19.6"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.6.tgz#e218c3df0987f4c0e0008ca00d6b6472d9b89b36"
integrity sha512-e/vggGopEfTKSvj4ihnOLTsqhrKRN3LeO6qSN/GxohhuRv8qH9bNQ4B8W7e/vFL+0XTnmHPB4/kegunZGA4Org==
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"