Compare commits

...

230 Commits

Author SHA1 Message Date
eb2327827b Release KCL 77 (#7188) 2025-05-23 18:54:04 +00:00
1f53dd1357 KCL: [number; 3] to RGB hex string color function (#7184)
Closes https://github.com/KittyCAD/modeling-app/issues/6805. Enables users to programatically construct colors, which will be helpful for 

- Applying color to visualize program execution and help debugging
- Doing weird cool shit
2025-05-23 13:53:58 -05:00
034366e65e Bugfix: formatter changed [0..<4] to [0..4] (#7186)
In #7179 I added exclusive ranges for KCL, but I forgot to update the
formatter/unparser to handle them. So it was silently changing exclusive-end
ranges to inclusive-end ranges.
2025-05-23 17:03:46 +00:00
cd537cd9c2 Remove the version badge on web signin (#7187)
Thanks @jacebrowning for reporting
2025-05-23 16:52:23 +00:00
22f92942f6 #6567 Code errors disappear when closing and reopening the editor (#7166)
* Fix error of not showing errors when reopening KCL code pane

* add test for errors not shown after reopening code pane

* rename test

* typo in e2e/playwright/editor-tests.spec.ts

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

* lint

* fmt

* fix test: Opening and closing the code pane will consistently show error diagnostics

* PR feedback: use catch(reportRejection) for safeParse

* no need for lint rule

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-23 12:41:37 -04:00
4eee50d79e Remove Owners font from the modeling app (#7185)
Our team started getting *rate limited* with access to the font, which
meant the app wasn't loading for them 😱. I don't want us to risk any
user being rate limited because of a font ever.
2025-05-23 12:33:05 -04:00
125b2c44d4 Clean up release process readme (#7182)
* Clean up release process readme

* Update CONTRIBUTING.md

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-23 11:22:39 -04:00
db9e35d686 Fix mirror2d selection by adding artifact graph support (#7178)
* Add artifact graph support for mirror2d

* Update output

* Disable test that can't pass
2025-05-23 11:16:36 -04:00
d0958220fe KCL: End-exclusive ranges like [0..<10] (#7179)
Closes https://github.com/KittyCAD/modeling-app/issues/6843

To clarify:
`[1..10]` is 1, 2, ..., 8, 9, 10
`[1..<10]` is 1, 2, ... 8, 9
2025-05-22 22:13:27 -05:00
fa4b3cfd1b Change artifact panics to runtime errors (#7177)
* Change artifact panics to runtime errors

* Condense format!()

* Remove unwrap
2025-05-22 17:48:19 -04:00
8972f8f109 Fix up the sign-in page's mobile layout (#7176)
@JBEmbedded pointed this out, and we don't want a bad look for website
browsers who click a stray "Try in Browser" link. There's a little
message saying we're working on touch controls for now, and we steal
their signin button.
2025-05-22 21:31:06 +00:00
85ccc6900c Do multiple chamfer/fillet in one API call (#6750)
KCL's `fillet` function takes an array of edges to fillet. Previously this would do `n` fillet API commands, one per edge. This PR combines them all into one call, which should improve performance. You can see the effect in the  artifact_commands snapshots, e.g. `rust/kcl-lib/tests/kcl_samples/axial-fan/artifact_commands.snap` 

Besides performance, this should fix a bug where some KCL fillets would fail, when they should have succeeded. Example from @max-mrgrsk:

```kcl
sketch001 = startSketchOn(XY)
  |> startProfile(at = [-12, -6])
  |> line(end = [0, 12], tag = $seg04)
  |> line(end = [24, 0], tag = $seg03)
  |> line(end = [0, -12], tag = $seg02)
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)], tag = $seg01)
  |> close()
extrude001 = extrude(
       sketch001,
       length = 12,
       tagEnd = $capEnd001,
       tagStart = $capStart001,
     )
  |> fillet(
       radius = 5,
       tags = [
         getCommonEdge(faces = [seg02, capEnd001]),
         getCommonEdge(faces = [seg01, capEnd001]),
         getCommonEdge(faces = [seg03, capEnd001]),
         getCommonEdge(faces = [seg04, capEnd001])
       ],
     )
```

This program fails on main, but succeeds on this branch.
2025-05-22 21:25:55 +00:00
4e2deca5d8 KCL: Set sensible defaults for pattern 'axis' arg (#7168) 2025-05-22 14:24:21 -05:00
04a2c184d7 KCL: Absolute point bezier curves (#7172)
Previously KCL bezier curves could only use relative control points. Now you can use absolute control points too. 

Here's an example of the new arguments:

```kcl
startSketchOn(XY)
  |> startProfile(at = [300, 300])
  |> bezierCurve(control1Absolute = [600, 300], control2Absolute = [-300, -100], endAbsolute = [600, 300])
  |> close()
  |> extrude(length = 10)
```

Closes https://github.com/KittyCAD/modeling-app/issues/7083
2025-05-22 13:06:06 -04:00
2c7701e2d4 Add markdown rendering to TTC error toast, with component tests (#7170)
Closes #5792. I tried to move these over to our new component test
bucket, but Remark doesn't play nice with that testing setup at least in
my initial attempts.
2025-05-22 13:00:21 -04:00
ae569b61db Use typed KclValue instead of any in sketchFromKclValue (#7144)
* use KclValue instead of any

* no need for any in sketchFromKclValueOptional

* simplify error reason for sketchFromKclValueOptional
2025-05-22 11:15:31 +02:00
0a0e6abd3f KCL: Autocomplete snippets for 'center' should suggest the origin (#7164)
Pattern functions and `polygon` both take a parameter `center` which
defaulted to [3.14, 3.14] for silly reasons. They now default to
[0, 0].
2025-05-22 04:08:34 +00:00
9c7aee32bd KCL: Custom snippet values for kcl-in-kcl (#7163)
In #7156, I allowed KCL to set specific snippet completions for each arg of each function. They're optional -- if you don't set one, it'll fall back to the type-driven defaults.

That PR only worked for KCL stdlib functions defined in Rust. This PR enables the same feature, but for functions defined in KCL.
2025-05-21 22:16:04 -05:00
ed979d807b Fix ascription to array type to not convert units (#7160) 2025-05-22 09:22:30 +12:00
f5c244dbb1 KCL: stdlib macro should now assume all functions use keywords (#7158)
This has been enforced by the parser since #6639, so there's no need for `keywords = true` in every stdlib function anymore.
2025-05-21 21:10:40 +00:00
0ea1e9a6da KCL: Customizable per-arg and per-fn snippet values (#7156)
Before, the LSP snippet for `startProfile` was 

```
startProfile(%, at = [3.14, 3.14])
```

Now it's 

```
startProfile(%, at = [0, 0])
```

This is configured by adding a `snippet_value=` field to the stdlib macro. For example:


```diff
#[stdlib {
    name = "startProfile",
    keywords = true,
    unlabeled_first = true,
    args = {
        sketch_surface = { docs = "What to start the profile on" },
-       at = { docs = "Where to start the profile. An absolute point." },
+       at = { docs = "Where to start the profile. An absolute point.", snippet_value = "[0, 0]" },        tag = { docs = "Tag this first starting point" },
    },
    tags = ["sketch"]
}]
```

## Work for follow-up PRs

 - Make this work for KCL functions defined in KCL, e.g. [`fn circle`](36c8ad439d/rust/kcl-lib/std/sketch.kcl (L31-L32)) -- something like `@(snippet_value = "[0, 0]")` perhaps
 - Go through the stdlib and change defaults where appropriate
2025-05-21 20:18:20 +00:00
a36530d6df Make Create with Zoo ML the default again (#7159) 2025-05-21 18:29:03 +00:00
825d34718a Update telemetry antenna entity names (#7155)
* Update telemetry antenna entity names

Changed the generic sketch and profile entity names to more specific names

* Update kcl-samples simulation test output

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-05-21 15:46:05 +00:00
d90d445d84 Pass the query parameters through to sign-in flow (#7157)
* Pass the query parameters through to sign-in flow

So users can return to their invoked command after signing in

* Don't run query param commands if not logged in
2025-05-21 15:32:52 +00:00
5976a0cba6 Change to skip asserting the artifact graph for samples (#7153)
* Change to skip asserting the artifact graph for samples

* Fix clippy warning
2025-05-21 14:51:31 +00:00
b50f2f5a2a Link to the dedicated page when there is intent to download (#7152) 2025-05-21 14:20:36 +00:00
f877b52898 Update telemetry antenna (#7150)
* Update telemetry antenna

* Update kcl-samples simulation test output

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-05-21 10:05:56 -04:00
4a585db637 Link to the new download page (#7149) 2025-05-21 13:42:11 +00:00
4d404bf137 Delete redundant Text-to-CAD tests (#7118) 2025-05-21 13:33:32 +00:00
e644b7e1fc Run the KCL tests every hour to detect regressions (#7139) 2025-05-21 09:21:04 -04:00
aff1684064 Chrome toast touchup (#7148) 2025-05-21 08:47:40 -04:00
d9afc50f91 Nickmccleery/add more samples (#7145) 2025-05-21 12:27:43 +00:00
eb7b4ccda6 Fix web app issue with search params on Safari (#7147)
* pierremtb/adhoc/safari-link-issue

* Fix both places with [...searchParams.entries()]
2025-05-21 12:06:17 +00:00
bbf4f1d251 Add title line which I didn't know did anything important. (#7135) 2025-05-21 09:00:21 +00:00
3cc7859ca5 load samples on web (#7142)
* load samples on web

* Update src/hooks/useQueryParamEffects.ts

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-21 07:59:42 +00:00
ab63345c57 Run std lib example tests one at a time (#7127)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-21 05:20:36 +00:00
3df02e02fa Release 76 (#7138) 2025-05-21 02:39:32 +00:00
35f5c62633 Don't race exiting a sketch scene (#7128)
* Turn sketch exit execute into actor, no more racey exits

* Turn sketch exit execute into actor, no more racey exits

* Fix types

---------

Co-authored-by: Frank Noirot <frank@zoo.dev>
2025-05-21 01:09:16 +00:00
0f0fc39d07 Add display of array element types in error messages (#7113)
* Add test showing unhelpful error message

* Add display of array element types in error messages

* Change to prose description

* Update output
2025-05-20 20:50:24 -04:00
a13b6b2b70 Fix open KCL sample via URL query param in browser (#7133)
There is now a `projectName` that isn't included in the query params I
was using and wasn't including in the URLs I was building.
2025-05-20 20:48:23 -04:00
4212b95232 Add KCL importing relative to where you're importing from (#7125)
* add test

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

* Add importing relative to where you're importing from

* Update output

* Remove runtime panics

* Change to debug_assert

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-21 00:47:32 +00:00
38a73a603b Update output to match latest (#7129) 2025-05-21 00:45:41 +00:00
c48d9fd4d7 Allow point-and-click Insert to suggest nested files (#7130)
* fix: saving off code

* fix: saving off progress

* chore: implemented kcl sample assembly unique sub dir creation

* fix: removing testing console logs

* fix: cleaning up old comment

* fix: add to file always does subdir/main.kcl now for single files

* fix: auto fmt

* fix: delete project and folder from ttc

* fix: fixed deleting projects and subdirs

* fix: if statement logic fixed for deleting project or subdir

* fix: TTC isProjectNew makes main.kcl not a subdir.

* fix: fixing e2e test

* fix: this should pass now

* pierremtb/make-insert-take-over-the-import-world

* Add test that doesn't work locally yet :(

* Fix test 🤦

* Change splice for push

* Fix up windows path

---------

Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Kevin Nadro <nadr0@users.noreply.github.com>
2025-05-20 20:44:22 -04:00
0753987b5a [Fix]: Allow importing assemblies into exsiting projects and handling the collision (#7108)
* fix: saving off code

* fix: saving off progress

* chore: implemented kcl sample assembly unique sub dir creation

* fix: removing testing console logs

* fix: cleaning up old comment

* fix: add to file always does subdir/main.kcl now for single files

* fix: auto fmt

* fix: delete project and folder from ttc

* fix: fixed deleting projects and subdirs

* fix: if statement logic fixed for deleting project or subdir

* fix: TTC isProjectNew makes main.kcl not a subdir.

* fix: fixing e2e test

* fix: this should pass now
2025-05-20 19:03:54 -04:00
815ff7dc2b more subtract regression tests (#7123)
* more regression tests

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

* snaps

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

* iupdates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-20 16:02:44 -07:00
46684d420d Test nested imports on all platforms (#7126) 2025-05-20 18:45:04 -04:00
eca09984a3 Fix: Follow up Text-to-CAD Edit to fix in browser (#7124)
* fix: web vs desktop who wins

* fix: fixed logic round two :(
2025-05-20 21:11:31 +00:00
ce63c6423e Impove naming in point-and-click Revolve to convey that axis are relative (#7122)
* Better axis options in point-and-click Revolve to convey the axis are relative
Fixes #7121

* Less changes
2025-05-20 16:57:55 -04:00
09699afe82 Fix: Can't go back to Profiles arg in Extrude, Revolve, Loft (#7106)
* Revert "Update failing E2E tests with new behavior, which allows skip with preselection"

This reverts commit d72bee8637.

* Fix: Can't go back to Profiles step in sweep commands
Fixes #7080

* Make it better but still not quite there

* I think I got it: this was likely the real bug making submit fire twice

* Bring timemouts back
2025-05-20 20:07:56 +00:00
36c8ad439d KCL: Add diameter arg to circle (#7116)
Paul's been requesting this for a long time. Now that we're fully using keyword args, this is easy to do.

We should probably add a similar `diameter` arg to `arc`, `tangentialArc`, `polygon` etc. And _maybe_ to `fillet`, but that might not be as helpful.
2025-05-20 19:44:35 +00:00
5dc77ceed5 Only start saving camera after scene is ready (#7120) 2025-05-20 15:12:08 -04:00
c7baa26b2d idiomatic kcl for hip sample (#7095)
* idiomatic kcl for hip sample

* Update kcl-samples simulation test output

* updates

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>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-20 11:36:08 -07:00
4d0454abcd Remove old ZMA logos, rip out JS theme state from open-in-desktop view (#7119)
* Remove old ZMA logos, rip out JS theme state from open-in-desktop view

Make this page dumber so that it doesn't break

* Lint and remove kcma refs

---------

Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
2025-05-20 18:13:58 +00:00
1dafbf105e Identify distinct test suites (#7109) 2025-05-20 12:56:55 -04:00
773f013115 [Fix]: When loading the modeling page the user's settings for camera projection was ignored (#7111)
* fix: initialization of user camera projection is now used again, ope

* fix: removing comment
2025-05-20 12:46:53 -04:00
c5cd460595 Show error when trying to export at non-top-level (#7110) 2025-05-20 12:43:11 -04:00
845352046b Modeling machine unit tests (#7098)
* successfully transition to sketch idle

* get constraint to mod code

* clean up

* remove .only

* Fixed tsc

---------

Co-authored-by: lee-at-zoo-corp <lee@zoo.dev>
2025-05-20 12:22:52 -04:00
597f1087f9 Fix enter key loop in sweep commands (#7112)
* use effect for focus of command palette submit button, not autoFocus

autoFocus is being overridden by the Headless UI Dialog component's
focus management here
https://headlessui.com/v1/react/dialog#focus-management (we do not have
access to pass back initialFocus in this case). So we can use an effect
to imperatively focus the button when this component is mounted.

* Update sweep tests to submit the command with Enter
2025-05-20 16:04:56 +00:00
511334683a test: Add regression test for importing only at the top level (#7104)
Add regression test for importing only at the top level
2025-05-20 11:43:48 -04:00
223a4ad45d Style the experimental badge to match the website (#7100)
* Style the experimental badge to match the website

* Match the styling of the rest of the app

We don't use all apps monospace fonts anywhere.

* Bring back all caps
2025-05-20 14:57:53 +00:00
edf31ec1d3 Make the textarea command bar input run its resize initially (#7103)
We have a hook to auto-grow the textarea input but it wasn't running
once initially. This is noticable on the onboarding, where we show the
user a long Text-to-CAD Edit prompt that overflows.
2025-05-20 10:56:03 -04:00
1539557005 Always update snapshots if needed (#7105) 2025-05-20 14:34:26 +00:00
1d3ba4e3ac [Fix]: Remove console logs (#7102)
* fix: these got in when they should not have

* fix: spacemacs found wrong eslint again biome thing..
2025-05-20 14:12:32 +00:00
4110aa00db Only update snapshots for tests that repeatedly fail (#7101)
* Only update snapshots for tests that repeatedly fail

* Let TAB silence snapshot capture failures as well
2025-05-20 14:00:33 +00:00
7eb52cda36 Fix: creating a dir ending with .kcl panics the app (#7099)
* Fix: creating a dir ending with .kcl panics the app
Fixes #7082

* Update snapshots

* Update snapshots

* Add test

* tag: ['@electron', '@macos', '@windows']

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-05-20 13:53:26 +00:00
7872fb9cbd Update snapshots on CI (#7069) 2025-05-20 06:00:31 -04:00
651181e62c Restrict subdirectory imports to main.kcl (#7094)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-20 18:13:17 +12:00
max
38a245f2fc fix typos in the kcl samples (#7078)
typos
2025-05-20 05:47:33 +00:00
1b4289f93f allow nested files imported (#7090)
* allow nested files

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

* fix test

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

* disallow bad things

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

* add playwright test on windows

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

* add playwright test on windows

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

* fixes

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

* updates

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

* updates

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

* fix test

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

* Update rust/kcl-lib/tests/nested_windows_main_kcl/unparsed@main.kcl.snap

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

* updates

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-19 22:42:25 -04:00
d0697c24fd Change Sketch to use the units of the module (#7076)
* Change Sketch to use the units of the module

* Update output
2025-05-19 20:20:47 -04:00
8c24e29081 [Fix]: P2E base path is always the project directory, P2E when completed stays in your current file (#7091)
* fix: fixes for p2e

* fix: yep tsc fixes

* fix: fixing reject workflow and navigate
2025-05-19 20:05:38 -04:00
2b9d26e2ff Make Text-to-CAD Edit the default workflow in the toolbar (#7092)
We want users to make edits first and foremost within projects, so we're
going to surface it as the default workflow button in the toolbar. WIP
until I verify that tests are okay with this.
2025-05-19 19:58:18 -04:00
ab148a7654 Fix: Esc key doesn't work in Text-to-CAD prompt (#7089)
* Fix: Esc key doesn't work in Text-to-CAD prompt
Fixes #7086

* Add e2e test because why not
2025-05-19 23:31:33 +00:00
553e650fbe Add brake disc to samples. (#7059)
* Add brake disc.

* Update kcl-samples simulation test output

* Update public/kcl-samples/brake-rotor/main.kcl

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>

* Update public/kcl-samples/brake-rotor/main.kcl

Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>

* updates

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>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-19 15:24:37 -07:00
9690a24c68 Avoid a spin-lock when auth is never resolved (#7084) 2025-05-19 18:16:07 -04:00
978d5d44a2 rotate a named axis (#7087)
updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-19 22:11:35 +00:00
9df476543a turn on the revolve test (#7075)
* turn on the revolve test

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

* updates

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

* updates

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

* updates

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

* updates

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-19 14:51:44 -07:00
cf303ebe97 Declare pattern transform functions in KCL (#7057)
* Declare pattern transform using KCL

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Boolean function param defaults

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Parse empty record types in fn types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-20 08:25:29 +12:00
b1d1d89ca5 Include link to the new book (#7056)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-19 14:49:23 -05:00
3a599d0a0a Release KCL 75 (#7077) 2025-05-19 19:02:38 +00:00
8340f6b906 Give a default value to projectName in Text-to-CAD Create command to allow invocation through command palette (#7061)
Give a default value to projectName

This argument is hidden since it's marked as skip, so browser users who
must now invoke the command through the command palette have no way of
setting the value. Since it is also required, the command palette fails
silently on submission (which we need to fix more broadly). This gives
it a default value so that users can submit properly.
2025-05-19 18:13:47 +00:00
ddb034b14d Show KCL backtraces (#7033)
* Add backtrace to errors

* Add display of backtraces with hints

* Change pane badge to only show count of errors

* Fix property name to not collide with Error superclass

* Increase min stack again

* Add e2e test that checks that the diagnostics are created in CodeMirror

* Remove unneeded code

* Change to the new hotness
2025-05-19 18:13:10 +00:00
bfa2f67393 Add a 1s client side rate limit / cache to billing requests (#7067)
* Add a 1s client side rate limit / cache to billing requests

* Stop using err; use isErr instead
2025-05-19 14:11:33 -04:00
447069a97b Revert "Remove Create with Text-to-CAD from toolbar, make commands in command palette more distinct" (#7068)
Revert "Remove Create with Text-to-CAD from toolbar, make commands in command…"

This reverts commit 5734cc7fc3.
2025-05-19 14:05:18 -04:00
49b78d726a Submit selection to command on unmount of selection arg input (#7047)
* Submit selection to command on unmount of selection arg input

This fixes #7024 by saving the user's selection to the command even if
they click another argument in the command palette's header. It does no
harm to save the selection to the argument, even if it's being torn down
because the user dismissed it has no negative effect.

* Refactor to not auto-submit before selection is cleared on mount

Thanks E2E test suite

* Update failing E2E tests with new behavior, which allows skip with preselection

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-05-19 13:21:43 -04:00
5b4cddd0b0 Fix React re-render (#7038)
feat: memoize share button to avoid re-renders
2025-05-19 12:58:35 -04:00
8878c148ed Fix reset project dir setting (#7064)
* Fix reset project dir setting
Fixes #6432

* Lint
2025-05-19 16:51:08 +00:00
c3c2ded795 Fix cleanup in network status hook (#7034)
fix: remove event listeners on unmount
2025-05-19 11:38:53 -04:00
fb35fdcc38 Disallow segment selection in all sweeps and change Sketches display name to Profiles (#7045)
* Disallow segment selection in sweep, plus displayName: Profiles for clarity
Fixes #7044

* Change selection hints for solid2d to be profile instead of face

* Update tests

* More fixes

* Fix tests following behavior change: we don't select segments in code anymore but profiles
2025-05-19 11:21:29 -04:00
e76ba9921c No onboarding toast if query params (#7060)
* No onboarding toast if query params

* Changed dependences
2025-05-19 09:38:38 -04:00
b19acd550d Type check and coerce arguments to user functions and return values from std Rust functions (#6958)
* Shuffle around function call code

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Refactor function calls to share more code

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Hack to leave the result of revolve as a singleton rather than array

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-19 16:50:15 +12:00
f3e9d110c0 KCL: Default circular pattern rotateDuplicates=true, arcDegrees=360 (#7052)
KCL: Default circular pattern rotateDuplicates=true, arcDeg=360

Seems like most users would want these.
2025-05-19 14:46:00 +12:00
658497da1d Allow same syntax for patterns as mirror revolve (#7054)
* allow named axis for patterns

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

* docs

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

* images

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

* Fix typo

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
2025-05-19 02:25:35 +00:00
bd01059a92 more csg regression tests (#7032)
* more csg regression tests

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

* artifacts

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-18 16:50:51 -07:00
57a977e6be Fix simulation_test file load error (#7042)
Co-authored-by: Lucas Kent <rubickent@gmail.com>
2025-05-18 16:28:59 -07:00
94b0cc1f3e Remove remaining links to nightly (#7051) 2025-05-18 11:21:31 -04:00
5734cc7fc3 Remove Create with Text-to-CAD from toolbar, make commands in command palette more distinct (#7048)
* Remove Create with Text-to-CAD from the toolbar

* Remove "prompt-to-edit" wording, call commands "create" and "edit"

* Use sparkles for the ML feature, not chat

* lints

* Start fixing up tests, there are probably more though

* Fix up a few more tests

* Fix up prompt-to-edit tests (yay using fixtures!)

* Fix native file menu tests

* Update snapshots

* Fix menu test

* Fix snaps

---------

Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-05-18 10:24:48 +00:00
3168c22de7 Remove false positive missing messages for other module SourceRanges (#7050) 2025-05-18 06:21:10 -04:00
3c94fe9047 Make warning toast not appear if the URL has any search params (#7046)
* Make warning toast not appear if the URL has any search params

This should avoid the scenario where someone clicks an "open sample"
type link and dismisses the command palette before they can finish what
they're doing.

* Update src/App.tsx

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-18 01:23:43 +00:00
cdd6b56d42 Change wasm init failed banner to a toast (#7043)
* Change wasm init failed banner to a toast
Closes #6976 for good!

* Move :(

* Rm testing bit

* Align left and bot suggestions

* Update src/components/WasmErrToast.tsx

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-17 18:01:12 -04:00
75ac3bc61b Replace map with forEach in CLI arg tests (#7035)
test: use forEach for command-line arg cases
2025-05-17 14:20:39 -04:00
29d511d085 [Fix] Updating docs for mirror2d (#7013)
* fix: mirror2d works on closed sketches

* fix: generating docs
2025-05-17 13:00:29 -05:00
max
b0a41939e8 Max's KCL samples (#7041)
* 3d models

* Update kcl-samples simulation test output

* typos

* Update kcl-samples simulation test output

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-05-17 11:16:22 -04:00
7d2c1061ba Allow global commands to be invoked from the command palette via URL (#6973) 2025-05-17 07:51:25 -04:00
d768073d17 [Fix] Using main.kcl for more of the workflows that generate kcl files (#7017)
* fix: when creating a t2c in a new project make the file name main.kcl

* fix: when creating a sample in a new project and there is only 1 file make the filename main.kcl

* fix: auto fixes

* fix: share links generate main.kcl

* fix: codespell typoe

* fix: fixing E2E tests

* Fix 3 more tests

* fix: share url link e2e file name fix

---------

Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Frank Noirot <frank@zoo.dev>
2025-05-17 03:43:25 +00:00
dc8496c62e Change download-app banner to a toast & permanent button (#7010)
* pierremtb/issue6976-download-app-toast

* Cleaning up, more testing

* we goin places ft. new icon thanks @franknoirot

* Add app-version to masks

* Revert "Add app-version to masks"

This reverts commit 9624c3f434.

* Update dialog logic and snapshots

* Update snapssss

* Hook up settingsActor

* Polish

* Fix snap

* Quick fix, thanks bot

* Cleaning up linksssssssss
2025-05-16 23:25:04 -04:00
416de9a9fb allow more than one tool (#6945)
* allow more than one tool

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

* updates

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

* updates

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

* updates

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

* update tests

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

* fmt

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

* bump kcl

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-16 23:22:50 +00:00
da65426ddc Fix to account for cached body items when computing NodePath (#7030) 2025-05-16 23:22:01 +00:00
585b485852 Revert "stupid paths filtering" (#7028)
Revert "stupid paths filtering (#7027)"

This reverts commit e85f16ff9c.
2025-05-16 22:29:34 +00:00
e85f16ff9c stupid paths filtering (#7027)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-16 15:02:58 -07:00
e7d2289a14 Revolve adjacency info (#7008)
* check edge colinear

* cleanup

* revert cargo.toml

* revert cargo.toml properly

* undo yarn.lock

* clippy

* add new sim test

* move tolerance2

* typo

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

* fmt

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

* update snap

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

* push real snap

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

* update tests

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-16 22:02:30 +00:00
d35531758d fix read_to_string to give error (#7022)
updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-16 16:56:19 -04:00
729e0a7949 add a subtract regression test (#7018)
* add a subtraact regression test

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

* also rename some github actions job so we can require them;

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

* artifacts

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-16 20:06:56 +00:00
620b7401aa Update Rust tests to use internal KCL samples on CI (#7014)
* Update Rust tests to use internal KCL samples on CI

* Regenerate manifest with internal KCL samples

* try again

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

* remove the needs

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

* updates

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

* updates

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

* updates

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

* updates

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

* features

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

* features

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

* updates

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

* secret

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-16 19:38:55 +00:00
e3e67b00d5 Run the component tests on CI (#7009)
* Run the component tests on CI

* Share WASM build

* Add basic token permissions
2025-05-16 15:51:43 +00:00
49d4f8e5c3 Remove the warningMessage field for command args (#7005) 2025-05-16 10:41:33 -05:00
47b159c605 Remove check on the Start Sketch button (#7004) 2025-05-16 10:38:18 -05:00
c7b086fa69 Change warning message on Chamfer for a more discreet note in tooltip (#7002) 2025-05-16 14:00:31 +00:00
203db79204 Fix light mode code mirror tooltip (#7001)
A CSS selector just needed `.dark` prepended to it
2025-05-16 13:37:41 +00:00
48a4fd8373 Organization and Pro tier link sharing features exposure (#6986)
* Improve url sharing for orgs and pros

* Remove sharing via menu item

* fmt

* Not sure what's different but it is

* fmt & lint

* whoops

* Update snapshots

* Typos from codespell

* Fix alignment

* Update snapshots

* Prune

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
Co-authored-by: Pierre Jacquier <pierre@zoo.dev>
2025-05-16 09:51:08 +00:00
17eb84325f Quick follow up fixing up experimetal progress/submit button colors (#6999) 2025-05-16 19:44:10 +10:00
ebf048478d Make Modify with Text-to-CAD selection arg optional by honoring skip: false on non-required args (#6992)
* Make "skip = false" non-required args appear in header

* Make non-required, unskippable selection args work

* Make prompt-to-edit's selection arg optional but non-skippable

* Update src/components/CommandBar/CommandBarSelectionInput.tsx

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

* Fix dumb logic bug

Thanks for user testing @Irev-dev

* Update mixed input to show selection

Feel free to revert @Irev-Dev if this is the wrong move, but I found it
odd that this component doesn't show the current selection in the text
like the other selection input does, so I copied that over.

* Merge branch 'main' into franknoirot/adhoc/optional-selection-args

* Merge branch 'main' into franknoirot/adhoc/optional-selection-args

* Merge remote-tracking branch 'origin' into franknoirot/adhoc/optional-selection-args

* fix tests

* change copy again

* Update src/components/CommandBar/CommandBarSelectionMixedInput.tsx

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-16 05:15:52 -04:00
28a8cd2421 [Bug] fix big screen boot up bug (#6998)
fix big screen boot up bug
2025-05-16 04:55:09 -04:00
1506de92f5 ML commands green branding and experimental badge (#6989)
* Remove tan warning from ml commands, move to experimental green branding

* Oops

* Removed unused var

---------

Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
2025-05-16 03:42:35 +00:00
8a03413643 Deflake onboarding test (#6996)
1. Remove all `waitFor` hidden states for the post-dismiss toast:
something about Playwright is making toasts hang in a way I've never
seen in real use. Not something I'm worried about, and we still test
that the toast fires the first time we dismiss.
2. Remove all `scene.connectionEstablished()` calls. This has me more
worried because some of the flakiness on this front seems like we're not
able to handle the rapid machine-speed navigation and overwriting that
this test does when it doesn't have to `waitFor` toasts to disappear.
But that is not the point of this test, which is just to ensure the
onboarding plays correctly and initiates correctly.
2025-05-15 23:27:58 -04:00
f59b806a88 Fix to display warnings when there's a fatal error (#6995)
* Fix to display warnings when there's a fatal error

* Fix JSON test
2025-05-16 03:22:21 +00:00
23a0085c78 Change runtime assert to runtime error and debug assert (#6987) 2025-05-15 22:55:16 -04:00
a280a8c3f0 Nickmccleery/i have no idea what im doing (#6967)
* Yeet in alt param structure.

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-16 02:16:32 +00:00
11620dfa6b Fix to display errors at the call site (#6991) 2025-05-15 22:11:37 -04:00
f6e26e0bab test: Add face_code_ref to the mermaid output (#6985)
* Add face_code_ref to the mermaid output

* Update output
2025-05-15 20:14:31 -04:00
f6b3a55cbf fix link (#6990) 2025-05-16 00:04:23 +00:00
74939e5cd6 Fix execution caching to cache artifact graph NodePath (#6978)
* Fix to add NodePaths to SketchOnFace and SketchOnPlane artifacts

* Fix to only compute the new part of the artifact graph

* Change to early-return sooner when in mock mode

* Add another test

* Fix to propagate NodePath for sketch on face

* Update output
2025-05-15 19:18:03 -04:00
9906c9947a Do not coerce unknown numbers and preserve known units if present (#6961)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-16 10:58:21 +12:00
48d6a21f0a Accept multiple export toast messages to be visible (#6979)
* Accept multiple export toast messages to be visible

* Wait for the toast to appear

* Wait before counting toasts
2025-05-15 22:48:15 +00:00
dd6a980915 Helix can't be selected as path arg in point-and-click sweep (#6968)
* Helix can't be selected as path arg in point-and-click sweep
Fixes #6966

* Remove old dry-run validations on Sweep, Loft, Revolve, and Shell

* Base on dry-run validation remove branch

* Add test
2025-05-15 15:42:38 -05:00
2516df3a39 fix my insta test fubar (#6981)
* fix my insta test fubar

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

* more python tests

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

* more python tests

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-15 13:37:12 -07:00
52125f0566 Change IS_NIGHTLY_OR_DEBUG to not include playwright version (#6982) 2025-05-15 20:23:06 +00:00
e489222b6a expose mock executing to python library; (#6980)
* expose mock executing to python library;

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

* bump

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

* Update rust/kcl-python-bindings/src/lib.rs

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-15 12:35:29 -07:00
d93a57d7bf more lsp tests / pass python a bool on parse (#6975)
* updates

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

* parse returns bool for python

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-15 11:04:53 -07:00
d34aea345b #6548 Fix autocomplete for offsetPlane (#6940)
* handle Plane in get_autocomplete_snippet to fix missing default plane value for offsetPlane

* adds test for offsetPlane default plane value

* cleanup test

* use XY instead of XZ for default plane

* add rust test for offsetplane autocomplete

* remove playwright test for offestPlane, as it has rust test now and there are autocomplete tests already
2025-05-15 19:53:35 +02:00
0b6102b0ac #6214 Fix center circle radius issues (#6971)
* add missing radius line for center circle

* remove some duplication by introducing createLineShape
2025-05-15 13:30:25 -04:00
9e0873ed84 Remove updater-test builds (#6962)
Remove updater-test
2025-05-15 13:25:40 -04:00
8587eb5fea Make idle sestting 30sec in nightly (#6972) 2025-05-15 17:17:59 +00:00
b898c27e74 Add KCL constants for sweep relativeTo strings (#6974)
* Add KCL constants for sweep relativeTo strings

Before:

```
sweep(pill, path = sweepPath, relativeTo = "trajectoryCurve")
```

After:

```
sweep(pill, path = sweepPath, relativeTo = sweep::TRAJECTORY)
```

* Update docs
2025-05-15 10:13:04 -07:00
3026866a16 Remove old dry-run validations on Sweep, Loft, Revolve, and Shell (#6969) 2025-05-15 12:11:40 -05:00
92fc294eae Update mesh clone test (#6597) 2025-05-15 16:46:37 +00:00
21e967ea7f More consistent error handling in modelingMachine codemods (#6910)
* First pass at consistency in modelingMachine codemods

* Add 'no kcl errors' guard instead of if check for all the existing ones

* Add more commands and improve consistency

* Add comments

* Fix test with old kcl that was showcasing the very behavior we're trying to fix
https://kittycadworkspace.slack.com/archives/C07A80B83FS/p1747231832870739?thread_ts=1747231178.515289&cid=C07A80B83FS

* Add test for sketch and helix

* Remove guard use and move hasErrors check closer to updateAst calls

* Revert "Remove guard use and move hasErrors check closer to updateAst calls"

This reverts commit 868ea4b605.

* Remove toasts from guards

* Remove some scene.settled calls

* Lint

* More shaky fixes

* Clean up and more test fixes

---------

Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
2025-05-15 12:26:20 -04:00
3f00e7186c Backoff Reconnect (#6358)
* Add a Stop command that does a bit of cleanup in the engineStateMachine

* Major network code startup refactor; backoff reconnect; many more logs for us

* Save camera state after every user interaction in case of disconnection and restoral

* Translate basic WebSocket error numbers into useful text

* Add a RestartRequest event to the engineCommandManager

* Adjust for a rebase

* Add E2E test for stream pause behavior

* Fix snapshot test

* fmt, lint

* small issue

* Fix tests

* Fix up idle test

* One last fix

* fixes

* Remove circ dep

* fix test

* use a const for time

* TEST -> isPlaywright instead

* whoops
2025-05-15 11:58:00 -04:00
d3a4fd8b55 Raw dog parse for python bindings (#6970)
* raw dog parse python

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

* add tests

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-15 15:39:28 +00:00
2be7107cca External: Fix: symbol replace text box dark mode contrast (#6827) (#6927)
* fix: symbol replace text box dark mode contrast (#6827)

* fix: symbol replace text box dark mode contrast (#6827)

* correct fix for rename popup white text on white background #6827

* correct fix for rename popup white text on white background #6827

* added comments explaining the change

---------

Co-authored-by: rajgandhi1 <rajgandhi9952@gmail.com>
2025-05-15 12:57:39 +00:00
94f194a984 new sweep default (#6965)
snaps

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-15 11:50:55 +00:00
4fe880a970 Revert "fixes"
This reverts commit 8f5fbfc273.
2025-05-15 04:28:20 -07:00
8f5fbfc273 fixes
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-15 04:27:59 -07:00
e660f52bb0 Restore automated snapshot commits (#6960)
* Restore automated snapshot commits

* Update snapshots

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-05-15 03:28:42 +00:00
d74fdd9369 Color picker goober works w single quotes (#6957)
* lsp stuffs

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-15 12:37:14 +10:00
334145f0be fix sketch on face of union (#6949)
* fix sketch on face of union

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

* rotate the model

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-14 23:25:12 +00:00
c24073b6ae Sensible parser error when using keyword as arg label (#6948)
Closes <https://github.com/KittyCAD/modeling-app/issues/6924>
2025-05-14 22:29:31 +00:00
078b7f3bf7 fix errors from the wasm side (#6939)
* updates

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

* playwright tests

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

* fix tests

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

* updates

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

* updates

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

* updates

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

* change order of operations

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

* lint

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

* fixups

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

* Revert "fixups"

This reverts commit c54fd71074.

* fixups

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-14 13:20:46 -07:00
3d65676ccb Permit concurrent unit tests (#6938)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-15 07:43:03 +12:00
ce566fb6e5 Accept idents as KW args (#6644)
Support kw arg/local variable shorthand

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-15 07:42:48 +12:00
b23fc9f623 Make the Reset View button do the same view_isometric behavior as load (#6934)
* Make the Reset View button do the same view_isometric behavior as load

Just copying some logic from the EngineStream code to make that button
behave the same way: old initial camera position while in Playwright,
isometric view for normal users.

* Move duplicate code into shared `resetCameraPosition` function

* Fix lints
2025-05-14 19:01:45 +00:00
5c2dfb8e40 Support new sweep flag (#6932)
Closes https://github.com/KittyCAD/engine/issues/3115
2025-05-14 13:54:10 -05:00
0e341d7863 #6202 Save input value before closing settings dialogue (#6931)
* call blur on current input before closing settings dialogue to save value

* separate esc handling is not needed

* lint
2025-05-14 14:16:23 -04:00
6a03ff9596 Stop checking for intermediate export toasts (#6935) 2025-05-14 17:53:44 +00:00
d7bd0c937d Keep test toast messages around for longer (#6930)
* Keep test toast messages around for longer

* Check for at least two locators

I wasn't able to reproduce, but it's possible one stuck around from a previous test.
2025-05-14 12:24:38 -04:00
d3b2483f4f Clear errors when leaving file to avoid seeing previous files errors (#6928)
Clear errors when leaving file to avoid seeing previous files errors when opening new project

Co-authored-by: Jace Browning <jacebrowning@gmail.com>
2025-05-14 17:20:04 +02:00
7838b7c9fd Fix "include settings" setting to have an effect (#6917)
* Fix "include settings" setting to have an effect

I'm not sold on if we should have this setting, but this fixes it for
now. The issue is was that the new callback actor approach was using a
stale version of the settings every time it received an "update" event:
JS closure problems. Now it receives the new settings as an event
payload.

* Update src/machines/settingsMachine.ts

---------

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-05-14 15:14:33 +00:00
130ecf1f88 Shard macOS and Windows e2e tests (#6926) 2025-05-14 14:33:53 +00:00
550d8b3753 #6300 Fix wrong Feature Tree when switching to kcl file with errors (#6922)
* reset lastSuccessfulOperation, variables when switching to new kcl file, add test

* use scene.settled instead of random delay in test
2025-05-14 14:17:22 +00:00
696222a070 Change KCL error messages to display principal type of values (#6906) 2025-05-14 10:04:51 -04:00
edb424988d Restore the native file menu tests (#6279)
* Restore the native file menu tests

* fix: saving off progress

* chore: making progress cleaning up these verbose tests and improving app logic for e2e

* chore: rewriting tests

* fix: reworking application logic for file menu in the scene and e2e scene file menu test

* chore: updating more e2e tests

* fix: updated all the tests, auto fixers

* fix: trying to improve tests within E2E, they aren't failing locally even with --repeat-each=10

* fix: application logic has a bug that you can navigate instantly but the scroll to view code will not trigger which breaks end to end tests

* fix: improving E2E tests

* fix: fixing clipboard typo

* fix: porting test() for each native file menu to a test.step to speed it up

* fix: auto fixes and console log helper function for playwright runtimes

* fix: more cleanup

* fix: trying to fix these...

* fix: got the tests working

* fix: addressing PR comments

* fix: trying to stablize the tests

* fix: auto fixes

* fix: trying to make it the command name and not arg? could be a source of race condition if the input is not written fast enough?

* fix: maybe because this close locator was running too quickly?

* fix: panic timeout, classic

* fix: these are gone

* fix: shorter waits

---------

Co-authored-by: Kevin Nadro <kevin@zoo.dev>
Co-authored-by: Kevin Nadro <nadr0@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-05-14 09:06:29 -04:00
1e487ef3bd Include NodePath in artifact graph mermaid charts as comments (#6884)
* Display NodePath in artifact graph mermaid charts

* Update output

* Change node path display to be only comments

* Update output

* Update output after rebase
2025-05-14 05:31:58 +00:00
811ef3e72d fix pw test i turned off (#6921)
updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-14 04:36:52 +00:00
980e3c4bc2 remove my sins (#6919)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-14 04:28:55 +00:00
78b6854c6b bump modeling-cmds, nuke slow world (#6753)
* bump modeling-cmds, nuke slow world

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

* more stuffs

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

* updates

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

* updates

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

* i mechanical engineered today

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

* reverse uno your revolves

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

* updates

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

* updates

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

* updates

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

* retry logic

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

* updates

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>

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-14 04:07:24 +00:00
068b9129cf add a sleep for local engine disconnect/reconnect (#6918)
updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-13 16:12:37 -07:00
05fba3c50c more stable shards (#6916)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-13 15:27:18 -07:00
7944a4ce41 New single-file samples for the website (#6670)
* New single-file samples for the website

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* Delete public/kcl-samples/piston directory

* More

* updates

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

* updates

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

* updates

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

* updates

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

* updates

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

* updates

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

* move another test

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

* updates

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

* updates

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>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-13 15:05:57 -07:00
4640f1a3ad Teaching t2c how to counterbore, countersink, and counterdrill (#6833)
* Teaching t2c how to counterbore, countersink, and counterdrill

* Delete public/kcl-samples/parametric-bearing-pillow-block directory

* Update mounting-wire.kcl

* new artifiacts

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

* Update kcl-samples simulation test output

* Update kcl-samples simulation test output

* updates

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

* updates

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

* updates

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-05-13 14:11:50 -07:00
cd79059d97 Subtract tests (#6913)
* add subtract test and cleanup some other tests

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

* updates

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

* fmt

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-13 14:06:10 -07:00
2d95e19048 Gears DLC (free) (#6835)
* Gears DLC (free)

Using the involuteCircular fn to create a variety of cylindrical gearsets

* Delete public/kcl-samples/gear directory

* Update main.kcl

fixing gear meshing

* new samples

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

* add link

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-13 14:03:52 -07:00
d047587bc1 Avoid using full revolve for now (#6912)
Avoid using revolve for now

When we moved to concurrent execution of KCL modules, we begun to see an
error we never fully understood, and because it was pretty hard to
trigger, we wound up never being able to fix it. Today we were able to
track it down to the `revolve` call here.

Specifically, the problem is triggered when we're doing a "Full Revolve"
(e.g., `angle = 359.999999` passes, but *not* `angle = 360` or the
default, as it is in `main`), and concurrently executing modules will
see something weird happen with `getNextAdjacentEdge`.

From all the smoke I believe this happens only when we are doing a *full
revolve*, *AND* we're executing other modules which are calling
`getNextAdjacentEdge`.

When the `revolve` is present, we can lose the race in *either*
`talk-button.kcl` OR `case.kcl`.

If I move back to single-threaded execution OR I add imports to sequence
things carefully, I can get the tests to pass. If the revolve is an
`extrude` or not a full revolve, it works fine.

My best guess is that it seems like the world got flipped upside down or
something, such that "next edge" has a different orentation for two
calls. My even further guess is that inside `revolve` we mutate
something connection-global such that it alters the intepretation of
calls made during the revolve implementation's "critical section".
2025-05-13 20:20:48 +00:00
128e1093fb Update snaps (#6911)
* update pattern entity ids since that pr merged

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

* artifacts

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-13 19:27:34 +00:00
afdc305e3e Update new onboarding after team feedback (#6903)
* Update onboarding following @jgomez720

* Fix up TODO's in desktop conclusion (ty Ian)
2025-05-13 14:52:19 -04:00
4bc5439996 Prevent concurrent run of build-apps on main (#6909) 2025-05-13 18:20:27 +00:00
be14022f97 Update samples PNG export (#6908) 2025-05-13 18:03:27 +00:00
eda78ef5ae Fix test by closing code pane after loading the scene (#6907) 2025-05-13 18:03:16 +00:00
0cc833e687 Keep toast message around longer when testing (#6902) 2025-05-13 13:59:52 -04:00
33e83747f3 Split up example tests into smaller batches and provide info on which example is failing (#6896)
* Give example info for failing std example tests

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Shard example tests into 10

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-13 10:50:54 -07:00
c3a8fc6d93 Remove unneeded check on the network health text label (#6905) 2025-05-13 13:46:09 -04:00
8ff84e269c Update bug icon to not use FontAwesome (#6904)
lol we had a custom bug icon in the codebase, no clue why I didn't
update the pane config.
2025-05-13 13:45:07 -04:00
99cb6a6179 [Fix] Created the safest navigate/load/open/please sir i want some more for a .kcl file (#6867)
* fix: clear scene and bust cache if rust panics

* Update onboarding following @jgomez720

* chore: hopefully made a safe navigate to kcl file to call executeAST without a race condition

* chore: hopefully made a safe navigate to kcl file to call executeAST without a race condition

* fix: clean up

* fix: FUCK

* fix: FUCK 2.0

* fix: oh boi

* fix: oh boi

* fix: idk man

* updates

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

* fix: take main on this, do not need a single line from my testing code

* fix: more PR cleanup from all of the testing code

* fix: trying to clean up more, ope this has a lot of other code

* fix: PR clean up

* fix: trying to get a clean branch, I had multiple other branches in here ope

* fix: more cleanup

* fix: another one

* fix: fixed the comment to be accurate

* fix: removed confusing comment

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
Co-authored-by: Jess Frazelle <github@jessfraz.com>
2025-05-13 15:35:29 +00:00
13dbfdfaa4 SystemIOMachine: Toast default error instead of empty string (#6898)
pierremtb/issue6820-add-error-instead-of-empty-string
2025-05-13 10:28:24 -05:00
8603f5c53a Default to the feature tree, code, and file panes open (#6901)
Only include the file pane on desktop. This should encourage users to
try point-and-click and feature tree workflows. After #6629 is
completed, we should default to the code pane being closed.
2025-05-13 15:25:27 +00:00
d5cc9e8386 Check both public and internal KCL samples (#6889) 2025-05-13 09:21:53 -04:00
533e17466b Update text-to-cad success toast to tell what file got made (#6882)
Closes #5820 and provides a bit of other polish to make this toast look
a bit better.
2025-05-13 12:26:29 +00:00
01c7b69f50 Function types (#6891)
* Change Fn to fn for function types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Support args and return types in function types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Use fancy function types in the docs

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-13 14:59:23 +12:00
47feae3bd9 Register modeling commands as disabled, enable without needing to re-open the command palette (#6886)
* Allow adding and removing commands from any command bar state

* Allow commands to be configured disabled in the combobox

* Set up modeling commands to toggle `disabled` based on network status, instead of filtering

* Fix tsc
2025-05-13 01:18:50 +00:00
e7ecd655c4 Add docs on arrays and ranges (#6890)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-13 13:06:07 +12:00
d9e538c6ea Fix docs for object properties (#6892)
Jon removed support for obj["a"] a while ago in #6529 aka
2e754f2a11
2025-05-13 00:56:50 +00:00
e297f8286f KCL: Fix incorrect error messages (#6883)
**Problem:**

KCL's xLine and yLine functions were telling users to supply either "end" or "endAbsolute" arguments. But "end" is not a valid argument for xLine/yLine, it's actually "length" instead.

**Cause:**

xLine/yLine were using a helper function designed for `line` KCL stdlib functions, which do use `end`. 

**Solution**

Add a new param to the helper function, indicating what the label should be for relative lines. "end" for `line` calls, `length` for x/yline
2025-05-13 00:26:43 +00:00
b3bc90bbe4 Fix lower right version background in dark mode and update snapshots (#6888)
* pierremtb/adhoc/fix-version-bg-dark-mode

* Update snapshots
2025-05-12 23:46:52 +00:00
95a02cbcd7 Check all nested KCL samples (#6880) 2025-05-12 18:43:51 -04:00
a049768f1c Move some more functions to be declared in KCL (#6856)
* Move the leg functions to KCL

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Move array functions to KCL

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Move clone to KCL

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Add a function type

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-13 08:29:38 +12:00
818d9a0d77 Release link and updater toast touchups on Nightly (#6881)
pierremtb/adhoc/clean-up-nightly-on-merge-more
2025-05-12 20:20:12 +00:00
1a8f80a7dc #6793 Fix file, folder renaming issues (#6869)
* fix going into rename mode for files with parents

* lastDirectoryClicked is not used

* fix file/folder rename bugs: renaming within folders

* Turn form into div to fix issue of child renaming continues into renaming the parent folder when hitting enter

* ContextMenu stopPropagation not needed anymore, maybe because of form refactor

* ContextMenu IS needed actually, with multiple nested folders

* make lint happy

* Update src/components/ContextMenu.tsx

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

* re-add <form> instead of <div> for file renaming

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-05-12 21:59:10 +02:00
566c9eaf10 Spell out shortcut in project search bar (#6872)
dumb little zero-thought bit of polish.
2025-05-12 19:36:05 +00:00
e6485c2da1 Clean up Nightly release version & notes (#6877)
* pierremtb/adhoc/clean-up-nightly-on-merge

* To revert: test to upload builds at test/nightly

* Remove + suffix trim that's not needed anymore

* Revert "To revert: test to upload builds at test/nightly"

This reverts commit b0549d426f.
2025-05-12 14:21:09 -04:00
0479edd36a Remove unused GitHub Actions workflow for old onboarding (#6873) 2025-05-12 17:30:51 +00:00
87c1e92134 Deploy Nightly on merge to main (#6871)
* Deploy Nightly on merge to main

* Forgot one block

* Remove .github/workflows/tag-nightly.yml

* Remove scripts/get-nightly-changelog.sh

* Update .github/workflows/build-apps.yml

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

---------

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-12 12:30:01 -04:00
8f950ac1b0 Always run end-to-end tests (#6870) 2025-05-12 12:23:09 -04:00
78e4f43708 Fix kcl errors indicator not scaling with multi-digit count (#6864)
Fixes #6847
2025-05-12 11:36:09 -04:00
270436f404 Fix: clearSceneAndBustCache when rust panics because it can load a stale cache (#6809)
* fix: clear scene and bust cache if rust panics

* fix: pr clean up

* fix: huh? cargo fmt doesn't do this?
2025-05-12 10:08:54 -05:00
57e61632a9 Fix to remove extraneous from package.json (#6868) 2025-05-12 14:50:44 +00:00
884191b8bb Bump kcl (#6865) 2025-05-12 14:18:55 +00:00
21b92f5f13 fix cache multi-file (#6844)
* updates

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

* updates

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

* bump kittycad.rs i need this for cli

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

* bump the version so i can fix cli

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

* fix

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

* clippy

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-12 09:07:18 -05:00
5599a75dbd make sure sketch can be exited (#6862) 2025-05-12 11:30:31 +00:00
3a06ae6e34 fix sketch on offset plane animations (#6858)
* fix sketch on offset plane animations

* trigger CI
2025-05-12 07:28:09 -04:00
22857d77e9 Fix bug with undo startSketchOn removing existing sketch (#6834)
* Fix bug with `undo startSketchOn` removing existing sketch

Fixes #6822, I believe. in this case the `variableName` was not being
marked as in-use, so I just logged out the AST and made sure this case
was covered. @Irev-Dev this is probably worth a check from you.

* Add a regression test

It's an E2E test because I'm being lazy, but it should probably be an
XState unit test at some point.

* check what's checked

---------

Co-authored-by: Kurt Hutten <k.hutten@protonmail.ch>
2025-05-12 16:55:39 +10:00
1a325d0b29 Fix to use correct units for array range expressions (#6837)
* Fix to use correct units for array range expressions

* Update output
2025-05-12 01:30:33 -04:00
1240b23080 Don't truncate extrude arg docs (#6854)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-12 16:48:30 +12:00
8445080d7a Some improvements to math::sqrt (#6853)
* Treat number as any rather than default

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Don't square root negative numbers

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-12 16:47:01 +12:00
bbe89f56a7 Fix the KCL any type and array coercion incorrectly nesting (#6816)
* Add sim test for any type

* Fix doc comments to match code

* Add array ascription tests

* Commit new test output

* Fix to not panic when type is undefined

* Fix to not panic on use of the any type

* Update test and generated output

* Fix error message after rebase

* Fix subtype of any

* Fix KCL to use new keyword args

* Fix to not nest MixedArray in HomArray

* Update output

* Remove all creation of MixedArray and use HomArray instead

* Rename MixedArray to Tuple

* Fix to coerce arrays the way tuples are done

* Restructure to appease the type signature extraction

* Fix TS unit test

* Update output after switch to HomArray

* Update docs

* Fix to remove edge case when creating points

* Update docs with broken point signature

* Fix display of tuples to not collide with arrays

* Change push to an array with type mismatch to be an error

* Add sim test for push type error

* Fix acription to more general array element type

* Fix to coerce point types

* Change array push to not error when item type differs

* Fix coercion tests

* Change to only flatten as a last resort and remove flattening tuples

* Contort code to appease doc generation

* Update docs

* Fix coerce axes

* Fix flattening test to test arrays instead of tuples

* Remove special subtype case for singleton coercion
2025-05-12 03:57:31 +00:00
86e8bcfe0b fix the null app explosion (#6851)
Signed-off-by: Jess Frazelle <github@jessfraz.com>
2025-05-12 03:51:13 +00:00
21ccf129d6 Accept type ascription within binary expressions (#6849)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-12 14:07:57 +12:00
dfc4b7d0c5 Non-fatal error on using && or || (#6845)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-12 13:46:17 +12:00
17b1120a27 Include metadata environment variables with results (#6838)
* Include metadata environment variables with results

* Share updated report after uploading each shard

* Hide raw curl progress
2025-05-11 21:40:11 -04:00
2b509a515b More docs for Plane, Pi, etc. (#6850)
* Document the units of PI

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Add links between lang and std references

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Change signature of conversion functions

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Split foreign imports out of modules docs

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* More docs for Plane

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Update docs/kcl-std/consts/std-math-PI.md

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

* Update rust/kcl-lib/std/math.kcl

Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
2025-05-12 12:59:45 +12:00
97594b9a9e Proper type-checking where a function requires a tag identifier not just a tag (#6848)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
2025-05-12 12:57:50 +12:00
c65190a158 Extend warning message to selection step in prompt-to-edit (#6840)
* Extend warning messages to all args in ML commands

* Only when it works actually

* Add warningMessage to selection mixed input
2025-05-11 17:03:58 -04:00
1348 changed files with 503000 additions and 575314 deletions

View File

@ -1,13 +1,43 @@
#!/bin/bash
set -euo pipefail
BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME:-}}"
COMMIT="${CI_COMMIT_SHA:-${GITHUB_SHA:-}}"
if [ -z "${TAB_API_URL:-}" ] || [ -z "${TAB_API_KEY:-}" ]; then
exit 0
fi
curl --request POST \
project="https://github.com/KittyCAD/modeling-app"
suite="${CI_SUITE:-unit}"
branch="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME:-}}"
commit="${CI_COMMIT_SHA:-${GITHUB_SHA:-}}"
echo "Uploading batch results"
curl --silent --request POST \
--header "X-API-Key: ${TAB_API_KEY}" \
--form "project=https://github.com/KittyCAD/modeling-app" \
--form "branch=${BRANCH}" \
--form "commit=${COMMIT}" \
--form "project=${project}" \
--form "suite=${suite}" \
--form "branch=${branch}" \
--form "commit=${commit}" \
--form "tests=@test-results/junit.xml" \
--form "CI_COMMIT_SHA=${CI_COMMIT_SHA:-}" \
--form "CI_PR_NUMBER=${CI_PR_NUMBER:-}" \
--form "GITHUB_BASE_REF=${GITHUB_BASE_REF:-}" \
--form "GITHUB_EVENT_NAME=${GITHUB_EVENT_NAME:-}" \
--form "GITHUB_HEAD_REF=${GITHUB_HEAD_REF:-}" \
--form "GITHUB_REF_NAME=${GITHUB_REF_NAME:-}" \
--form "GITHUB_REF=${GITHUB_REF:-}" \
--form "GITHUB_SHA=${GITHUB_SHA:-}" \
--form "GITHUB_WORKFLOW=${GITHUB_WORKFLOW:-}" \
--form "RUNNER_ARCH=${RUNNER_ARCH:-}" \
${TAB_API_URL}/api/results/bulk
echo
echo "Sharing updated report"
curl --silent --request POST \
--header "Content-Type: application/json" \
--header "X-API-Key: ${TAB_API_KEY}" \
--data "{
\"project\": \"${project}\",
\"branch\": \"${branch}\",
\"commit\": \"${commit}\"
}" \
${TAB_API_URL}/api/share

View File

@ -7,14 +7,13 @@ on:
- main
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'nightly-v[0-9]+.[0-9]+.[0-9]+'
env:
IS_RELEASE: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'v') }}
IS_NIGHTLY: ${{ github.ref_type == 'tag' && startsWith(github.ref_name, 'nightly-v') }}
IS_NIGHTLY: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
@ -95,7 +94,9 @@ jobs:
- name: Set nightly version, product name, release notes, and icons
if: ${{ env.IS_NIGHTLY == 'true' }}
run: |
export VERSION=${GITHUB_REF_NAME#nightly-v}
COMMIT=$(git rev-parse --short HEAD)
DATE=$(date +'%-y.%-m.%-d')
export VERSION=$DATE-main.$COMMIT
npm run files:set-version
npm run files:flip-to-nightly
@ -122,18 +123,6 @@ jobs:
- id: export_notes
run: echo "notes=`cat release-notes.md`" >> "$GITHUB_OUTPUT"
- name: Prepare electron-builder.yml file for updater test
if: ${{ env.IS_RELEASE == 'true' }}
run: |
yq -i '.publish[0].url = "https://dl.zoo.dev/releases/modeling-app/updater-test"' electron-builder.yml
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: prepared-files-updater-test
path: |
electron-builder.yml
build-apps:
needs: [prepare-files]
@ -258,55 +247,13 @@ jobs:
# TODO: add the 'Build for Mac TestFlight (nightly)' stage back
# The steps below are for updater-test builds, only on release
- uses: actions/download-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
name: prepared-files-updater-test
- name: Copy updated electron-builder.yml file for updater test
if: ${{ env.IS_RELEASE == 'true' }}
run: |
ls -R prepared-files-updater-test
cp prepared-files-updater-test/electron-builder.yml electron-builder.yml
- name: Build the app (updater-test)
if: ${{ env.IS_RELEASE == 'true' }}
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
CSC_KEYCHAIN: ${{ secrets.APPLE_SIGNING_IDENTITY }}
WINDOWS_CERTIFICATE_THUMBPRINT: ${{ secrets.WINDOWS_CERTIFICATE_THUMBPRINT }}
run: npm run tronb:package:prod
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: updater-test-arm64-${{ matrix.platform }}
path: |
out/*-arm64-win.exe
out/*-arm64-mac.dmg
out/*-arm64-linux.AppImage
- uses: actions/upload-artifact@v4
if: ${{ env.IS_RELEASE == 'true' }}
with:
name: updater-test-x64-${{ matrix.platform }}
path: |
out/*-x64-win.exe
out/*-x64-mac.dmg
out/*-x86_64-linux.AppImage
upload-apps-release:
runs-on: ubuntu-22.04
permissions:
contents: write
if: ${{ github.ref_type == 'tag' }}
# Equivalent to IS_RELEASE || IS_NIGHTLY (but we can't access those env vars here)
if: ${{ (github.ref_type == 'tag' && startsWith(github.ref_name, 'v')) || (github.event_name == 'push' && github.ref == 'refs/heads/main') }}
env:
VERSION_NO_V: ${{ needs.prepare-files.outputs.version }}
VERSION: ${{ format('v{0}', needs.prepare-files.outputs.version) }}
@ -412,17 +359,6 @@ jobs:
- name: List artifacts
run: "ls -R out"
- name: Set more complete nightly release notes
if: ${{ env.IS_NIGHTLY == 'true' }}
run: |
# Note: preferred going this way instead of a full clone in the checkout step,
# see https://github.com/actions/checkout/issues/1471
git fetch --prune --unshallow --tags
export TAG="nightly-${VERSION}"
export PREVIOUS_TAG=$(git tag --list --sort=-committerdate "nightly-v[0-9]*" | head -n2 | tail -n1)
export NOTES=$(./scripts/get-nightly-changelog.sh)
npm run files:set-notes
- name: Authenticate to Google Cloud
if: ${{ env.IS_NIGHTLY == 'true' }}
uses: 'google-github-actions/auth@v2.1.8'

56
.github/workflows/build-wasm.yml vendored Normal file
View File

@ -0,0 +1,56 @@
name: Build WASM
on:
workflow_call:
permissions:
contents: read
jobs:
npm-build-wasm:
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
run: npm install
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # configured below
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Use Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: './rust'
- name: Build Wasm
shell: bash
run: npm run build:wasm
- uses: actions/upload-artifact@v4
with:
name: prepared-wasm
path: |
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
- uses: actions/upload-artifact@v4
with:
name: prepared-ts-rs-bindings
path: |
rust/kcl-lib/bindings/*

View File

@ -1,16 +1,22 @@
name: cargo test
on:
push:
branches:
- main
pull_request:
workflow_dispatch:
schedule:
- cron: 0 * * * * # hourly
permissions:
contents: read
pull-requests: write
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
name: cargo test
jobs:
build-test-artifacts:
name: Build test artifacts
@ -88,6 +94,7 @@ jobs:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
ZOO_HOST: https://api.dev.zoo.dev
RUST_BACKTRACE: full
RUST_MIN_STACK: 10485760000
- name: Commit differences
if: steps.path-changes.outputs.outside-kcl-samples == 'false' && steps.cargo-test-kcl-samples.outcome == 'failure'
shell: bash
@ -119,6 +126,7 @@ jobs:
# Configure nextest when it's run by insta (via just).
NEXTEST_PROFILE: ci
RUST_BACKTRACE: full
RUST_MIN_STACK: 10485760000
- name: Build and archive tests
run: |
cd rust
@ -155,7 +163,7 @@ jobs:
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
@ -182,12 +190,65 @@ jobs:
env:
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
ZOO_HOST: https://api.dev.zoo.dev
RUST_MIN_STACK: 10485760000
- name: Upload results
if: always()
run: .github/ci-cd-scripts/upload-results.sh
env:
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:kcl
run-internal-kcl-samples:
name: cargo test (internal-kcl-samples)
runs-on:
- runs-on=${{ github.run_id }}
- runner=32cpu-linux-x64
- extras=s3-cache
steps:
- uses: runs-on/action@v1
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- name: Start Vector
run: .github/ci-cd-scripts/start-vector-ubuntu.sh
env:
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
OS_NAME: ${{ env.OS_NAME }}
- uses: taiki-e/install-action@nextest
- name: Download internal KCL samples
run: git clone --depth=1 https://x-access-token:${{ secrets.GH_PAT_KCL_SAMPLES_INTERNAL }}@github.com/KittyCAD/kcl-samples-internal public/kcl-samples/internal
- name: Run tests
shell: bash
run: |-
cd rust/kcl-lib
cargo nextest run \
--retries=10 --no-fail-fast --features artifact-graph --profile=ci \
internal \
2>&1 | tee /tmp/github-actions.log
env:
TWENTY_TWENTY: overwrite
INSTA_UPDATE: always
EXPECTORATE: overwrite
KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN_DEV}}
ZOO_HOST: https://api.dev.zoo.dev
MODELING_APP_INTERNAL_SAMPLES_SECRET: ${{secrets.MODELING_APP_INTERNAL_SAMPLES_SECRET}}
RUST_MIN_STACK: 10485760000
run-wasm-tests:
name: Run wasm tests
strategy:

View File

@ -1,47 +0,0 @@
name: Check Onboarding KCL
on:
pull_request:
types: [opened, synchronize]
paths:
- 'src/lib/exampleKcl.ts'
- 'public/kcl-samples/bracket/main.kcl'
permissions:
contents: read
issues: write
pull-requests: write
jobs:
comment:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Comment on PR
uses: actions/github-script@v7
with:
script: |
const message = '`public/kcl-samples/bracket/main.kcl` or `src/lib/exampleKcl.ts` has been updated in this PR, please review and update the `src/routes/onboarding`, if needed.';
const issue_number = context.payload.pull_request.number;
const owner = context.repo.owner;
const repo = context.repo.repo;
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number
});
const commentExists = comments.some(comment => comment.body === message);
if (!commentExists) {
// Post a comment on the PR
await github.rest.issues.createComment({
owner,
repo,
issue_number,
body: message,
});
}

View File

@ -1,4 +1,5 @@
name: E2E Tests
on:
push:
branches:
@ -18,73 +19,13 @@ permissions:
jobs:
conditions:
runs-on: ubuntu-latest
outputs:
significant: ${{ steps.path-changes.outputs.significant }}
should-run: ${{ steps.should-run.outputs.should-run }}
steps:
- uses: actions/checkout@v4
- name: Fetch the base branch
if: ${{ github.event_name == 'pull_request' }}
run: git fetch origin ${{ github.base_ref }} --depth=1
- name: Check for path changes
id: path-changes
shell: bash
run: |
set -euo pipefail
# Manual runs or push should run all tests.
if [[ ${{ github.event_name }} != 'pull_request' ]]; then
echo "significant=true" >> $GITHUB_OUTPUT
exit 0
fi
changed_files=$(git diff --name-only origin/${{ github.base_ref }})
echo "$changed_files"
if grep -Evq '^README.md|^public/kcl-samples/|^rust/kcl-lib/tests/kcl_samples/' <<< "$changed_files" ; then
echo "significant=true" >> $GITHUB_OUTPUT
else
echo "significant=false" >> $GITHUB_OUTPUT
fi
- name: Should run
id: should-run
shell: bash
run: |
set -euo pipefail
# We should run when this is a scheduled run or if there are
# significant changes in the diff.
if [[ ${{ github.event_name }} == 'schedule' || ${{ steps.path-changes.outputs.significant }} == 'true' ]]; then
echo "should-run=true" >> $GITHUB_OUTPUT
else
echo "should-run=false" >> $GITHUB_OUTPUT
fi
- name: Display conditions
shell: bash
run: |
# For debugging purposes
set -euo pipefail
echo "GITHUB_REF: $GITHUB_REF"
echo "GITHUB_HEAD_REF: $GITHUB_HEAD_REF"
echo "GITHUB_BASE_REF: $GITHUB_BASE_REF"
echo "significant: ${{ steps.path-changes.outputs.significant }}"
echo "should-run: ${{ steps.should-run.outputs.should-run }}"
prepare-wasm:
# separate job on Ubuntu to build or fetch the wasm blob once on the fastest runner
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
needs: conditions
steps:
- uses: actions/checkout@v4
if: needs.conditions.outputs.should-run == 'true'
- id: filter
if: needs.conditions.outputs.should-run == 'true'
name: Check for Rust changes
uses: dorny/paths-filter@v3
with:
@ -93,18 +34,16 @@ jobs:
- 'rust/**'
- uses: actions/setup-node@v4
if: needs.conditions.outputs.should-run == 'true'
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
if: needs.conditions.outputs.should-run == 'true'
run: npm install
- name: Download Wasm Cache
- name: Download Wasm cache
id: download-wasm
if: ${{ needs.conditions.outputs.should-run == 'true' && github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }}
if: ${{ github.event_name != 'schedule' && steps.filter.outputs.rust == 'false' }}
uses: dawidd6/action-download-artifact@v7
continue-on-error: true
with:
@ -114,9 +53,8 @@ jobs:
branch: main
path: rust/kcl-wasm-lib/pkg
- name: Build WASM condition
- name: Build Wasm condition
id: wasm
if: needs.conditions.outputs.should-run == 'true'
run: |
set -euox pipefail
# Build wasm if this is a scheduled run, there are Rust changes, or
@ -128,35 +66,34 @@ jobs:
fi
- name: Use correct Rust toolchain
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
- name: Install Rust
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
with:
tool: wasm-pack
- name: Rust Cache
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
- name: Use Rust cache
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
uses: Swatinem/rust-cache@v2
with:
workspaces: './rust'
- name: Build Wasm
if: ${{ needs.conditions.outputs.should-run == 'true' && steps.wasm.outputs.should-build-wasm == 'true' }}
if: ${{ steps.wasm.outputs.should-build-wasm == 'true' }}
shell: bash
run: npm run build:wasm
- uses: actions/upload-artifact@v4
if: needs.conditions.outputs.should-run == 'true'
with:
name: prepared-wasm
path: |
@ -165,10 +102,9 @@ jobs:
snapshots:
name: playwright:snapshots:ubuntu
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
needs: [conditions, prepare-wasm]
needs: [prepare-wasm]
steps:
- uses: actions/create-github-app-token@v1
if: needs.conditions.outputs.should-run == 'true'
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
@ -176,16 +112,13 @@ jobs:
owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4
if: needs.conditions.outputs.should-run == 'true'
with:
token: ${{ steps.app-token.outputs.token }}
- uses: actions/download-artifact@v4
if: needs.conditions.outputs.should-run == 'true'
name: prepared-wasm
- name: Copy prepared wasm
if: needs.conditions.outputs.should-run == 'true'
- name: Copy prepared Wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
@ -193,34 +126,25 @@ jobs:
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- uses: actions/setup-node@v4
if: needs.conditions.outputs.should-run == 'true'
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
id: deps-install
if: needs.conditions.outputs.should-run == 'true'
run: npm install
- name: Cache Playwright Browsers
if: needs.conditions.outputs.should-run == 'true'
- name: Cache browsers
uses: actions/cache@v4
with:
path: |
~/.cache/ms-playwright/
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
- name: Install Playwright Browsers
if: needs.conditions.outputs.should-run == 'true'
- name: Install browsers
run: npm run playwright install --with-deps
- name: build web
if: needs.conditions.outputs.should-run == 'true'
run: npm run tronb:vite:dev
- name: Run ubuntu/chrome snapshots
if: needs.conditions.outputs.should-run == 'true'
- name: Test snapshots
uses: nick-fields/retry@v3.0.2
with:
shell: bash
@ -233,10 +157,23 @@ jobs:
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:snapshots
TARGET: web
- name: Update snapshots
if: always()
run: npm run test:snapshots -- --last-failed --update-snapshots
env:
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
TAB_API_URL: ${{ secrets.TAB_API_URL }}
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:snapshots
TARGET: web
- uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
if: ${{ !cancelled() && (success() || failure()) }}
with:
name: playwright-report-ubuntu-snapshot-${{ github.sha }}
path: playwright-report/
@ -244,20 +181,19 @@ jobs:
retention-days: 30
overwrite: true
- name: Check for changes
if: ${{ needs.conditions.outputs.should-run == 'true' && github.ref != 'refs/heads/main' }}
- name: Check diff
if: ${{ github.ref != 'refs/heads/main' }}
shell: bash
id: git-check
run: |
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
if git status | grep -q "Changes to be committed"
if git status | grep --quiet "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT
fi
- name: Commit changes, if any
# TODO: find a more reliable way to detect visual changes
if: ${{ false && needs.conditions.outputs.should-run == 'true' && steps.git-check.outputs.modified == 'true' }}
- name: Commit changes
if: ${{ steps.git-check.outputs.modified == 'true' }}
shell: bash
run: |
git add e2e/playwright/snapshot-tests.spec.ts-snapshots e2e/playwright/snapshots
@ -267,12 +203,12 @@ jobs:
git fetch origin
echo ${{ github.head_ref }}
git checkout ${{ github.head_ref }}
git commit -m "A snapshot a day keeps the bugs away! 📷🐛" || true
git commit --message "Update snapshots" || true
git push
git push origin ${{ github.head_ref }}
electron:
needs: [conditions, prepare-wasm]
needs: [prepare-wasm]
timeout-minutes: 60
env:
OS_NAME: ${{ contains(matrix.os, 'ubuntu') && 'ubuntu' || (contains(matrix.os, 'windows') && 'windows' || 'macos') }}
@ -308,21 +244,24 @@ jobs:
shardTotal: 8
- os: namespace-profile-macos-8-cores
shardIndex: 1
shardTotal: 1
shardTotal: 2
- os: namespace-profile-macos-8-cores
shardIndex: 2
shardTotal: 2
- os: windows-latest-8-cores
shardIndex: 1
shardTotal: 1
shardTotal: 2
- os: windows-latest-8-cores
shardIndex: 2
shardTotal: 2
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
if: needs.conditions.outputs.should-run == 'true'
- uses: actions/download-artifact@v4
if: needs.conditions.outputs.should-run == 'true'
name: prepared-wasm
- name: Copy prepared wasm
if: needs.conditions.outputs.should-run == 'true'
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
@ -330,18 +269,15 @@ jobs:
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- uses: actions/setup-node@v4
if: needs.conditions.outputs.should-run == 'true'
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
id: deps-install
if: needs.conditions.outputs.should-run == 'true'
run: npm install
- name: Cache Playwright Browsers
if: needs.conditions.outputs.should-run == 'true'
uses: actions/cache@v4
with:
path: |
@ -349,22 +285,20 @@ jobs:
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
- name: Install Playwright Browsers
if: needs.conditions.outputs.should-run == 'true'
run: npm run playwright install --with-deps
- name: Build web
if: needs.conditions.outputs.should-run == 'true'
run: npm run tronb:vite:dev
- name: Start Vector
if: ${{ needs.conditions.outputs.should-run == 'true' && !contains(matrix.os, 'windows') }}
if: ${{ !contains(matrix.os, 'windows') }}
run: .github/ci-cd-scripts/start-vector-${{ env.OS_NAME }}.sh
env:
GH_ACTIONS_AXIOM_TOKEN: ${{ secrets.GH_ACTIONS_AXIOM_TOKEN }}
OS_NAME: ${{ env.OS_NAME }}
- uses: actions/download-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && (success() || failure()) }}
if: ${{ !cancelled() && (success() || failure()) }}
continue-on-error: true
with:
name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
@ -372,7 +306,7 @@ jobs:
- name: Run playwright/electron flow (with retries)
id: retry
if: ${{ needs.conditions.outputs.should-run == 'true' && !cancelled() && steps.deps-install.outcome == 'success' }}
if: ${{ !cancelled() && steps.deps-install.outcome == 'success' }}
uses: nick-fields/retry@v3.0.2
with:
shell: bash
@ -386,10 +320,11 @@ jobs:
TAB_API_KEY: ${{ secrets.TAB_API_KEY }}
CI_COMMIT_SHA: ${{ github.event.pull_request.head.sha }}
CI_PR_NUMBER: ${{ github.event.pull_request.number }}
CI_SUITE: e2e:desktop
TARGET: desktop
- uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}
if: always()
with:
name: test-results-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: test-results/
@ -398,7 +333,7 @@ jobs:
overwrite: true
- uses: actions/upload-artifact@v4
if: ${{ needs.conditions.outputs.should-run == 'true' && always() }}
if: always()
with:
name: playwright-report-${{ env.OS_NAME }}-${{ matrix.shardIndex }}-${{ github.sha }}
path: playwright-report/

View File

@ -21,14 +21,11 @@ on:
- '**.rs'
- .github/workflows/kcl-language-server.yml
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
env:
CARGO_INCREMENTAL: 0
CARGO_NET_RETRY: 10
@ -38,10 +35,9 @@ env:
MACOSX_DEPLOYMENT_TARGET: 10.15
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER: arm-linux-gnueabihf-gcc
jobs:
test:
name: vscode tests
name: kcl-language-server (vscode tests)
strategy:
fail-fast: false
matrix:
@ -77,22 +73,20 @@ jobs:
include:
- os: windows-latest
target: x86_64-pc-windows-msvc
code-target:
win32-x64
#- os: windows-latest
#target: i686-pc-windows-msvc
#code-target:
#win32-ia32
#- os: windows-latest
#target: aarch64-pc-windows-msvc
#code-target: win32-arm64
code-target: win32-x64
#- os: windows-latest
#target: i686-pc-windows-msvc
#code-target:
#win32-ia32
#- os: windows-latest
#target: aarch64-pc-windows-msvc
#code-target: win32-arm64
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
code-target:
linux-x64
#- os: ubuntu-latest
#target: aarch64-unknown-linux-musl
#code-target: linux-arm64
code-target: linux-x64
#- os: ubuntu-latest
#target: aarch64-unknown-linux-musl
#code-target: linux-arm64
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
code-target: linux-arm64
@ -105,41 +99,33 @@ jobs:
- os: macos-latest
target: aarch64-apple-darwin
code-target: darwin-arm64
name: build-release (${{ matrix.target }})
name: kcl-language-server build-release (${{ matrix.target }})
runs-on: ${{ matrix.os }}
container: ${{ matrix.container }}
env:
RA_TARGET: ${{ matrix.target }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Use correct Rust toolchain
shell: bash
run: |
rm rust/rust-toolchain.toml
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: rust
components: rust-src
target: ${{ matrix.target }}
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
- name: Update apt repositories
if: matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'arm-unknown-linux-gnueabihf' || matrix.os == 'ubuntu-latest'
run: sudo apt-get update
- if: ${{ matrix.os == 'ubuntu-latest' }}
name: Install deps
shell: bash
@ -164,64 +150,53 @@ jobs:
zlib1g-dev
cargo install cross
- name: Install AArch64 target toolchain
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: sudo apt-get install gcc-aarch64-linux-gnu
- name: Install ARM target toolchain
if: matrix.target == 'arm-unknown-linux-gnueabihf'
run: sudo apt-get install gcc-arm-linux-gnueabihf
- name: build
run: |
cd rust
cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }}
- name: Install dependencies
run: |
cd rust/kcl-language-server
# npm will symlink which will cause issues w tarballing later
yarn install
- name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/')
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }}
- name: Package Extension (nightly)
if: startsWith(github.event.ref, 'refs/tags/') == false
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-${{ matrix.code-target }}.vsix" --target ${{ matrix.code-target }} --pre-release
- name: remove server
if: matrix.target == 'x86_64-unknown-linux-gnu'
run: |
cd rust/kcl-language-server
rm -rf server
- name: Package Extension (no server, release)
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/')
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix
- name: Package Extension (no server, nightly)
if: matrix.target == 'x86_64-unknown-linux-gnu' && startsWith(github.event.ref, 'refs/tags/') == false
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o ../build/kcl-language-server-no-server.vsix --pre-release
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-${{ matrix.target }}
path: ./rust/build
build-release-x86_64-unknown-linux-musl:
name: build-release (x86_64-unknown-linux-musl)
name: kcl-language-server build-release (x86_64-unknown-linux-musl)
runs-on: ubuntu-latest
env:
RA_TARGET: x86_64-unknown-linux-musl
@ -231,7 +206,6 @@ jobs:
image: alpine:latest
volumes:
- /usr/local/cargo/registry:/usr/local/cargo/registry
steps:
- name: Install dependencies
run: |
@ -245,55 +219,46 @@ jobs:
nodejs \
npm \
yarn
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Use correct Rust toolchain
shell: bash
run: |
rm rust/rust-toolchain.toml
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: rust
components: rust-src
target: ${{ matrix.target }}
- name: build
run: |
cd rust
cargo kcl-language-server-release build --client-patch-version ${{ github.run_number }}
- name: Install dependencies
run: |
cd rust/kcl-language-server
# npm will symlink which will cause issues w tarballing later
yarn install
- name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/')
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64
- name: Package Extension (release)
if: startsWith(github.event.ref, 'refs/tags/') == false
run: |
cd rust/kcl-language-server
npx vsce package --yarn -o "../build/kcl-language-server-alpine-x64.vsix" --target alpine-x64 --pre-release
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: release-x86_64-unknown-linux-musl
path: ./rust/build
publish:
name: publish
name: kcl-language-server (publish)
runs-on: ubuntu-latest
needs: ["build-release", "build-release-x86_64-unknown-linux-musl"]
if: startsWith(github.event.ref, 'refs/tags')
@ -301,22 +266,17 @@ jobs:
contents: write
steps:
- run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- run: 'echo "TAG: $TAG"'
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: ${{ env.FETCH_DEPTH }}
- name: Install Nodejs
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
- run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
- run: 'echo "HEAD_SHA: $HEAD_SHA"'
- uses: actions/download-artifact@v4
with:
name: release-aarch64-apple-darwin
@ -344,33 +304,29 @@ jobs:
- uses: actions/download-artifact@v4
with:
name: release-x86_64-pc-windows-msvc
path:
rust/build
#- uses: actions/download-artifact@v4
#with:
#name: release-i686-pc-windows-msvc
#path:
#build
#- uses: actions/download-artifact@v4
#with:
#name: release-aarch64-pc-windows-msvc
#path: rust/build
path: rust/build
#- uses: actions/download-artifact@v4
#with:
#name: release-i686-pc-windows-msvc
#path:
#build
#- uses: actions/download-artifact@v4
#with:
#name: release-aarch64-pc-windows-msvc
#path: rust/build
- run: ls -al ./rust/build
- name: Publish Release
uses: ./.github/actions/github-release
with:
files: "rust/build/*"
name: ${{ env.TAG }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: move files to dir for upload
shell: bash
run: |
cd rust
mkdir -p releases/language-server/${{ env.TAG }}
cp -r build/* releases/language-server/${{ env.TAG }}
- name: "Authenticate to Google Cloud"
uses: "google-github-actions/auth@v2.1.8"
with:
@ -385,15 +341,12 @@ jobs:
with:
path: rust/releases
destination: dl.kittycad.io
- run: rm rust/build/kcl-language-server-no-server.vsix
- name: Publish Extension (Code Marketplace, release)
# token from https://dev.azure.com/kcl-language-server/
run: |
cd rust/kcl-language-server
npx vsce publish --pat ${{ secrets.VSCE_PAT }} --packagePath ../build/kcl-language-server-*.vsix
- name: Publish Extension (OpenVSX, release)
run: |
cd rust/kcl-language-server

View File

@ -4,7 +4,6 @@
# maturin generate-ci github
#
name: kcl-python-bindings
on:
push:
branches:
@ -27,16 +26,14 @@ on:
- '**.rs'
- .github/workflows/kcl-python-bindings.yml
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
linux-x86_64:
name: kcl-python-bindings (linux-x86_64)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -58,8 +55,8 @@ jobs:
with:
name: wheels-linux-x86_64
path: rust/kcl-python-bindings/dist
windows:
name: kcl-python-bindings (windows)
runs-on: windows-16-cores
strategy:
matrix:
@ -84,8 +81,8 @@ jobs:
with:
name: wheels-windows-${{ matrix.target }}
path: rust/kcl-python-bindings/dist
macos:
name: kcl-python-bindings (macos)
runs-on: macos-latest
strategy:
matrix:
@ -110,8 +107,8 @@ jobs:
with:
name: wheels-macos-${{ matrix.target }}
path: rust/kcl-python-bindings/dist
test:
name: kcl-python-bindings (test)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -127,8 +124,8 @@ jobs:
env:
KITTYCAD_API_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
ZOO_HOST: https://api.dev.zoo.dev
sdist:
name: kcl-python-bindings (sdist)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@ -136,10 +133,10 @@ jobs:
uses: astral-sh/setup-uv@v5
- name: Install codespell
run: |
uv venv .venv
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
echo "$PWD/.venv/bin" >> $GITHUB_PATH
uv pip install pip --upgrade
uv venv .venv
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
echo "$PWD/.venv/bin" >> $GITHUB_PATH
uv pip install pip --upgrade
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
@ -151,7 +148,6 @@ jobs:
with:
name: wheels-sdist
path: rust/kcl-python-bindings/dist
release:
name: Release
runs-on: ubuntu-latest
@ -168,11 +164,11 @@ jobs:
uses: astral-sh/setup-uv@v5
- name: do uv things
run: |
cd rust/kcl-python-bindings
uv venv .venv
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
echo "$PWD/.venv/bin" >> $GITHUB_PATH
uv pip install pip --upgrade
cd rust/kcl-python-bindings
uv venv .venv
echo "VIRTUAL_ENV=.venv" >> $GITHUB_ENV
echo "$PWD/.venv/bin" >> $GITHUB_PATH
uv pip install pip --upgrade
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:

View File

@ -28,53 +28,7 @@ jobs:
- run: npm run fmt:check
npm-build-wasm:
# Build the wasm blob once on the fastest runner.
runs-on: runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- name: Install dependencies
run: npm install
- name: Use correct Rust toolchain
shell: bash
run: |
[ -e rust-toolchain.toml ] || cp rust/rust-toolchain.toml ./
- name: Install rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
cache: false # Configured below.
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Rust Cache
uses: Swatinem/rust-cache@v2
with:
workspaces: './rust'
- name: Build Wasm
shell: bash
run: npm run build:wasm
- uses: actions/upload-artifact@v4
with:
name: prepared-wasm
path: |
rust/kcl-wasm-lib/pkg/kcl_wasm_lib*
- uses: actions/upload-artifact@v4
with:
name: prepared-ts-rs-bindings
path: |
rust/kcl-lib/bindings/*
uses: ./.github/workflows/build-wasm.yml
npm-tsc:
runs-on: ubuntu-latest
@ -173,116 +127,3 @@ jobs:
uses: actions/checkout@v4
- name: Run codespell
uses: crate-ci/typos@v1.32.0
npm-unit-test-kcl-samples:
runs-on: ubuntu-latest
needs: npm-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
- name: Install Chromium Browser
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: npm run playwright install chromium --with-deps
- name: run unit tests for kcl samples
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: npm run test:unit:kcl-samples
env:
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
npm-unit-test:
runs-on: ubuntu-latest
needs: npm-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
- name: Install Chromium Browser
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: npm run playwright install chromium --with-deps
- name: Run unit tests
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: xvfb-run -a npm run test:unit
env:
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- name: Check for changes
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
id: git-check
run: |
git add src/lang/std/artifactMapGraphs
if git status src/lang/std/artifactMapGraphs | grep -q "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT
fi
- name: Commit changes, if any
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' && steps.git-check.outputs.modified == 'true' }}
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
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
git commit -am "Look at this (photo)Graph *in the voice of Nickelback*" || true
git push
git push origin ${{ github.head_ref }}

View File

@ -1,39 +0,0 @@
name: tag-nightly
permissions:
contents: write
on:
schedule:
- cron: '0 4 * * *'
# Daily at 04:00 AM UTC
# Will checkout the last commit from the default branch (main as of 2023-10-04)
jobs:
tag-nightly:
runs-on: ubuntu-22.04
steps:
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.MODELING_APP_GH_APP_ID }}
private-key: ${{ secrets.MODELING_APP_GH_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- run: npm install
- name: Push tag
run: |
VERSION_NO_V=$(date +'%-y.%-m.%-d')
TAG="nightly-v$VERSION_NO_V"
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git tag $TAG
git push origin tag $TAG

124
.github/workflows/unit-tests.yml vendored Normal file
View File

@ -0,0 +1,124 @@
name: Unit Tests
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: write
pull-requests: write
actions: read
jobs:
npm-build-wasm:
uses: ./.github/workflows/build-wasm.yml
npm-test-unit:
runs-on: ubuntu-latest
needs: npm-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- run: npm run simpleserver:bg
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
- name: Install Chromium Browser
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: npm run playwright install chromium --with-deps
- name: Run unit tests
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
run: xvfb-run -a npm run test:unit
env:
VITE_KC_DEV_TOKEN: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
- name: Check for changes
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' }}
id: git-check
run: |
git add src/lang/std/artifactMapGraphs
if git status src/lang/std/artifactMapGraphs | grep -q "Changes to be committed"
then echo "modified=true" >> $GITHUB_OUTPUT
else echo "modified=false" >> $GITHUB_OUTPUT
fi
- name: Commit changes, if any
if: ${{ github.event_name != 'release' && github.event_name != 'schedule' && steps.git-check.outputs.modified == 'true' }}
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
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
git commit -am "Look at this (photo)Graph *in the voice of Nickelback*" || true
git push
git push origin ${{ github.head_ref }}
npm-test-unit-components:
runs-on: ubuntu-latest
needs: npm-build-wasm
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm install
- uses: taiki-e/install-action@d4635f2de61c8b8104d59cd4aede2060638378cc
with:
tool: wasm-pack
- name: Download all artifacts
uses: actions/download-artifact@v4
- name: Copy prepared wasm
run: |
ls -R prepared-wasm
cp prepared-wasm/kcl_wasm_lib_bg.wasm public
mkdir rust/kcl-wasm-lib/pkg
cp prepared-wasm/kcl_wasm_lib* rust/kcl-wasm-lib/pkg
- name: Copy prepared ts-rs bindings
run: |
ls -R prepared-ts-rs-bindings
mkdir rust/kcl-lib/bindings
cp -r prepared-ts-rs-bindings/* rust/kcl-lib/bindings/
- name: Run component tests
run: npm run test:unit:components

2
.gitignore vendored
View File

@ -58,6 +58,8 @@ trace.zip
/public/kcl-samples/.github
/public/kcl-samples/screenshots/main.kcl
/public/kcl-samples/step/main.kcl
/public/kcl-samples/internal
/rust/kcl-lib/tests/kcl_samples/internal
/test-results/
/playwright-report/
/blob-report/

View File

@ -122,15 +122,14 @@ https://github.com/KittyCAD/modeling-app/issues/new
#### 2. Push a new tag
Create a new tag and push it to the repo. The `semantic-release.sh` script will automatically bump the minor part, which we use the most. For instance going from `v0.27.0` to `v0.28.0`.
Decide on a `v`-prefixed semver `VERSION` (eg. `v1.2.3`) with the team and tag the repo, eg. on latest main:
```
VERSION=$(./scripts/semantic-release.sh)
git tag $VERSION
git push origin --tags
git push origin $VERSION
```
This will trigger the `build-apps` workflow, set the version, build & sign the apps, and generate release files as well as updater-test artifacts.
This will trigger the `build-apps` workflow, set the version, build & sign the apps, and generate release files.
The workflow should be listed right away [in this list](https://github.com/KittyCAD/modeling-app/actions/workflows/build-apps.yml?query=event%3Apush)).
@ -142,13 +141,10 @@ The release builds can be found under the `out-{arch}-{platform}` zip files, at
Manually test against this [list](https://github.com/KittyCAD/modeling-app/issues/3588) across Windows, MacOS, Linux and posting results as comments in the issue.
##### Updater-test builds
The other `build-apps` output in the release `build-apps` workflow (triggered by 2.) is `updater-test-{arch}-{platform}`. It's a semi-automated process: for macOS, Windows, and Linux, download the corresponding updater-test artifact file, install the app, run it, expect an updater prompt to a dummy v0.255.255, install it and check that the app comes back at that version.
The only difference with these builds is that they point to a different update location on the release bucket, with this dummy v0.255.255 always available. This helps ensuring that the version we release will be able to update to the next one available.
If the prompt doesn't show up, start the app in command line to grab the electron-updater logs. This is likely an issue with the current build that needs addressing (or the updater-test location in the storage bucket).
A prompt should show up asking for a downgrade to the last release version. Running through that at the end of testing
and making sure the current release candidate has the ability to be updated to what electron-updater points to is critical,
but what is actually being downloaded and installed isn't.
If the prompt doesn't show up, start the app in command line to grab the electron-updater logs. This is likely an issue with the current build that needs addressing.
```
# Windows (PowerShell)

View File

@ -4,7 +4,7 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
## Windows
1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for Windows and for your processor type.
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for Windows and for your processor type.
2. Once downloaded, run the installer `Zoo Design Studio-{version}-{arch}-win.exe` which should take a few seconds.
@ -12,16 +12,16 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
## macOS
1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for macOS and for your processor type.
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for macOS and for your processor type.
2. Once downloaded, open the disk image `Zoo Design Studio-{version}-{arch}-mac.dmg` and drag the applications to your `Applications` directory.
3. You can then open your `Applications` directory and double-click on `Zoo Design Studio` to open.
## Linux
## Linux
1. Download the [Zoo Design Studio installer](https://zoo.dev/modeling-app/download) for Linux and for your processor type.
1. Download the [Zoo Design Studio installer](https://zoo.dev/design-studio/download) for Linux and for your processor type.
2. Install the dependencies needed to run the [AppImage format](https://appimage.org/).
- On Ubuntu, install the FUSE library with these commands in a terminal.
@ -29,7 +29,7 @@ Compared to other CAD software, getting Zoo Design Studio up and running is quic
sudo apt update
sudo apt install libfuse2
```
- Optionally, follow [these steps](https://github.com/probonopd/go-appimage/blob/master/src/appimaged/README.md#initial-setup) to install `appimaged`. It is a daemon that makes interacting with AppImage files more seamless.
- Optionally, follow [these steps](https://github.com/probonopd/go-appimage/blob/master/src/appimaged/README.md#initial-setup) to install `appimaged`. It is a daemon that makes interacting with AppImage files more seamless.
- Once installed, copy the downloaded `Zoo Design Studio-{version}-{arch}-linux.AppImage` to the directory of your choice, for instance `~/Applications`.
- `appimaged` should automatically find it and make it executable. If not, run:

View File

@ -23,6 +23,7 @@ endif
install: node_modules/.package-lock.json $(CARGO) $(WASM_PACK) ## Install dependencies
node_modules/.package-lock.json: package.json package-lock.json
npm prune
npm install
$(CARGO):
@ -43,15 +44,15 @@ endif
# BUILD
CARGO_SOURCES := rust/.cargo/config.toml $(wildcard rust/Cargo.*) $(wildcard rust/**/Cargo.*)
KCL_SOURCES := $(wildcard public/kcl-samples/**/*.kcl)
RUST_SOURCES := $(wildcard rust/**/*.rs)
REACT_SOURCES := $(wildcard src/*.tsx) $(wildcard src/**/*.tsx)
TYPESCRIPT_SOURCES := tsconfig.* $(wildcard src/*.ts) $(wildcard src/**/*.ts)
VITE_SOURCES := $(wildcard vite.*) $(wildcard vite/**/*.tsx)
.PHONY: build
build: install public/kcl_wasm_lib_bg.wasm .vite/build/main.js
build: install public/kcl_wasm_lib_bg.wasm public/kcl-samples/manifest.json .vite/build/main.js
public/kcl_wasm_lib_bg.wasm: $(CARGO_SOURCES) $(RUST_SOURCES)
ifdef WINDOWS
@ -60,6 +61,9 @@ else
npm run build:wasm:dev
endif
public/kcl-samples/manifest.json: $(KCL_SOURCES)
cd rust/kcl-lib && EXPECTORATE=overwrite cargo test generate_manifest
.vite/build/main.js: $(REACT_SOURCES) $(TYPESCRIPT_SOURCES) $(VITE_SOURCES)
npm run tronb:vite:dev
@ -107,6 +111,7 @@ test: test-unit test-e2e
.PHONY: test-unit
test-unit: install ## Run the unit tests
npm run test:rust
npm run test:unit:components
@ curl -fs localhost:3000 >/dev/null || ( echo "Error: localhost:3000 not available, 'make run-web' first" && exit 1 )
npm run test:unit

View File

@ -2,7 +2,7 @@
# Zoo Design Studio
[zoo.dev/modeling-app](https://zoo.dev/modeling-app)
[zoo.dev/design-studio](https://zoo.dev/design-studio)
A CAD application from the future, brought to you by the [Zoo team](https://zoo.dev).
@ -34,20 +34,14 @@ The 3D view in Design Studio is just a video stream from our hosted geometry eng
- WebSockets (via [KittyCAD TS client](https://github.com/KittyCAD/kittycad.ts))
- Code Editor
- [CodeMirror](https://codemirror.net/)
- Custom WASM LSP Server
- [Custom WASM LSP Server](https://github.com/KittyCAD/modeling-app/tree/main/rust/kcl-lib/src/lsp/kcl)
- Modeling
- [KittyCAD TypeScript client](https://github.com/KittyCAD/kittycad.ts)
## Get Started
We recommend downloading the latest application binary from our [releases](https://github.com/KittyCAD/modeling-app/releases) page. If you don't see your platform or architecture supported there, please file an issue.
If you'd like to try out upcoming changes sooner, you can also download those from our [nightly releases](https://zoo.dev/modeling-app/download/nightly) page.
We recommend downloading the latest application binary from our [website](https://zoo.dev/design-studio/download). If you don't see your platform or architecture supported there, please file an issue. See the [installation guide](INSTALL.md) for additional instructions.
## Developing
Finally, if you'd like to run a development build or contribute to the project, please visit our [contributor guide](CONTRIBUTING.md) to get started.
## KCL
To contribute to the KittyCAD Language, see the [README](https://github.com/KittyCAD/modeling-app/tree/main/rust/kcl-lib) for KCL.
Finally, if you'd like to run a development build or contribute to the project, please visit our [contributor guide](CONTRIBUTING.md) to get started. To contribute to the KittyCAD Language, see the dedicated [readme](rust/kcl-lib/README.md) for KCL.

View File

@ -21,7 +21,7 @@ extend-exclude = [
]
[default.extend-words]
metalness = "metalness" # appearance API
metalness = "metalness" # appearance API
Hom = "Hom" # short for homogenous
typ = "typ" # used to declare a variable named 'type' which is a reserved keyword in Rust
ue = "ue" # short for UnaryExpression
@ -29,6 +29,7 @@ THRE = "THRE" # Weird bug that wrongly detects THREEjs as a typo
nwo = "nwo" # don't know what this is about tbh
"ot" = "ot" # some abbreviation, idk what
"oe" = "oe" # some abbreviation, idk what
"colinear" = "colinear" # some engine shit, kidding
[default]
extend-ignore-identifiers-re = [

32
docs/kcl-lang/arrays.md Normal file
View File

@ -0,0 +1,32 @@
---
title: "Arrays and ranges"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
Arrays are sequences of values.
Arrays can be written out as *array literals* using a sequence of expressions surrounded by square brackets, e.g., `['hello', 'world']` is an array of strings, `[x, x + 1, x + 2]` is an array of numbers (assuming `x` is a number), `[]` is an empty array, and `['hello', 42, true]` is a mixed array.
A value in an array can be accessed by indexing using square brackets where the index is a number, for example, `arr[0]`, `arr[42]`, `arr[i]` (where `arr` is an array and `i` is a (whole) number).
There are some useful functions for working with arrays in the standard library, see [std::array](/docs/kcl-std/modules/std-array) for details.
## Array types
Arrays have their own types: `[T]` where `T` is the type of the elements of the array, for example, `[string]` means an array of `string`s and `[any]` means an array of any values.
Array types can also include length information: `[T; n]` denotes an array of length `n` (where `n` is a number literal) and `[T; 1+]` denotes an array whose length is at least one (i.e., a non-empty array). E.g., `[string; 1+]` and `[number(mm); 3]` are valid array types.
## Ranges
Ranges are a succinct way to create an array of sequential numbers. The syntax is `[start .. end]` where `start` and `end` evaluate to whole numbers (integers). Ranges are inclusive of the start and end. The end must be greater than the start. Examples:
```kcl,norun
[0..3] // [0, 1, 2, 3]
[3..10] // [3, 4, 5, 6, 7, 8, 9, 10]
x = 2
[x..x+1] // [2, 3]
```
The units of the start and end numbers must be the same and the result inherits those units.

View File

@ -0,0 +1,99 @@
---
title: "Importing geometry from other CAD systems"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
`import` can also be used to import files from other CAD systems. The format of the statement is the
same as for KCL files. You can only import the whole file, not items from it. E.g.,
```norun
import "tests/inputs/cube.obj"
// Use `cube` just like a KCL object.
```
```kcl
import "tests/inputs/cube.sldprt" as cube
// Use `cube` just like a KCL object.
```
For formats lacking unit data (such as STL, OBJ, or PLY files), the default
unit of measurement is millimeters. Alternatively you may specify the unit
by using an attribute. Likewise, you can also specify a coordinate system. E.g.,
```kcl
@(lengthUnit = ft, coords = opengl)
import "tests/inputs/cube.obj"
```
When importing a GLTF file, the bin file will be imported as well.
Import paths are relative to the current project directory. Imports currently only work when
using the native Design Studio, not in the browser.
### Supported values
File formats: `fbx`, `gltf`/`glb`, `obj`+, `ply`+, `sldprt`, `step`/`stp`, `stl`+. (Those marked with a
'+' support customising the length unit and coordinate system).
Length units: `mm` (the default), `cm`, `m`, `inch`, `ft`, `yd`.
Coordinate systems:
- `zoo` (the default), forward: -Y, up: +Z, handedness: right
- `opengl`, forward: +Z, up: +Y, handedness: right
- `vulkan`, forward: +Z, up: -Y, handedness: left
---
## Performance deepdive for foreignfile imports
Parallelized foreignfile imports now let you overlap file reads, initialization,
and rendering. To maximize throughput, you need to understand the three distinct
stages—reading, initializing (background render start), and invocation (blocking)
—and structure your code to defer blocking operations until the end.
### Foreign import execution stages
1. **Import (Read / Initialization) Stage**
```kcl
import "tests/inputs/cube.step" as cube
```
- Reads the file from disk and makes its API available.
- Starts engine rendering but **does not block** your script.
- This kickstarts the render pipeline while you keep executing other code.
2. **Invocation (Blocking) Stage**
```kcl
import "tests/inputs/cube.step" as cube
cube
|> translate(z=10) // ← blocks here only
```
- Any method call (e.g., `translate`, `scale`, `rotate`) waits for the background render to finish before applying transformations.
### Best practices
#### 1. Defer blocking calls
```kcl
import "tests/inputs/cube.step" as cube // 1) Read / Background render starts
// --- perform other operations and calculations here ---
cube
|> translate(z=10) // 2) Blocks only here
```
#### 2. Split heavy work into separate modules
Place computationally expensive or IOheavy work into its own module so it can render in parallel while `main.kcl` continues.
#### Future improvements
Upcoming releases will autoanalyse dependencies and only block when truly necessary. Until then, explicit deferral will give you the best performance.

View File

@ -4,8 +4,8 @@ excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
This is a reference for KCL. If you are learning KCL, you may prefer the [guide]() which explains
things in a more tutorial fashion.
This is a reference for KCL. If you are learning KCL, you may prefer the [guide](https://zoo.dev/docs/kcl-book/intro.html) which explains
things in a more tutorial fashion. See also our documentation of the [standard library](/docs/kcl-std).
## Topics
@ -14,7 +14,9 @@ things in a more tutorial fashion.
* [Values and types](/docs/kcl-lang/types)
* [Numeric types and units](/docs/kcl-lang/numeric)
* [Functions](/docs/kcl-lang/functions)
* [Projects, modules, and imports](/docs/kcl-lang/modules)
* [Arrays and ranges](/docs/kcl-lang/arrays)
* [Projects and modules](/docs/kcl-lang/modules)
* [Attributes](/docs/kcl-lang/attributes)
* [Importing geometry from other CAD systems](/docs/kcl-lang/foreign-imports)
* [Settings](/docs/kcl-lang/settings)
* [Known Issues](/docs/kcl-lang/known-issues)

View File

@ -1,5 +1,5 @@
---
title: "Modules"
title: "Projects and modules"
excerpt: "Documentation of the KCL language for the Zoo Design Studio."
layout: manual
---
@ -27,9 +27,6 @@ import increment from "util.kcl"
answer = increment(41)
```
Imported files _must_ be in the same project so that units are uniform across
modules. This means that it must be in the same directory.
Import statements must be at the top-level of a file. It is not allowed to have
an `import` statement inside a function or in the body of an ifelse.
@ -58,6 +55,9 @@ Imported symbols can be renamed for convenience or to avoid name collisions.
import increment as inc, decrement as dec from "util.kcl"
```
You can import files from the current directory or from subdirectories, but if importing from a
subdirectory you can only import `main.kcl`.
---
## Functions vs `clone`
@ -177,7 +177,7 @@ You can also import the whole module. This is useful if you want to use the
result of a module as a variable, like a part.
```norun
import "tests/inputs/cube.kcl" as cube
import "cube.kcl"
cube
|> translate(x=10)
```
@ -229,6 +229,19 @@ The final statement is what's important because it's the return value of the
entire module. The module is expected to return a single object that can be used
as a variable by the file that imports it.
The name of the file or subdirectory is used as the name of the variable within the importing program.
If you want to use a different name, you can do so by using the `as` keyword:
```kcl,norun
import "cube.kcl" // Introduces a new variable called `cube`.
import "cube.kcl" as block // Introduces a new variable called `block`.
import "cube/main.kcl" // Introduces a new variable called `cube`.
import "cube/main.kcl" as block // Introduces a new variable called `block`.
```
If the filename includes hyphens (`-`) or starts with an underscore (`_`), then you must specify a
variable name.
---
## Multiple instances of the same import
@ -241,7 +254,7 @@ If you want to have multiple instances of the same object, you can use the
[`clone`](/docs/kcl/clone) function. This will render a new instance of the object in memory.
```norun
import cube from "tests/inputs/cube.kcl"
import cube from "cube.kcl"
cube
|> translate(x=10)
@ -257,109 +270,10 @@ separate objects in memory, and can be manipulated independently.
Here is an example with a file from another CAD system:
```kcl
import "tests/inputs/cube.step" as cube
import "tests/inputs/cube.step"
cube
|> translate(x=10)
clone(cube)
|> translate(x=20)
```
---
## Importing files from other CAD systems
`import` can also be used to import files from other CAD systems. The format of the statement is the
same as for KCL files. You can only import the whole file, not items from it. E.g.,
```norun
import "tests/inputs/cube.obj"
// Use `cube` just like a KCL object.
```
```kcl
import "tests/inputs/cube.sldprt" as cube
// Use `cube` just like a KCL object.
```
For formats lacking unit data (such as STL, OBJ, or PLY files), the default
unit of measurement is millimeters. Alternatively you may specify the unit
by using an attribute. Likewise, you can also specify a coordinate system. E.g.,
```kcl
@(lengthUnit = ft, coords = opengl)
import "tests/inputs/cube.obj"
```
When importing a GLTF file, the bin file will be imported as well.
Import paths are relative to the current project directory. Imports currently only work when
using the native Design Studio, not in the browser.
### Supported values
File formats: `fbx`, `gltf`/`glb`, `obj`+, `ply`+, `sldprt`, `step`/`stp`, `stl`+. (Those marked with a
'+' support customising the length unit and coordinate system).
Length units: `mm` (the default), `cm`, `m`, `inch`, `ft`, `yd`.
Coordinate systems:
- `zoo` (the default), forward: -Y, up: +Z, handedness: right
- `opengl`, forward: +Z, up: +Y, handedness: right
- `vulkan`, forward: +Z, up: -Y, handedness: left
---
## Performance deepdive for foreignfile imports
Parallelized foreignfile imports now let you overlap file reads, initialization,
and rendering. To maximize throughput, you need to understand the three distinct
stages—reading, initializing (background render start), and invocation (blocking)
—and structure your code to defer blocking operations until the end.
### Foreign import execution stages
1. **Import (Read / Initialization) Stage**
```kcl
import "tests/inputs/cube.step" as cube
```
- Reads the file from disk and makes its API available.
- Starts engine rendering but **does not block** your script.
- This kickstarts the render pipeline while you keep executing other code.
2. **Invocation (Blocking) Stage**
```kcl
import "tests/inputs/cube.step" as cube
cube
|> translate(z=10) // ← blocks here only
```
- Any method call (e.g., `translate`, `scale`, `rotate`) waits for the background render to finish before applying transformations.
### Best practices
#### 1. Defer blocking calls
```kcl
import "tests/inputs/cube.step" as cube // 1) Read / Background render starts
// --- perform other operations and calculations here ---
cube
|> translate(z=10) // 2) Blocks only here
```
#### 2. Split heavy work into separate modules
Place computationally expensive or IOheavy work into its own module so it can render in parallel while `main.kcl` continues.
#### Future improvements
Upcoming releases will autoanalyse dependencies and only block when truly necessary. Until then, explicit deferral will give you the best performance.

View File

@ -28,6 +28,8 @@ Any of the suffixes described above can be used meaning that values with that ty
You can also use `number(Length)`, `number(Angle)`, or `number(Count)`. These types mean a number with any length, angle, or unitless (count) units, respectively (note that `number(_)` and `number(Count)` are equivalent since there is only one kind of unitless-ness).
Using just `number` means accepting any kind of number, even where the units are unknown by KCL.
## Function calls

View File

@ -19,18 +19,6 @@ myBool = false
Currently you cannot redeclare a constant.
## Arrays
An array is defined with `[]` braces. What is inside the brackets can
be of any type. For example, the following is completely valid:
```
myArray = ["thing", 2, false]
```
If you want to get a value from an array you can use the index like so:
`myArray[0]`.
## Objects
@ -40,8 +28,8 @@ An object is defined with `{}` braces. Here is an example object:
myObj = { a = 0, b = "thing" }
```
We support two different ways of getting properties from objects, you can call
`myObj.a` or `myObj["a"]` both work.
To get the property of an object, you can call `myObj.a`, which in the above
example returns 0.
## `ImportedGeometry`

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -11,7 +11,13 @@ The value of `pi`, Archimedes constant (π).
PI: number(_?) = 3.14159265358979323846264338327950288_?
```
`PI` is a number and is technically a ratio, so you might expect it to have type `number(_)`.
However, `PI` is nearly always used for converting between different units - usually degrees to or
from radians. Therefore, `PI` is treated a bit specially by KCL and always has unknown units. This
means that if you use `PI`, you will need to give KCL some extra information about the units of numbers.
Usually you should use type ascription on the result of calculations, e.g., `(2 * PI): number(rad)`.
You might prefer to use `units::toRadians` or `units::toDegrees` to convert between angles with
different units.
### Examples

View File

@ -0,0 +1,16 @@
---
title: "sweep::SKETCH_PLANE"
subtitle: "Constant in std::sweep"
excerpt: "Local/relative to a position centered within the plane being sketched on"
layout: manual
---
Local/relative to a position centered within the plane being sketched on
```kcl
sweep::SKETCH_PLANE: string = 'sketchPlane'
```

View File

@ -0,0 +1,16 @@
---
title: "sweep::TRAJECTORY"
subtitle: "Constant in std::sweep"
excerpt: "Local/relative to the trajectory curve"
layout: manual
---
Local/relative to the trajectory curve
```kcl
sweep::TRAJECTORY: string = 'trajectoryCurve'
```

View File

@ -26,7 +26,7 @@ You can provide more than one sketch to extrude, and they will all be extruded i
|----------|------|-------------|----------|
| `sketches` | [`[Sketch]`](/docs/kcl-std/types/std-types-Sketch) | Which sketch or sketches should be extruded | Yes |
| `length` | [`number`](/docs/kcl-std/types/std-types-number) | How far to extrude the given sketches | Yes |
| `symmetric` | [`bool`](/docs/kcl-std/types/std-types-bool) | If true, the extrusion will happen symmetrically around the sketch. Otherwise, the | No |
| `symmetric` | [`bool`](/docs/kcl-std/types/std-types-bool) | If true, the extrusion will happen symmetrically around the sketch. Otherwise, the extrusion will happen on only one side of the sketch. | No |
| `bidirectionalLength` | [`number`](/docs/kcl-std/types/std-types-number) | If specified, will also extrude in the opposite direction to 'distance' to the specified distance. If 'symmetric' is true, this value is ignored. | No |
| `tagStart` | [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator) | A named tag for the face at the start of the extrusion, i.e. the original sketch | No |
| `tagEnd` | [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator) | A named tag for the face at the end of the extrusion, i.e. the new face created by extruding the original sketch | No |

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

@ -0,0 +1,38 @@
---
title: "legAngX"
subtitle: "Function in std::math"
excerpt: "Compute the angle of the given leg for x."
layout: manual
---
Compute the angle of the given leg for x.
```kcl
legAngX(
hypotenuse: number(Length),
leg: number(Length),
): number(deg)
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse. | Yes |
| `leg` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side). | Yes |
### Returns
[`number(deg)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legAngX(hypotenuse = 5, leg = 3)
```

View File

@ -0,0 +1,38 @@
---
title: "legAngY"
subtitle: "Function in std::math"
excerpt: "Compute the angle of the given leg for y."
layout: manual
---
Compute the angle of the given leg for y.
```kcl
legAngY(
hypotenuse: number(Length),
leg: number(Length),
): number(deg)
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse. | Yes |
| `leg` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side). | Yes |
### Returns
[`number(deg)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legAngY(hypotenuse = 5, leg = 3)
```

View File

@ -0,0 +1,38 @@
---
title: "legLen"
subtitle: "Function in std::math"
excerpt: "Compute the length of the given leg."
layout: manual
---
Compute the length of the given leg.
```kcl
legLen(
hypotenuse: number(Length),
leg: number(Length),
): number(Length)
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse. | Yes |
| `leg` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side). | Yes |
### Returns
[`number(Length)`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legLen(hypotenuse = 5, leg = 3)
```

View File

@ -11,7 +11,8 @@ layout: manual
circle(
@sketch_or_surface: Sketch | Plane | Face,
center: Point2d,
radius: number(Length),
radius?: number(Length),
diameter?: number(Length),
tag?: tag,
): Sketch
```
@ -25,7 +26,8 @@ the provided (x, y) origin point.
|----------|------|-------------|----------|
| `sketch_or_surface` | [`Sketch`](/docs/kcl-std/types/std-types-Sketch) or [`Plane`](/docs/kcl-std/types/std-types-Plane) or [`Face`](/docs/kcl-std/types/std-types-Face) | Sketch to extend, or plane or surface to sketch on. | Yes |
| `center` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | The center of the circle. | Yes |
| `radius` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The radius of the circle. | Yes |
| `radius` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The radius of the circle. Incompatible with `diameter`. | No |
| `diameter` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | The diameter of the circle. Incompatible with `radius`. | No |
| [`tag`](/docs/kcl-std/types/std-types-tag) | [`tag`](/docs/kcl-std/types/std-types-tag) | Create a new tag which refers to this circle. | No |
### Returns
@ -51,7 +53,7 @@ exampleSketch = startSketchOn(XZ)
|> line(end = [0, 30])
|> line(end = [-30, 0])
|> close()
|> subtract2d(tool = circle(center = [0, 15], radius = 5))
|> subtract2d(tool = circle(center = [0, 15], diameter = 10))
example = extrude(exampleSketch, length = 5)
```

View File

@ -1,19 +1,19 @@
---
title: "patternTransform2d"
subtitle: "Function in std::sketch"
excerpt: "Just like patternTransform, but works on 2D sketches not 3D solids."
excerpt: "Just like `patternTransform`, but works on 2D sketches not 3D solids."
layout: manual
---
Just like patternTransform, but works on 2D sketches not 3D solids.
Just like `patternTransform`, but works on 2D sketches not 3D solids.
```kcl
patternTransform2d(
@sketches: [Sketch],
instances: number,
transform: FunctionSource,
useOriginal?: bool,
): [Sketch]
@sketches: [Sketch; 1+],
instances: number(_),
transform: fn(number(_)): { },
useOriginal?: boolean,
): [Sketch; 1+]
```
@ -22,14 +22,14 @@ patternTransform2d(
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `sketches` | [`[Sketch]`](/docs/kcl-std/types/std-types-Sketch) | The sketch(es) to duplicate | Yes |
| `instances` | [`number`](/docs/kcl-std/types/std-types-number) | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `transform` | `FunctionSource` | How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples. | Yes |
| `useOriginal` | [`bool`](/docs/kcl-std/types/std-types-bool) | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |
| `sketches` | [`[Sketch; 1+]`](/docs/kcl-std/types/std-types-Sketch) | The sketch(es) to duplicate. | Yes |
| `instances` | [`number(_)`](/docs/kcl-std/types/std-types-number) | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `transform` | [`fn(number(_)): { }`](/docs/kcl-std/types/std-types-fn) | How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples. | Yes |
| `useOriginal` | `boolean` | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. | No |
### Returns
[`[Sketch]`](/docs/kcl-std/types/std-types-Sketch)
[`[Sketch; 1+]`](/docs/kcl-std/types/std-types-Sketch)
### Examples

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -14,8 +14,6 @@ mirror2d(
): Sketch
```
Only works on unclosed sketches for now.
Mirror occurs around a local sketch axis rather than a global axis.
### Arguments

View File

@ -8,7 +8,7 @@ layout: manual
Convert a number to centimeters from its current units.
```kcl
units::toCentimeters(@num: number(cm)): number(cm)
units::toCentimeters(@num: number(Length)): number(cm)
```
@ -17,7 +17,7 @@ units::toCentimeters(@num: number(cm)): number(cm)
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(cm)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
| `num` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns

View File

@ -8,7 +8,7 @@ layout: manual
Converts a number to degrees from its current units.
```kcl
units::toDegrees(@num: number(deg)): number(deg)
units::toDegrees(@num: number(Angle)): number(deg)
```
@ -17,7 +17,7 @@ units::toDegrees(@num: number(deg)): number(deg)
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(deg)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
| `num` | [`number(Angle)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns

View File

@ -8,7 +8,7 @@ layout: manual
Convert a number to feet from its current units.
```kcl
units::toFeet(@num: number(ft)): number(ft)
units::toFeet(@num: number(Length)): number(ft)
```
@ -17,7 +17,7 @@ units::toFeet(@num: number(ft)): number(ft)
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(ft)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
| `num` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns

View File

@ -8,7 +8,7 @@ layout: manual
Convert a number to inches from its current units.
```kcl
units::toInches(@num: number(in)): number(in)
units::toInches(@num: number(Length)): number(in)
```
@ -17,7 +17,7 @@ units::toInches(@num: number(in)): number(in)
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(in)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
| `num` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns

View File

@ -8,7 +8,7 @@ layout: manual
Convert a number to meters from its current units.
```kcl
units::toMeters(@num: number(m)): number(m)
units::toMeters(@num: number(Length)): number(m)
```
@ -17,7 +17,7 @@ units::toMeters(@num: number(m)): number(m)
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(m)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
| `num` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns

View File

@ -8,7 +8,7 @@ layout: manual
Convert a number to millimeters from its current units.
```kcl
units::toMillimeters(@num: number(mm)): number(mm)
units::toMillimeters(@num: number(Length)): number(mm)
```
@ -17,7 +17,7 @@ units::toMillimeters(@num: number(mm)): number(mm)
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(mm)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
| `num` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns

View File

@ -8,7 +8,7 @@ layout: manual
Converts a number to radians from its current units.
```kcl
units::toRadians(@num: number(rad)): number(rad)
units::toRadians(@num: number(Angle)): number(rad)
```
@ -17,7 +17,7 @@ units::toRadians(@num: number(rad)): number(rad)
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(rad)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
| `num` | [`number(Angle)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns

View File

@ -8,7 +8,7 @@ layout: manual
Converts a number to yards from its current units.
```kcl
units::toYards(@num: number(yd)): number(yd)
units::toYards(@num: number(Length)): number(yd)
```
@ -17,7 +17,7 @@ units::toYards(@num: number(yd)): number(yd)
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `num` | [`number(yd)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
| `num` | [`number(Length)`](/docs/kcl-std/types/std-types-number) | A number. | Yes |
### Returns

View File

@ -12,15 +12,17 @@ layout: manual
* [`appearance`](/docs/kcl-std/appearance)
* [`assert`](/docs/kcl-std/assert)
* [`assertIs`](/docs/kcl-std/assertIs)
* [`clone`](/docs/kcl-std/clone)
* [`clone`](/docs/kcl-std/functions/std-clone)
* [`helix`](/docs/kcl-std/functions/std-helix)
* [`offsetPlane`](/docs/kcl-std/functions/std-offsetPlane)
* [`patternLinear2d`](/docs/kcl-std/patternLinear2d)
* [**std::appearance**](/docs/kcl-std/modules/std-appearance)
* [`appearance::hexString`](/docs/kcl-std/functions/std-appearance-hexString)
* [**std::array**](/docs/kcl-std/modules/std-array)
* [`map`](/docs/kcl-std/map)
* [`pop`](/docs/kcl-std/pop)
* [`push`](/docs/kcl-std/push)
* [`reduce`](/docs/kcl-std/reduce)
* [`map`](/docs/kcl-std/functions/std-array-map)
* [`pop`](/docs/kcl-std/functions/std-array-pop)
* [`push`](/docs/kcl-std/functions/std-array-push)
* [`reduce`](/docs/kcl-std/functions/std-array-reduce)
* [**std::math**](/docs/kcl-std/modules/std-math)
* [`abs`](/docs/kcl-std/functions/std-math-abs)
* [`acos`](/docs/kcl-std/functions/std-math-acos)
@ -30,9 +32,9 @@ layout: manual
* [`ceil`](/docs/kcl-std/functions/std-math-ceil)
* [`cos`](/docs/kcl-std/functions/std-math-cos)
* [`floor`](/docs/kcl-std/functions/std-math-floor)
* [`legAngX`](/docs/kcl-std/legAngX)
* [`legAngY`](/docs/kcl-std/legAngY)
* [`legLen`](/docs/kcl-std/legLen)
* [`legAngX`](/docs/kcl-std/functions/std-math-legAngX)
* [`legAngY`](/docs/kcl-std/functions/std-math-legAngY)
* [`legLen`](/docs/kcl-std/functions/std-math-legLen)
* [`ln`](/docs/kcl-std/functions/std-math-ln)
* [`log`](/docs/kcl-std/functions/std-math-log)
* [`log10`](/docs/kcl-std/functions/std-math-log10)
@ -65,7 +67,7 @@ layout: manual
* [`line`](/docs/kcl-std/line)
* [`loft`](/docs/kcl-std/loft)
* [`patternCircular2d`](/docs/kcl-std/patternCircular2d)
* [`patternTransform2d`](/docs/kcl-std/patternTransform2d)
* [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d)
* [`polygon`](/docs/kcl-std/polygon)
* [`profileStart`](/docs/kcl-std/profileStart)
* [`profileStartX`](/docs/kcl-std/profileStartX)
@ -94,7 +96,7 @@ layout: manual
* [`intersect`](/docs/kcl-std/intersect)
* [`patternCircular3d`](/docs/kcl-std/patternCircular3d)
* [`patternLinear3d`](/docs/kcl-std/patternLinear3d)
* [`patternTransform`](/docs/kcl-std/patternTransform)
* [`patternTransform`](/docs/kcl-std/functions/std-solid-patternTransform)
* [`shell`](/docs/kcl-std/functions/std-solid-shell)
* [`subtract`](/docs/kcl-std/subtract)
* [`union`](/docs/kcl-std/union)
@ -128,6 +130,9 @@ layout: manual
* [`E`](/docs/kcl-std/consts/std-math-E)
* [`PI`](/docs/kcl-std/consts/std-math-PI)
* [`TAU`](/docs/kcl-std/consts/std-math-TAU)
* [**std::sweep**](/docs/kcl-std/modules/std-sweep)
* [`sweep::SKETCH_PLANE`](/docs/kcl-std/consts/std-sweep-SKETCH_PLANE)
* [`sweep::TRAJECTORY`](/docs/kcl-std/consts/std-sweep-TRAJECTORY)
* [**std::turns**](/docs/kcl-std/modules/std-turns)
* [`turns::HALF_TURN`](/docs/kcl-std/consts/std-turns-HALF_TURN)
* [`turns::QUARTER_TURN`](/docs/kcl-std/consts/std-turns-QUARTER_TURN)
@ -140,12 +145,13 @@ See also the [types overview](/docs/kcl-lang/types)
* [**Primitive types**](/docs/kcl-lang/types)
* [`End`](/docs/kcl-lang/types#End)
* [`ImportedGeometry`](/docs/kcl-lang/types#ImportedGeometry)
* [`ImportedGeometry`](/docs/kcl-std/types/std-types-ImportedGeometry)
* [`Start`](/docs/kcl-lang/types#Start)
* [`TagDeclarator`](/docs/kcl-lang/types#TagDeclarator)
* [`TagIdentifier`](/docs/kcl-lang/types#TagIdentifier)
* [`any`](/docs/kcl-std/types/std-types-any)
* [`bool`](/docs/kcl-std/types/std-types-bool)
* [`fn`](/docs/kcl-std/types/std-types-fn)
* [`number`](/docs/kcl-std/types/std-types-number)
* [`string`](/docs/kcl-std/types/std-types-string)
* [`tag`](/docs/kcl-std/types/std-types-tag)

View File

@ -1,38 +0,0 @@
---
title: "legAngX"
subtitle: "Function in std::math"
excerpt: "Compute the angle of the given leg for x."
layout: manual
---
Compute the angle of the given leg for x.
```kcl
legAngX(
hypotenuse: number,
leg: number,
): number
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse | Yes |
| `leg` | [`number`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side) | Yes |
### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legAngX(hypotenuse = 5, leg = 3)
```

View File

@ -1,38 +0,0 @@
---
title: "legAngY"
subtitle: "Function in std::math"
excerpt: "Compute the angle of the given leg for y."
layout: manual
---
Compute the angle of the given leg for y.
```kcl
legAngY(
hypotenuse: number,
leg: number,
): number
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse | Yes |
| `leg` | [`number`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side) | Yes |
### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legAngY(hypotenuse = 5, leg = 3)
```

View File

@ -1,38 +0,0 @@
---
title: "legLen"
subtitle: "Function in std::math"
excerpt: "Compute the length of the given leg."
layout: manual
---
Compute the length of the given leg.
```kcl
legLen(
hypotenuse: number,
leg: number,
): number
```
### Arguments
| Name | Type | Description | Required |
|----------|------|-------------|----------|
| `hypotenuse` | [`number`](/docs/kcl-std/types/std-types-number) | The length of the triangle's hypotenuse | Yes |
| `leg` | [`number`](/docs/kcl-std/types/std-types-number) | The length of one of the triangle's legs (i.e. non-hypotenuse side) | Yes |
### Returns
[`number`](/docs/kcl-std/types/std-types-number) - A number.
### Examples
```kcl
legLen(hypotenuse = 5, leg = 3)
```

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,16 @@
---
title: "appearance"
subtitle: "Module in std"
excerpt: ""
layout: manual
---
## Functions and constants
* [`appearance::hexString`](/docs/kcl-std/functions/std-appearance-hexString)

View File

@ -12,8 +12,8 @@ Functions for manipulating arrays of values.
## Functions and constants
* [`map`](/docs/kcl-std/map)
* [`pop`](/docs/kcl-std/pop)
* [`push`](/docs/kcl-std/push)
* [`reduce`](/docs/kcl-std/reduce)
* [`map`](/docs/kcl-std/functions/std-array-map)
* [`pop`](/docs/kcl-std/functions/std-array-pop)
* [`push`](/docs/kcl-std/functions/std-array-push)
* [`reduce`](/docs/kcl-std/functions/std-array-reduce)

View File

@ -23,9 +23,9 @@ Functions for mathematical operations and some useful constants.
* [`ceil`](/docs/kcl-std/functions/std-math-ceil)
* [`cos`](/docs/kcl-std/functions/std-math-cos)
* [`floor`](/docs/kcl-std/functions/std-math-floor)
* [`legAngX`](/docs/kcl-std/legAngX)
* [`legAngY`](/docs/kcl-std/legAngY)
* [`legLen`](/docs/kcl-std/legLen)
* [`legAngX`](/docs/kcl-std/functions/std-math-legAngX)
* [`legAngY`](/docs/kcl-std/functions/std-math-legAngY)
* [`legLen`](/docs/kcl-std/functions/std-math-legLen)
* [`ln`](/docs/kcl-std/functions/std-math-ln)
* [`log`](/docs/kcl-std/functions/std-math-log)
* [`log10`](/docs/kcl-std/functions/std-math-log10)

View File

@ -30,7 +30,7 @@ This module contains functions for creating and manipulating sketches, and makin
* [`line`](/docs/kcl-std/line)
* [`loft`](/docs/kcl-std/loft)
* [`patternCircular2d`](/docs/kcl-std/patternCircular2d)
* [`patternTransform2d`](/docs/kcl-std/patternTransform2d)
* [`patternTransform2d`](/docs/kcl-std/functions/std-sketch-patternTransform2d)
* [`polygon`](/docs/kcl-std/polygon)
* [`profileStart`](/docs/kcl-std/profileStart)
* [`profileStartX`](/docs/kcl-std/profileStartX)

View File

@ -18,7 +18,7 @@ This module contains functions for modifying solids, e.g., by adding a fillet or
* [`intersect`](/docs/kcl-std/intersect)
* [`patternCircular3d`](/docs/kcl-std/patternCircular3d)
* [`patternLinear3d`](/docs/kcl-std/patternLinear3d)
* [`patternTransform`](/docs/kcl-std/patternTransform)
* [`patternTransform`](/docs/kcl-std/functions/std-solid-patternTransform)
* [`shell`](/docs/kcl-std/functions/std-solid-shell)
* [`subtract`](/docs/kcl-std/subtract)
* [`union`](/docs/kcl-std/union)

View File

@ -0,0 +1,17 @@
---
title: "sweep"
subtitle: "Module in std"
excerpt: ""
layout: manual
---
## Functions and constants
* [`sweep::SKETCH_PLANE`](/docs/kcl-std/consts/std-sweep-SKETCH_PLANE)
* [`sweep::TRAJECTORY`](/docs/kcl-std/consts/std-sweep-TRAJECTORY)

View File

@ -18,6 +18,7 @@ Types can (optionally) be used to describe a function's arguments and returned v
* [`Edge`](/docs/kcl-std/types/std-types-Edge)
* [`Face`](/docs/kcl-std/types/std-types-Face)
* [`Helix`](/docs/kcl-std/types/std-types-Helix)
* [`ImportedGeometry`](/docs/kcl-std/types/std-types-ImportedGeometry)
* [`Plane`](/docs/kcl-std/types/std-types-Plane)
* [`Point2d`](/docs/kcl-std/types/std-types-Point2d)
* [`Point3d`](/docs/kcl-std/types/std-types-Point3d)
@ -25,6 +26,7 @@ Types can (optionally) be used to describe a function's arguments and returned v
* [`Solid`](/docs/kcl-std/types/std-types-Solid)
* [`any`](/docs/kcl-std/types/std-types-any)
* [`bool`](/docs/kcl-std/types/std-types-bool)
* [`fn`](/docs/kcl-std/types/std-types-fn)
* [`number`](/docs/kcl-std/types/std-types-number)
* [`string`](/docs/kcl-std/types/std-types-string)
* [`tag`](/docs/kcl-std/types/std-types-tag)

View File

@ -11,12 +11,16 @@ Contains frequently used constants, functions for interacting with the KittyCAD
The standard library is organised into modules (listed below), but most things are always available in KCL programs.
You might also want the [KCL language reference](/docs/kcl-lang) or the [KCL guide](https://zoo.dev/docs/kcl-book/intro.html).
## Modules
* [`appearance::appearance`](/docs/kcl-std/modules/std-appearance)
* [`array`](/docs/kcl-std/modules/std-array)
* [`math`](/docs/kcl-std/modules/std-math)
* [`sketch`](/docs/kcl-std/modules/std-sketch)
* [`solid`](/docs/kcl-std/modules/std-solid)
* [`sweep::sweep`](/docs/kcl-std/modules/std-sweep)
* [`transform`](/docs/kcl-std/modules/std-transform)
* [`turns::turns`](/docs/kcl-std/modules/std-turns)
* [`types`](/docs/kcl-std/modules/std-types)
@ -35,7 +39,7 @@ The standard library is organised into modules (listed below), but most things a
* [`appearance`](/docs/kcl-std/appearance)
* [`assert`](/docs/kcl-std/assert)
* [`assertIs`](/docs/kcl-std/assertIs)
* [`clone`](/docs/kcl-std/clone)
* [`clone`](/docs/kcl-std/functions/std-clone)
* [`helix`](/docs/kcl-std/functions/std-helix)
* [`offsetPlane`](/docs/kcl-std/functions/std-offsetPlane)
* [`patternLinear2d`](/docs/kcl-std/patternLinear2d)

View File

@ -12,8 +12,8 @@ patternCircular2d(
@sketchSet: [Sketch],
instances: number,
center: Point2d,
arcDegrees: number,
rotateDuplicates: bool,
arcDegrees?: number,
rotateDuplicates?: bool,
useOriginal?: bool,
): [Sketch]
```
@ -27,8 +27,8 @@ patternCircular2d(
| `sketchSet` | [`[Sketch]`](/docs/kcl-std/types/std-types-Sketch) | Which sketch(es) to pattern | Yes |
| `instances` | [`number`](/docs/kcl-std/types/std-types-number) | The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect. | Yes |
| `center` | [`Point2d`](/docs/kcl-std/types/std-types-Point2d) | The center about which to make the pattern. This is a 2D vector. | Yes |
| `arcDegrees` | [`number`](/docs/kcl-std/types/std-types-number) | The arc angle (in degrees) to place the repetitions. Must be greater than 0. | Yes |
| `rotateDuplicates` | [`bool`](/docs/kcl-std/types/std-types-bool) | Whether or not to rotate the duplicates as they are copied. | Yes |
| `arcDegrees` | [`number`](/docs/kcl-std/types/std-types-number) | The arc angle (in degrees) to place the repetitions. Must be greater than 0. Defaults to 360. | No |
| `rotateDuplicates` | [`bool`](/docs/kcl-std/types/std-types-bool) | Whether or not to rotate the duplicates as they are copied. Defaults to true. | No |
| `useOriginal` | [`bool`](/docs/kcl-std/types/std-types-bool) | If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false. | No |
### Returns

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 it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,13 @@
---
title: "ImportedGeometry"
subtitle: "Type in std::types"
excerpt: "Represents geometry which is defined using some other CAD system and imported into KCL."
layout: manual
---
Represents geometry which is defined using some other CAD system and imported into KCL.

View File

@ -7,8 +7,25 @@ layout: manual
An abstract plane.
A plane has a position and orientation in space defined by its origin and axes. A plane can be used
to sketch on.
A plane has a position and orientation in space defined by its origin and axes. A plane is abstract
in the sense that it is not part of the objects being drawn. A plane can be used to sketch on.
A plane can be created in several ways:
- you can use one of the default planes, e.g., `XY`.
- you can use `offsetPlane` to create a new plane offset from an existing one, e.g., `offsetPlane(XY, offset = 150)`.
- you can use negation to create a plane from an existing one which is identical but has an opposite normal
e.g., `-XY`.
- you can define an entirely custom plane, e.g.,
```js
myXY = {
origin = { x = 0, y = 0, z = 0 },
xAxis = { x = 1, y = 0, z = 0 },
yAxis = { x = 0, y = 1, z = 0 },
}
```
Any object with appropriate `origin`, `xAxis`, and `yAxis` fields can be used as a plane.

View File

@ -0,0 +1,13 @@
---
title: "fn"
subtitle: "Type in std::types"
excerpt: "The type of any function in KCL."
layout: manual
---
The type of any function in KCL.

View File

@ -78,11 +78,10 @@ extrude001 = extrude(sketch001, length = 5)`
// Delete a character to break the KCL
await editor.openPane()
await editor.scrollToText('bracketLeg1Sketch, length = thickness)')
await page
.getByText('extrude(bracketLeg1Sketch, length = thickness)')
.click()
await page.keyboard.press('Backspace')
await editor.scrollToText('extrude(%, length = width)')
await page.getByText('extrude(%, length = width)').click()
await page.keyboard.press(')')
// Ensure that a badge appears on the button
await expect(codePaneButtonHolder).toContainText('notification')
@ -99,16 +98,11 @@ extrude001 = extrude(sketch001, length = 5)`
await page.waitForTimeout(500)
// Ensure that a badge appears on the button
await expect(codePaneButtonHolder).toContainText('notification')
// Ensure we have no errors in the gutter.
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// Open the code pane
await editor.openPane()
// Go to our problematic code again (missing closing paren!)
await editor.scrollToText('extrude(bracketLeg1Sketch, length = thickness')
// Go to our problematic code again
await editor.scrollToText('extrude(%, length = w')
// Ensure that a badge appears on the button
await expect(codePaneButtonHolder).toContainText('notification')
@ -134,8 +128,6 @@ extrude001 = extrude(sketch001, length = 5)`
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
await page.waitForTimeout(1000)
// Ensure badge is present
const codePaneButtonHolder = page.locator('#code-button-holder')
await expect(codePaneButtonHolder).toContainText('notification', {
@ -158,10 +150,14 @@ extrude001 = extrude(sketch001, length = 5)`
await expect(
page
.getByText(
'Modeling command failed: [ApiError { error_code: InternalEngine, message: "Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis" }]'
'Solid3D revolve failed: sketch profile must lie entirely on one side of the revolution axis'
)
.first()
).toBeVisible()
// Make sure ApiError is not on the page.
// This ensures we didn't nest the json
await expect(page.getByText('ApiError')).not.toBeVisible()
})
test('When error is not in view WITH LINTS you can click the badge to scroll to it', async ({
@ -179,7 +175,7 @@ extrude001 = extrude(sketch001, length = 5)`
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
await scene.settled(cmdBar)
// await scene.settled(cmdBar)
// Ensure badge is present
const codePaneButtonHolder = page.locator('#code-button-holder')
@ -233,6 +229,48 @@ extrude001 = extrude(sketch001, length = 5)`
.first()
).toBeVisible()
})
test('KCL errors with functions show hints for the entire backtrace', async ({
page,
homePage,
scene,
cmdBar,
editor,
toolbar,
}) => {
await homePage.goToModelingScene()
await scene.settled(cmdBar)
const code = `fn check(@x) {
return assert(x, isGreaterThan = 0)
}
fn middle(@x) {
return check(x)
}
middle(1)
middle(0)
`
await test.step('Set the code with a KCL error', async () => {
await toolbar.openPane('code')
await editor.replaceCode('', code)
})
// This shows all the diagnostics in a way that doesn't require the mouse
// pointer hovering over a coordinate, which would be brittle.
await test.step('Open CodeMirror diagnostics list', async () => {
// Ensure keyboard focus is in the editor.
await page.getByText('fn check(').click()
await page.keyboard.press('ControlOrMeta+Shift+M')
})
await expect(
page.getByText(`assert failed: Expected 0 to be greater than 0 but it wasn't
check()
middle()`)
).toBeVisible()
// There should be one hint inside middle() and one at the top level.
await expect(page.getByText('Part of the error backtrace')).toHaveCount(2)
})
})
test(

View File

@ -36,7 +36,10 @@ test.describe('Command bar tests', () => {
await u.closeDebugPanel()
// Click the line of code for xLine.
await page.getByText(`close()`).click() // TODO remove this and reinstate // await topHorzSegmentClick()
await page.getByText(`startProfile(at = [-10, -10])`).click()
// Wait for the selection to register (TODO: we need a definitive way to wait for this)
await page.waitForTimeout(200)
await toolbar.extrudeButton.click()
await cmdBar.expectState({
@ -45,10 +48,10 @@ test.describe('Command bar tests', () => {
currentArgKey: 'sketches',
currentArgValue: '',
headerArguments: {
Sketches: '',
Profiles: '',
Length: '',
},
highlightedHeaderArg: 'sketches',
highlightedHeaderArg: 'Profiles',
})
await cmdBar.progressCmdBar()
await cmdBar.progressCmdBar()
@ -56,7 +59,7 @@ test.describe('Command bar tests', () => {
stage: 'review',
commandName: 'Extrude',
headerArguments: {
Sketches: '1 segment',
Profiles: '1 profile',
Length: '5',
},
})
@ -286,7 +289,7 @@ test.describe('Command bar tests', () => {
await cmdBar.cmdOptions.getByText('Extrude').click()
// Assert that we're on the selection step
await expect(page.getByRole('button', { name: 'sketches' })).toBeDisabled()
await expect(page.getByRole('button', { name: 'Profiles' })).toBeDisabled()
// Select a face
await page.mouse.move(700, 200)
await page.mouse.click(700, 200)
@ -399,7 +402,6 @@ test.describe('Command bar tests', () => {
sortBy: 'last-modified-desc',
})
await page.goto(page.url() + targetURL)
expect(page.url()).toContain(targetURL)
})
await test.step(`Submit the command`, async () => {
@ -410,7 +412,7 @@ test.describe('Command bar tests', () => {
currentArgValue: '',
headerArguments: {
Method: '',
Name: 'test',
Name: 'main.kcl',
Code: '1 line',
},
highlightedHeaderArg: 'method',
@ -421,7 +423,7 @@ test.describe('Command bar tests', () => {
commandName: 'Import file from URL',
headerArguments: {
Method: 'New project',
Name: 'test',
Name: 'main.kcl',
Code: '1 line',
},
})
@ -463,7 +465,6 @@ test.describe('Command bar tests', () => {
sortBy: 'last-modified-desc',
})
await page.goto(page.url() + targetURL)
expect(page.url()).toContain(targetURL)
})
await test.step(`Submit the command`, async () => {
@ -474,7 +475,7 @@ test.describe('Command bar tests', () => {
currentArgValue: '',
headerArguments: {
Method: '',
Name: 'test',
Name: 'main.kcl',
Code: '1 line',
},
highlightedHeaderArg: 'method',
@ -487,7 +488,7 @@ test.describe('Command bar tests', () => {
currentArgValue: '',
headerArguments: {
Method: 'Existing project',
Name: 'test',
Name: 'main.kcl',
ProjectName: '',
Code: '1 line',
},
@ -500,7 +501,7 @@ test.describe('Command bar tests', () => {
headerArguments: {
Method: 'Existing project',
ProjectName: 'testProjectDir',
Name: 'test',
Name: 'main.kcl',
Code: '1 line',
},
})
@ -510,7 +511,7 @@ test.describe('Command bar tests', () => {
await test.step(`Ensure we created the project and are in the modeling scene`, async () => {
await editor.expectEditor.toContain('extrusionDistance = 12')
await toolbar.openPane('files')
await toolbar.expectFileTreeState(['main.kcl', 'test.kcl'])
await toolbar.expectFileTreeState(['main-1.kcl', 'main.kcl'])
})
})
@ -661,4 +662,56 @@ c = 3 + a`
`a = 5b = a * amyParameter001 = ${newValue}c = 3 + a`
)
})
test('Command palette can be opened via query parameter', async ({
page,
homePage,
cmdBar,
}) => {
await page.goto(`${page.url()}/?cmd=app.theme&groupId=settings`)
await homePage.expectState({
projectCards: [],
sortBy: 'last-modified-desc',
})
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Settings · app · theme',
currentArgKey: 'value',
currentArgValue: '',
headerArguments: {
Level: 'user',
Value: '',
},
highlightedHeaderArg: 'value',
})
})
test('Text-to-CAD command can be closed with escape while in prompt', async ({
page,
homePage,
cmdBar,
}) => {
await homePage.expectState({
projectCards: [],
sortBy: 'last-modified-desc',
})
await homePage.textToCadBtn.click()
await cmdBar.expectState({
stage: 'arguments',
commandName: 'Text-to-CAD Create',
currentArgKey: 'prompt',
currentArgValue: '',
headerArguments: {
Method: 'New project',
NewProjectName: 'untitled',
Prompt: '',
},
highlightedHeaderArg: 'prompt',
})
await page.keyboard.press('Escape')
await cmdBar.toBeClosed()
await cmdBar.expectState({
stage: 'commandBarClosed',
})
})
})

View File

@ -58,12 +58,6 @@ test(
await expect(submitButton).toBeVisible()
await page.keyboard.press('Enter')
// Look out for the toast message
const exportingToastMessage = page.getByText(`Exporting...`)
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
await expect(exportingToastMessage).toBeVisible()
await expect(alreadyExportingToastMessage).not.toBeVisible()
// Expect it to succeed
const errorToastMessage = page.getByText(`Error while exporting`)
const engineErrorToastMessage = page.getByText(`Nothing to export`)
@ -71,8 +65,9 @@ test(
await expect(engineErrorToastMessage).not.toBeVisible()
const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible()
await expect(exportingToastMessage).not.toBeVisible()
await page.waitForTimeout(1_000)
const count = await successToastMessage.count()
await expect(count).toBeGreaterThanOrEqual(1)
// Check for the exported file
const firstFileFullPath = path.resolve(
@ -141,7 +136,9 @@ test(
await expect(engineErrorToastMessage).not.toBeVisible()
const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible()
await page.waitForTimeout(1_000)
const count = await successToastMessage.count()
await expect(count).toBeGreaterThanOrEqual(1)
await expect(exportingToastMessage).not.toBeVisible()
// Check for the exported file=

View File

@ -1001,7 +1001,7 @@ a1 = startSketchOn(offsetPlane(XY, offset = 10))
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfile(%, at = [3.14, 12])
|> startProfile(%, at = [0, 12])
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
)
@ -1076,7 +1076,7 @@ sketch001 = startSketchOn(XZ)
await expect(page.locator('.cm-content')).toHaveText(
`@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(XZ)
|> startProfile(%, at = [3.14, 12])
|> startProfile(%, at = [0, 12])
|> xLine(%, length = 5) // lin`.replaceAll('\n', '')
)
})
@ -1131,6 +1131,8 @@ sketch001 = startSketchOn(XZ)
await page.waitForTimeout(100)
await page.getByText('startProfile(at = [4.61, -14.01])').click()
// Wait for the selection to register (TODO: we need a definitive way to wait for this)
await page.waitForTimeout(200)
await toolbar.extrudeButton.click()
await cmdBar.progressCmdBar()
await cmdBar.expectState({
@ -1138,7 +1140,7 @@ sketch001 = startSketchOn(XZ)
currentArgKey: 'length',
currentArgValue: '5',
headerArguments: {
Sketches: '1 face',
Profiles: '1 profile',
Length: '',
},
highlightedHeaderArg: 'length',
@ -1148,7 +1150,7 @@ sketch001 = startSketchOn(XZ)
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Sketches: '1 face',
Profiles: '1 profile',
Length: '5',
},
commandName: 'Extrude',
@ -1533,7 +1535,6 @@ sketch001 = startSketchOn(XZ)
await homePage.goToModelingScene()
await scene.connectionEstablished()
await scene.settled(cmdBar)
await scene.expectPixelColor(
TEST_COLORS.DARK_MODE_BKGD,
@ -1589,4 +1590,38 @@ sketch001 = startSketchOn(XZ)
await expect(page.getByTestId('center-rectangle')).toBeVisible()
})
})
test('syntax errors still show when reopening KCL pane', async ({
page,
homePage,
scene,
cmdBar,
}) => {
const u = await getUtils(page)
await page.setBodyDimensions({ width: 1200, height: 500 })
await homePage.goToModelingScene()
// Wait for connection, this is especially important for this test, because safeParse is invoked when
// connection is established which would interfere with the test if it happened during later steps.
await scene.connectionEstablished()
await scene.settled(cmdBar)
// Code with no error
await u.codeLocator.fill(`x = 7`)
await page.waitForTimeout(200) // allow some time for the error to show potentially
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0)
// Code with error
await u.codeLocator.fill(`x 7`)
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(1)
// Close and reopen KCL code panel
await u.closeKclCodePanel()
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(0) // error disappears on close
await u.openKclCodePanel()
// Verify error is still visible
await expect(page.locator('.cm-lint-marker-error')).toHaveCount(1)
})
})

View File

@ -238,6 +238,26 @@ test.describe('when using the file tree to', () => {
}
)
test(
`create new folders and that doesn't trigger a navigation`,
{ tag: ['@electron', '@macos', '@windows'] },
async ({ page, homePage, scene, toolbar, cmdBar }) => {
await homePage.goToModelingScene()
await scene.settled(cmdBar)
await toolbar.openPane('files')
const { createNewFolder } = await getUtils(page, test)
await createNewFolder('folder')
await createNewFolder('folder.kcl')
await test.step(`Postcondition: folders are created and we didn't navigate`, async () => {
await toolbar.expectFileTreeState(['folder', 'folder.kcl', 'main.kcl'])
await expect(toolbar.fileName).toHaveText('main.kcl')
})
}
)
test(
'deleting all files recreates a default main.kcl with no code',
{ tag: '@electron' },

View File

@ -105,14 +105,19 @@ export class CmdBarFixture {
expectState = async (expected: CmdBarSerialised) => {
return expect.poll(() => this._serialiseCmdBar()).toEqual(expected)
}
/** The method will use buttons OR press enter randomly to progress the cmdbar,
* this could have unexpected results depending on what's focused
*
* TODO: This method assumes the user has a valid input to the current stage,
/**
* This method is used to progress the command bar to the next step, defaulting to clicking the next button.
* Optionally, with the `shouldUseKeyboard` parameter, it will hit `Enter` to progress.
* * TODO: This method assumes the user has a valid input to the current stage,
* and assumes we are past the `pickCommand` step.
*/
progressCmdBar = async (shouldFuzzProgressMethod = true) => {
progressCmdBar = async (shouldUseKeyboard = false) => {
await this.page.waitForTimeout(2000)
if (shouldUseKeyboard) {
await this.page.keyboard.press('Enter')
return
}
const arrowButton = this.page.getByRole('button', {
name: 'arrow right Continue',
})
@ -146,15 +151,19 @@ export class CmdBarFixture {
await this.cmdBarOpenBtn.click()
await expect(this.page.getByPlaceholder('Search commands')).toBeVisible()
if (selectCmd === 'promptToEdit') {
const promptEditCommand = this.page.getByText(
'Use Zoo AI to edit your parts and code.'
)
const promptEditCommand = this.selectOption({ name: 'Text-to-CAD Edit' })
await expect(promptEditCommand.first()).toBeVisible()
await promptEditCommand.first().scrollIntoViewIfNeeded()
await promptEditCommand.first().click()
}
}
closeCmdBar = async () => {
const cmdBarCloseBtn = this.page.getByTestId('command-bar-close-button')
await cmdBarCloseBtn.click()
await expect(this.cmdBarElement).not.toBeVisible()
}
get cmdSearchInput() {
return this.page.getByTestId('cmd-bar-search')
}
@ -298,4 +307,32 @@ export class CmdBarFixture {
`Monitoring text-to-cad API requests. Output will be saved to: ${outputPath}`
)
}
async toBeOpened() {
// Check that the command bar is opened
await expect(this.cmdBarElement).toBeVisible({ timeout: 10_000 })
}
async toBeClosed() {
// Check that the command bar is closed
await expect(this.cmdBarElement).not.toBeVisible({ timeout: 10_000 })
}
async expectArgValue(value: string) {
// Check the placeholder project name exists
const actualArgument = await this.cmdBarElement
.getByTestId('cmd-bar-arg-value')
.inputValue()
const expectedArgument = value
expect(actualArgument).toBe(expectedArgument)
}
async expectCommandName(value: string) {
// Check the placeholder project name exists
const actual = await this.cmdBarElement
.getByTestId('command-name')
.textContent()
const expected = value
expect(actual).toBe(expected)
}
}

View File

@ -24,7 +24,9 @@ export class HomePageFixture {
projectTextName!: Locator
sortByDateBtn!: Locator
sortByNameBtn!: Locator
appHeader!: Locator
tutorialBtn!: Locator
textToCadBtn!: Locator
constructor(page: Page) {
this.page = page
@ -44,7 +46,9 @@ export class HomePageFixture {
this.sortByDateBtn = this.page.getByTestId('home-sort-by-modified')
this.sortByNameBtn = this.page.getByTestId('home-sort-by-name')
this.appHeader = this.page.getByTestId('app-header')
this.tutorialBtn = this.page.getByTestId('home-tutorial-button')
this.textToCadBtn = this.page.getByTestId('home-text-to-cad')
}
private _serialiseSortBy = async (): Promise<
@ -119,10 +123,19 @@ export class HomePageFixture {
await projectCard.click()
}
goToModelingScene = async (name: string = 'testDefault') => {
/** Returns the project name in case caller has used the default and needs it */
goToModelingScene = async (name = 'testDefault') => {
// On web this is a no-op. There is no project view.
if (process.env.PLATFORM === 'web') return
if (process.env.PLATFORM === 'web') return ''
await this.createAndGoToProject(name)
return name
}
isNativeFileMenuCreated = async () => {
await expect(this.appHeader).toHaveAttribute(
'data-native-file-menu',
'true'
)
}
}

View File

@ -46,6 +46,7 @@ export class SceneFixture {
public networkToggleConnected!: Locator
public engineConnectionsSpinner!: Locator
public startEditSketchBtn!: Locator
public appHeader!: Locator
constructor(page: Page) {
this.page = page
@ -57,6 +58,7 @@ export class SceneFixture {
this.startEditSketchBtn = page
.getByRole('button', { name: 'Start Sketch' })
.or(page.getByRole('button', { name: 'Edit Sketch' }))
this.appHeader = this.page.getByTestId('app-header')
}
private _serialiseScene = async (): Promise<SceneSerialised> => {
const camera = await this.getCameraInfo()
@ -280,6 +282,13 @@ export class SceneFixture {
await expect(buttonToTest).toBeVisible()
await buttonToTest.click()
}
isNativeFileMenuCreated = async () => {
await expect(this.appHeader).toHaveAttribute(
'data-native-file-menu',
'true'
)
}
}
function isColourArray(

View File

@ -61,6 +61,7 @@ class MyAPIReporter implements Reporter {
const payload = {
// Required information
project: 'https://github.com/KittyCAD/modeling-app',
suite: process.env.CI_SUITE || 'e2e',
branch: process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || '',
commit: process.env.CI_COMMIT_SHA || process.env.GITHUB_SHA || '',
test: test.titlePath().slice(2).join(' '),

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,6 @@ test.describe('Onboarding tests', () => {
homePage,
toolbar,
editor,
scene,
tronApp,
}) => {
if (!tronApp) {
@ -62,7 +61,6 @@ test.describe('Onboarding tests', () => {
await editor.expectEditor.toContain('@settings(defaultLengthUnit = in)', {
shouldNormalise: true,
})
await scene.connectionEstablished()
})
await test.step('Go home and verify we still see the tutorial button, then begin it.', async () => {
@ -132,9 +130,7 @@ test.describe('Onboarding tests', () => {
})
await test.step('Dismiss the onboarding', async () => {
await postDismissToast.waitFor({ state: 'hidden' })
await page.keyboard.press('Escape')
await expect(postDismissToast).toBeVisible()
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
await expect.poll(() => page.url()).not.toContain('/onboarding')
})
@ -162,13 +158,10 @@ test.describe('Onboarding tests', () => {
await test.step('Gets to the onboarding start', async () => {
await expect(toolbar.projectName).toContainText('tutorial-project')
await expect(tutorialWelcomeHeading).toBeVisible()
await scene.connectionEstablished()
})
await test.step('Dismiss the onboarding', async () => {
await postDismissToast.waitFor({ state: 'hidden' })
await page.keyboard.press('Escape')
await expect(postDismissToast).toBeVisible()
await expect(page.getByTestId('onboarding-content')).not.toBeVisible()
await expect.poll(() => page.url()).not.toContain('/onboarding')
})

View File

@ -70,22 +70,28 @@ test.describe('Point-and-click assemblies tests', () => {
await test.step('Setup parts and expect empty assembly scene', async () => {
const projectName = 'assembly'
await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, projectName)
await fsp.mkdir(bracketDir, { recursive: true })
const projDir = path.join(dir, projectName)
const nestedProjDir = path.join(dir, projectName, 'nested', 'twice')
await fsp.mkdir(projDir, { recursive: true })
await fsp.mkdir(nestedProjDir, { recursive: true })
await Promise.all([
fsp.copyFile(
executorInputPath('cylinder.kcl'),
path.join(bracketDir, 'cylinder.kcl')
path.join(projDir, 'cylinder.kcl')
),
fsp.copyFile(
executorInputPath('cylinder.kcl'),
path.join(nestedProjDir, 'main.kcl')
),
fsp.copyFile(
executorInputPath('e2e-can-sketch-on-chamfer.kcl'),
path.join(bracketDir, 'bracket.kcl')
path.join(projDir, 'bracket.kcl')
),
fsp.copyFile(
testsInputPath('cube.step'),
path.join(bracketDir, 'cube.step')
path.join(projDir, 'cube.step')
),
fsp.writeFile(path.join(bracketDir, 'main.kcl'), ''),
fsp.writeFile(path.join(projDir, 'main.kcl'), ''),
])
})
await page.setBodyDimensions({ width: 1000, height: 500 })
@ -167,6 +173,25 @@ test.describe('Point-and-click assemblies tests', () => {
await expect(
page.getByText('This file is already imported')
).toBeVisible()
await cmdBar.closeCmdBar()
})
await test.step('Insert a nested kcl part', async () => {
await insertPartIntoAssembly(
'nested/twice/main.kcl',
'main',
toolbar,
cmdBar,
page
)
await toolbar.openPane('code')
await page.waitForTimeout(10000)
await editor.expectEditor.toContain(
`
import "nested/twice/main.kcl" as main
`,
{ shouldNormalise: true }
)
})
}
)

View File

@ -78,8 +78,8 @@ test.describe('Point-and-click tests', () => {
stage: 'arguments',
currentArgKey: 'sketches',
currentArgValue: '',
headerArguments: { Sketches: '', Length: '' },
highlightedHeaderArg: 'sketches',
headerArguments: { Profiles: '', Length: '' },
highlightedHeaderArg: 'Profiles',
commandName: 'Extrude',
})
await cmdBar.progressCmdBar()
@ -87,7 +87,7 @@ test.describe('Point-and-click tests', () => {
stage: 'arguments',
currentArgKey: 'length',
currentArgValue: '5',
headerArguments: { Sketches: '1 face', Length: '' },
headerArguments: { Profiles: '1 profile', Length: '' },
highlightedHeaderArg: 'length',
commandName: 'Extrude',
})
@ -98,7 +98,7 @@ test.describe('Point-and-click tests', () => {
await cmdBar.expectState({
stage: 'review',
headerArguments: { Sketches: '1 face', Length: '5' },
headerArguments: { Profiles: '1 profile', Length: '5' },
commandName: 'Extrude',
})
await cmdBar.progressCmdBar()
@ -1634,15 +1634,15 @@ sketch002 = startSketchOn(plane001)
stage: 'arguments',
currentArgKey: 'sketches',
currentArgValue: '',
headerArguments: { Sketches: '' },
highlightedHeaderArg: 'sketches',
headerArguments: { Profiles: '' },
highlightedHeaderArg: 'Profiles',
commandName: 'Loft',
})
await selectSketches()
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: { Sketches: '2 faces' },
headerArguments: { Profiles: '2 profiles' },
commandName: 'Loft',
})
await cmdBar.submit()
@ -1658,14 +1658,14 @@ sketch002 = startSketchOn(plane001)
stage: 'arguments',
currentArgKey: 'sketches',
currentArgValue: '',
headerArguments: { Sketches: '' },
highlightedHeaderArg: 'sketches',
headerArguments: { Profiles: '' },
highlightedHeaderArg: 'Profiles',
commandName: 'Loft',
})
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'review',
headerArguments: { Sketches: '2 faces' },
headerArguments: { Profiles: '2 profiles' },
commandName: 'Loft',
})
await cmdBar.submit()
@ -1830,10 +1830,10 @@ sketch002 = startSketchOn(XZ)
currentArgValue: '',
headerArguments: {
Sectional: '',
Sketches: '',
Profiles: '',
Path: '',
},
highlightedHeaderArg: 'sketches',
highlightedHeaderArg: 'Profiles',
stage: 'arguments',
})
await clickOnSketch1()
@ -1844,7 +1844,7 @@ sketch002 = startSketchOn(XZ)
currentArgValue: '',
headerArguments: {
Sectional: '',
Sketches: '1 face',
Profiles: '1 profile',
Path: '',
},
highlightedHeaderArg: 'path',
@ -1857,7 +1857,7 @@ sketch002 = startSketchOn(XZ)
currentArgValue: '',
headerArguments: {
Sectional: '',
Sketches: '1 face',
Profiles: '1 profile',
Path: '',
},
highlightedHeaderArg: 'path',
@ -1867,13 +1867,17 @@ sketch002 = startSketchOn(XZ)
await cmdBar.expectState({
commandName: 'Sweep',
headerArguments: {
Sketches: '1 face',
Profiles: '1 profile',
Path: '1 segment',
Sectional: '',
},
stage: 'review',
})
await cmdBar.progressCmdBar()
// Confirm we can submit from the review step with just `Enter`
await cmdBar.progressCmdBar(true)
await cmdBar.expectState({
stage: 'commandBarClosed',
})
})
await test.step(`Confirm code is added to the editor, scene has changed`, async () => {
@ -1931,63 +1935,51 @@ sketch002 = startSketchOn(XZ)
})
})
test(`Sweep point-and-click failing validation`, async ({
test(`Sweep point-and-click helix`, async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
}) => {
const initialCode = `@settings(defaultLengthUnit = in)
sketch001 = startSketchOn(YZ)
|> circle(
center = [0, 0],
radius = 500
)
sketch002 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> xLine(length = -500)
|> line(endAbsolute = [-2000, 500])
`
const circleCode = `circle(sketch001, center = [0, -1], radius = .1)`
const initialCode = `helix001 = helix(
axis = X,
radius = 1,
length = 10,
revolutions = 10,
angleStart = 0,
ccw = false,
)
sketch001 = startSketchOn(XZ)
profile001 = ${circleCode}`
const sweepDeclaration = 'sweep001 = sweep(profile001, path = helix001)'
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
}, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.settled(cmdBar)
// One dumb hardcoded screen pixel value
const testPoint = { x: 700, y: 250 }
const [clickOnSketch1] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
const [clickOnSketch2] = scene.makeMouseHelpers(
testPoint.x - 50,
testPoint.y
)
await test.step(`Look for sketch001`, async () => {
await toolbar.closePane('code')
await scene.expectPixelColor([53, 53, 53], testPoint, 15)
})
await test.step(`Go through the command bar flow and fail validation with a toast`, async () => {
await test.step(`Add sweep through the command bar flow`, async () => {
await toolbar.openPane('feature-tree')
await toolbar.sweepButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({
commandName: 'Sweep',
currentArgKey: 'sketches',
currentArgValue: '',
headerArguments: {
Sectional: '',
Sketches: '',
Profiles: '',
Path: '',
},
highlightedHeaderArg: 'sketches',
highlightedHeaderArg: 'Profiles',
stage: 'arguments',
})
await clickOnSketch1()
await editor.scrollToText(circleCode)
await page.getByText(circleCode).click()
await cmdBar.progressCmdBar()
await cmdBar.expectState({
commandName: 'Sweep',
@ -1995,17 +1987,45 @@ sketch002 = startSketchOn(XZ)
currentArgValue: '',
headerArguments: {
Sectional: '',
Sketches: '1 face',
Profiles: '1 profile',
Path: '',
},
highlightedHeaderArg: 'path',
stage: 'arguments',
})
const helix = await toolbar.getFeatureTreeOperation('Helix', 0)
await helix.click()
await cmdBar.expectState({
commandName: 'Sweep',
currentArgKey: 'path',
currentArgValue: '',
headerArguments: {
Sectional: '',
Profiles: '1 profile',
Path: '',
},
highlightedHeaderArg: 'path',
stage: 'arguments',
})
await clickOnSketch2()
await cmdBar.progressCmdBar()
await expect(
page.getByText('Unable to sweep with the current selection. Reason:')
).toBeVisible()
await cmdBar.expectState({
commandName: 'Sweep',
headerArguments: {
Profiles: '1 profile',
Path: '1 helix',
Sectional: '',
},
stage: 'review',
})
await cmdBar.progressCmdBar(true)
await editor.expectEditor.toContain(sweepDeclaration)
})
await test.step('Delete sweep via feature tree selection', async () => {
const sweep = await toolbar.getFeatureTreeOperation('Sweep', 0)
await sweep.click()
await page.keyboard.press('Delete')
await editor.expectEditor.not.toContain(sweepDeclaration)
})
})
@ -3627,67 +3647,6 @@ profile001 = startProfile(sketch001, at = [-20, 20])
})
})
test(`Shell dry-run validation rejects sweeps`, async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
}) => {
const initialCode = `sketch001 = startSketchOn(YZ)
|> circle(
center = [0, 0],
radius = 500
)
sketch002 = startSketchOn(XZ)
|> startProfile(at = [0, 0])
|> xLine(length = -2000)
sweep001 = sweep(sketch001, path = sketch002)
`
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
}, initialCode)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.settled(cmdBar)
// One dumb hardcoded screen pixel value
const testPoint = { x: 500, y: 250 }
const [clickOnSweep] = scene.makeMouseHelpers(testPoint.x, testPoint.y)
await test.step(`Confirm sweep exists`, async () => {
await toolbar.closePane('code')
await scene.expectPixelColor([231, 231, 231], testPoint, 15)
})
await test.step(`Go through the Shell flow and fail validation with a toast`, async () => {
await toolbar.shellButton.click()
await expect
.poll(() => page.getByText('Please select one').count())
.toBe(1)
await cmdBar.expectState({
stage: 'arguments',
currentArgKey: 'selection',
currentArgValue: '',
headerArguments: {
Selection: '',
Thickness: '',
},
highlightedHeaderArg: 'selection',
commandName: 'Shell',
})
await clickOnSweep()
await page.waitForTimeout(500)
await cmdBar.progressCmdBar()
await expect(
page.getByText('Unable to shell with the current selection. Reason:')
).toBeVisible()
await page.waitForTimeout(1000)
})
})
test.describe('Revolve point and click workflows', () => {
test('Base case workflow, auto spam continue in command bar', async ({
context,
@ -3736,7 +3695,7 @@ tag=$rectangleSegmentC002,
await scene.settled(cmdBar)
// select line of code
const codeToSelection = `segAng(rectangleSegmentA002) - 90,`
const codeToSelection = `startProfile(at = [-66.77, 84.81])`
// revolve
await editor.scrollToText(codeToSelection)
await page.getByText(codeToSelection).click()
@ -4679,10 +4638,10 @@ path001 = startProfile(sketch001, at = [0, 0])
currentArgKey: 'sketches',
currentArgValue: '',
headerArguments: {
Sketches: '',
Profiles: '',
Length: '',
},
highlightedHeaderArg: 'sketches',
highlightedHeaderArg: 'Profiles',
commandName: 'Extrude',
})
await cmdBar.progressCmdBar()
@ -4691,7 +4650,7 @@ path001 = startProfile(sketch001, at = [0, 0])
currentArgKey: 'length',
currentArgValue: '5',
headerArguments: {
Sketches: '2 faces',
Profiles: '2 profiles',
Length: '',
},
highlightedHeaderArg: 'length',
@ -4702,7 +4661,7 @@ path001 = startProfile(sketch001, at = [0, 0])
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Sketches: '2 faces',
Profiles: '2 profiles',
Length: '1',
},
commandName: 'Extrude',
@ -4773,11 +4732,11 @@ path001 = startProfile(sketch001, at = [0, 0])
currentArgKey: 'sketches',
currentArgValue: '',
headerArguments: {
Sketches: '',
Profiles: '',
Path: '',
Sectional: '',
},
highlightedHeaderArg: 'sketches',
highlightedHeaderArg: 'Profiles',
commandName: 'Sweep',
})
await cmdBar.progressCmdBar()
@ -4786,7 +4745,7 @@ path001 = startProfile(sketch001, at = [0, 0])
currentArgKey: 'path',
currentArgValue: '',
headerArguments: {
Sketches: '2 faces',
Profiles: '2 profiles',
Path: '',
Sectional: '',
},
@ -4799,7 +4758,7 @@ path001 = startProfile(sketch001, at = [0, 0])
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Sketches: '2 faces',
Profiles: '2 profiles',
Path: '1 segment',
Sectional: '',
},
@ -4870,11 +4829,11 @@ path001 = startProfile(sketch001, at = [0, 0])
currentArgKey: 'sketches',
currentArgValue: '',
headerArguments: {
Sketches: '',
Profiles: '',
AxisOrEdge: '',
Angle: '',
},
highlightedHeaderArg: 'sketches',
highlightedHeaderArg: 'Profiles',
commandName: 'Revolve',
})
await cmdBar.progressCmdBar()
@ -4883,7 +4842,7 @@ path001 = startProfile(sketch001, at = [0, 0])
currentArgKey: 'axisOrEdge',
currentArgValue: '',
headerArguments: {
Sketches: '2 faces',
Profiles: '2 profiles',
AxisOrEdge: '',
Angle: '',
},
@ -4899,7 +4858,7 @@ path001 = startProfile(sketch001, at = [0, 0])
currentArgKey: 'angle',
currentArgValue: '360',
headerArguments: {
Sketches: '2 faces',
Profiles: '2 profiles',
AxisOrEdge: 'Edge',
Edge: '1 segment',
Angle: '',
@ -4912,7 +4871,7 @@ path001 = startProfile(sketch001, at = [0, 0])
await cmdBar.expectState({
stage: 'review',
headerArguments: {
Sketches: '2 faces',
Profiles: '2 profiles',
AxisOrEdge: 'Edge',
Edge: '1 segment',
Angle: '180',
@ -4943,4 +4902,34 @@ path001 = startProfile(sketch001, at = [0, 0])
)
})
})
test(`Point and click codemods can't run on KCL errors`, async ({
context,
page,
homePage,
scene,
editor,
toolbar,
cmdBar,
}) => {
const badCode = `sketch001 = startSketchOn(XZ)
profile001 = circle(sketch001, center = [0, 0], radius = 1)
extrude001 = extrude(profile001 length = 1)`
await context.addInitScript((initialCode) => {
localStorage.setItem('persistCode', initialCode)
}, badCode)
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await scene.connectionEstablished()
await test.step(`Start Sketch is disabled`, async () => {
await expect(toolbar.startSketchBtn).not.toBeEnabled()
await editor.expectEditor.toContain(badCode, { shouldNormalise: true })
})
await test.step(`Helix is disabled`, async () => {
await expect(toolbar.helixButton).not.toBeEnabled()
await editor.expectEditor.toContain(badCode, { shouldNormalise: true })
})
})
})

View File

@ -11,6 +11,7 @@ import {
getPlaywrightDownloadDir,
getUtils,
isOutOfViewInScrollContainer,
runningOnWindows,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
@ -1818,7 +1819,6 @@ test(
'extrude-custom-plane.kcl',
'extrude-inside-fn-with-tags.kcl',
'fillet-and-shell.kcl',
'fillet_duplicate_tags.kcl',
'focusrite_scarlett_mounting_bracket.kcl',
'function_sketch.kcl',
'function_sketch_with_position.kcl',
@ -1826,7 +1826,6 @@ test(
'helix_defaults.kcl',
'helix_defaults_negative_extrude.kcl',
'helix_with_length.kcl',
'i_shape.kcl',
'kittycad_svg.kcl',
'lego.kcl',
'lsystem.kcl',
@ -1981,7 +1980,6 @@ test(
}
)
// Flaky
test(
'Original project name persist after onboarding',
{ tag: '@electron' },
@ -2066,3 +2064,55 @@ test(
})
}
)
test(
'import from nested directory',
{ tag: ['@electron', '@windows', '@macos'] },
async ({ scene, cmdBar, context, page }) => {
await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
const nestedDir = path.join(bracketDir, 'nested')
await fsp.mkdir(nestedDir, { recursive: true })
await fsp.copyFile(
executorInputPath('cylinder-inches.kcl'),
path.join(nestedDir, 'main.kcl')
)
await fsp.writeFile(
path.join(bracketDir, 'main.kcl'),
runningOnWindows()
? `import 'nested\\main.kcl' as thing\n\nthing`
: `import 'nested/main.kcl' as thing\n\nthing`
)
})
await page.setBodyDimensions({ width: 1200, height: 500 })
const u = await getUtils(page)
const pointOnModel = { x: 630, y: 280 }
await test.step('Opening the bracket project should load the stream', async () => {
// expect to see the text bracket
await expect(page.getByText('bracket')).toBeVisible()
await page.getByText('bracket').click()
await scene.settled(cmdBar)
await expect(
page.getByRole('button', { name: 'Start Sketch' })
).toBeEnabled({
timeout: 20_000,
})
// gray at this pixel means the stream has loaded in the most
// user way we can verify it (pixel color)
await expect
.poll(() => u.getGreatestPixDiff(pointOnModel, [125, 125, 125]), {
timeout: 10_000,
})
.toBeLessThan(15)
})
}
)

View File

@ -99,6 +99,8 @@ test.describe('edit with AI example snapshots', () => {
await test.step('fire off edit prompt', async () => {
await cmdBar.captureTextToCadRequestSnapshot(test.info())
await cmdBar.openCmdBar('promptToEdit')
await page.waitForTimeout(100)
await cmdBar.progressCmdBar()
// being specific about the color with a hex means asserting pixel color is more stable
await page
.getByTestId('cmd-bar-arg-value')

View File

@ -88,6 +88,8 @@ test.describe('Prompt-to-edit tests', () => {
await test.step('fire off edit prompt', async () => {
await cmdBar.openCmdBar('promptToEdit')
await page.waitForTimeout(100)
await cmdBar.progressCmdBar()
// being specific about the color with a hex means asserting pixel color is more stable
await page
.getByTestId('cmd-bar-arg-value')
@ -165,6 +167,8 @@ test.describe('Prompt-to-edit tests', () => {
await test.step('fire of bad prompt', async () => {
await cmdBar.openCmdBar('promptToEdit')
await page.waitForTimeout(100)
await cmdBar.progressCmdBar()
await page
.getByTestId('cmd-bar-arg-value')
.fill('ansheusha asnthuatshoeuhtaoetuhthaeu laughs in dvorak')

View File

@ -19,11 +19,12 @@ test.describe('Regression tests', () => {
context,
page,
homePage,
scene,
}) => {
// because the model has `line([0,0]..` it is valid code, but the model is invalid
// regression test for https://github.com/KittyCAD/modeling-app/issues/3251
// Since the bad model also found as issue with the artifact graph, which in tern blocked the editor diognostics
const u = await getUtils(page)
// const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
@ -40,7 +41,8 @@ test.describe('Regression tests', () => {
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await u.waitForPageLoad()
await scene.connectionEstablished()
// await u.waitForPageLoad()
// error in guter
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
@ -51,8 +53,11 @@ test.describe('Regression tests', () => {
// the close doesn't work
// when https://github.com/KittyCAD/modeling-app/issues/3268 is closed
// this test will need updating
const crypticErrorText = `ApiError`
const crypticErrorText = `Cannot close a path that is non-planar or with duplicate vertices.
Internal engine error on request`
await expect(page.getByText(crypticErrorText).first()).toBeVisible()
// Ensure we didn't nest the json.
await expect(page.getByText('ApiError')).not.toBeVisible()
})
test('user should not have to press down twice in cmdbar', async ({
page,
@ -185,8 +190,8 @@ extrude001 = extrude(sketch001, length = 50)
page.locator('.pretty-json-container >> text=myVar:"67')
).toBeVisible()
})
test('ProgramMemory can be serialised', async ({ page, homePage }) => {
const u = await getUtils(page)
test('ProgramMemory can be serialised', async ({ page, homePage, scene }) => {
// const u = await getUtils(page)
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
@ -211,11 +216,12 @@ extrude001 = extrude(sketch001, length = 50)
// Listen for all console events and push the message text to an array
page.on('console', (message) => messages.push(message.text()))
await homePage.goToModelingScene()
await u.waitForPageLoad()
// await u.waitForPageLoad()
await scene.connectionEstablished()
// wait for execution done
await u.openDebugPanel()
await u.expectCmdLog('[data-message-type="execution-done"]')
// await u.openDebugPanel()
// await u.expectCmdLog('[data-message-type="execution-done"]')
const forbiddenMessages = ['cannot serialize tagged newtype variant']
forbiddenMessages.forEach((forbiddenMessage) => {
@ -229,6 +235,7 @@ extrude001 = extrude(sketch001, length = 50)
context,
page,
homePage,
scene,
}) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -247,11 +254,10 @@ extrude001 = extrude(sketch001, length = 50)
shell(exampleSketch, faces = ['end'], thickness = 0.25)`
)
})
await homePage.goToModelingScene()
await scene.connectionEstablished()
await expect(async () => {
await homePage.goToModelingScene()
await u.waitForPageLoad()
// error in guter
await expect(page.locator('.cm-lint-marker-error')).toBeVisible({
timeout: 1_000,
@ -329,10 +335,10 @@ extrude002 = extrude(profile002, length = 150)
)
const websocketPromise = page.waitForEvent('websocket')
await toolbar.closePane('code')
await page.setBodyDimensions({ width: 1000, height: 500 })
await homePage.goToModelingScene()
await toolbar.closePane('code')
const websocket = await websocketPromise
await scene.connectionEstablished()
@ -452,12 +458,10 @@ extrude002 = extrude(profile002, length = 150)
// Click the stl.
await expect(stlOption).toBeVisible()
await page.keyboard.press('Enter')
// Click the checkbox
await expect(submitButton).toBeVisible()
await page.keyboard.press('Enter')
// Find the toast.
@ -465,11 +469,13 @@ extrude002 = extrude(profile002, length = 150)
await expect(exportingToastMessage).toBeVisible()
// Expect it to succeed.
await expect(exportingToastMessage).not.toBeVisible({ timeout: 15_000 })
await expect(exportingToastMessage).not.toBeVisible()
await expect(engineErrorToastMessage).not.toBeVisible()
const successToastMessage = page.getByText(`Exported successfully`)
await expect(successToastMessage).toBeVisible()
await page.waitForTimeout(1_000)
const count = await successToastMessage.count()
await expect(count).toBeGreaterThanOrEqual(1)
}
)
// We updated this test such that you can have multiple exports going at once.
@ -545,14 +551,15 @@ extrude002 = extrude(profile002, length = 150)
expect(alreadyExportingToastMessage).not.toBeVisible(),
])
await expect(successToastMessage).toHaveCount(2)
const count = await successToastMessage.count()
await expect(count).toBeGreaterThanOrEqual(2)
})
})
test(
`Network health indicator only appears in modeling view`,
{ tag: '@electron' },
async ({ context, page }, testInfo) => {
async ({ context, page }) => {
await context.folderSetupFn(async (dir) => {
const bracketDir = path.join(dir, 'bracket')
await fsp.mkdir(bracketDir, { recursive: true })
@ -561,9 +568,7 @@ extrude002 = extrude(profile002, length = 150)
path.join(bracketDir, 'main.kcl')
)
})
await page.setBodyDimensions({ width: 1200, height: 500 })
const u = await getUtils(page)
// Locators
const projectsHeading = page.getByRole('heading', {
@ -583,10 +588,8 @@ extrude002 = extrude(profile002, length = 150)
})
await test.step('Check the modeling view', async () => {
await expect(projectsHeading).not.toBeVisible()
await expect(networkHealthIndicator).toBeVisible()
await expect(networkHealthIndicator).toContainText('Problem')
await u.waitForPageLoad()
await expect(networkHealthIndicator).toContainText('Connected')
})
}
)
@ -841,6 +844,40 @@ washer = extrude(washerSketch, length = thicknessMax)`
await editor.expectEditor.toContain('@settings(defaultLengthUnit = yd)')
})
})
test('Exiting existing sketch without editing should not delete it', async ({
page,
editor,
homePage,
context,
toolbar,
scene,
cmdBar,
}) => {
await context.folderSetupFn(async (dir) => {
const testDir = path.join(dir, 'test')
await fsp.mkdir(testDir, { recursive: true })
await fsp.writeFile(
path.join(testDir, 'main.kcl'),
`s1 = startSketchOn(XY)
|> startProfile(at = [0, 25])
|> xLine(endAbsolute = -15 + 1.5)
s2 = startSketchOn(XY)
|> startProfile(at = [25, 0])
|> yLine(endAbsolute = -15 + 1.5)`,
'utf-8'
)
})
await homePage.openProject('test')
await scene.settled(cmdBar)
await toolbar.waitForFeatureTreeToBeBuilt()
await toolbar.editSketch(1)
await page.waitForTimeout(1000) // Just hang out for a second
await toolbar.exitSketch()
await editor.expectEditor.toContain('s2 = startSketchOn(XY)')
})
})
async function clickExportButton(page: Page) {

View File

@ -995,8 +995,8 @@ profile001 = startProfile(sketch001, at = [${roundOff(scale * 69.6)}, ${roundOff
await u.expectCmdLog('[data-message-type="execution-done"]')
await u.closeDebugPanel()
// click "line(end = [1.32, 0.38])"
await page.getByText(`line(end = [1.32, 0.38])`).click()
// click profile in code
await page.getByText(`startProfile(at = [-0.45, 0.87])`).click()
await page.waitForTimeout(100)
await expect(page.getByRole('button', { name: 'Edit Sketch' })).toBeEnabled(
{ timeout: 10_000 }
@ -1014,14 +1014,14 @@ profile001 = startProfile(sketch001, at = [${roundOff(scale * 69.6)}, ${roundOff
// click extrude
await toolbar.extrudeButton.click()
// sketch selection should already have been made. "Sketches: 1 face" only show up when the selection has been made already
// sketch selection should already have been made.
// otherwise the cmdbar would be waiting for a selection.
await cmdBar.progressCmdBar()
await cmdBar.expectState({
stage: 'arguments',
currentArgKey: 'length',
currentArgValue: '5',
headerArguments: { Sketches: '1 segment', Length: '' },
headerArguments: { Profiles: '1 profile', Length: '' },
highlightedHeaderArg: 'length',
commandName: 'Extrude',
})
@ -1365,18 +1365,18 @@ solid001 = subtract([extrude001], tools = [extrude002])
await page.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`fn in2mm = (inches) => {
`fn in2mm(@inches) {
return inches * 25.4
}
const railTop = in2mm(.748)
const railSide = in2mm(.024)
const railBaseWidth = in2mm(.612)
const railWideWidth = in2mm(.835)
const railBaseLength = in2mm(.200)
const railClampable = in2mm(.200)
railTop = in2mm(.748)
railSide = in2mm(.024)
railBaseWidth = in2mm(.612)
railWideWidth = in2mm(.835)
railBaseLength = in2mm(.200)
railClampable = in2mm(.200)
const rail = startSketchOn(XZ)
rail = startSketchOn(XZ)
|> startProfile(at = [-railTop / 2, railClampable + railBaseLength])
|> line(endAbsolute = [
railTop / 2,
@ -3496,6 +3496,69 @@ profile001 = startProfile(sketch001, at = [-102.72, 237.44])
).toBeVisible()
})
// Ensure feature tree is not showing previous file's content when switching to a file with KCL errors.
test('Feature tree shows correct sketch count per file', async ({
context,
homePage,
scene,
toolbar,
cmdBar,
page,
}) => {
const u = await getUtils(page)
// Setup project with files.
const GOOD_KCL = `sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [220.81, 253.8])
|> line(end = [132.84, -151.31])
|> line(end = [25.51, 167.15])
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()
sketch002 = startSketchOn(XZ)
profile002 = startProfile(sketch002, at = [158.35, -70.82])
|> line(end = [73.9, -152.19])
|> line(end = [85.33, 135.48])
|> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|> close()`
const ERROR_KCL = `sketch001 = startSketchOn(XZ)
profile001 = startProfile(sketch001, at = [127.56, 179.02])
|> line(end = [132.84, -112.6])
|> line(end = [85.33, 234.01])
|> line(enfd = [-137.23, -54.55])`
await context.folderSetupFn(async (dir) => {
const projectDir = path.join(dir, 'multi-file-sketch-test')
await fs.mkdir(projectDir, { recursive: true })
await Promise.all([
fs.writeFile(path.join(projectDir, 'good.kcl'), GOOD_KCL, 'utf-8'),
fs.writeFile(path.join(projectDir, 'error.kcl'), ERROR_KCL, 'utf-8'),
])
})
await page.setBodyDimensions({ width: 1000, height: 800 })
await homePage.openProject('multi-file-sketch-test')
await scene.connectionEstablished()
await u.closeDebugPanel()
await toolbar.openFeatureTreePane()
await toolbar.openPane('files')
await toolbar.openFile('good.kcl')
await expect(
toolbar.featureTreePane.getByRole('button', { name: 'Sketch' })
).toHaveCount(2)
await toolbar.openFile('error.kcl')
await expect(
toolbar.featureTreePane.getByRole('button', { name: 'Sketch' })
).toHaveCount(0)
})
test('adding a syntax error, recovers after fixing', async ({
page,
homePage,

View File

@ -1,4 +1,3 @@
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
import type { CmdBarFixture } from '@e2e/playwright/fixtures/cmdBarFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import { TEST_SETTINGS, TEST_SETTINGS_KEY } from '@e2e/playwright/storageStates'
@ -9,6 +8,7 @@ import {
settingsToToml,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test'
import { KCL_DEFAULT_LENGTH } from '@src/lib/constants'
test.beforeEach(async ({ page, context }) => {
// Make the user avatar image always 404
@ -766,7 +766,7 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
})
})
test('theme persists', async ({ page, context }) => {
test('theme persists', async ({ page, context, homePage }) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
@ -784,7 +784,7 @@ test('theme persists', async ({ page, context }) => {
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await homePage.goToModelingScene()
await page.waitForTimeout(500)
// await page.getByRole('link', { name: 'Settings Settings (tooltip)' }).click()
@ -812,7 +812,7 @@ test('theme persists', async ({ page, context }) => {
// Disconnect and reconnect to check the theme persists through a reload
// Expect the network to be down
await expect(networkToggle).toContainText('Offline')
await expect(networkToggle).toContainText('Problem')
// simulate network up
await u.emulateNetworkConditions({
@ -873,6 +873,50 @@ sweepSketch = startSketchOn(XY)
mask: lowerRightMasks(page),
})
})
test('code color goober works with single quotes', async ({
page,
context,
scene,
cmdBar,
}) => {
const u = await getUtils(page)
await context.addInitScript(async () => {
localStorage.setItem(
'persistCode',
`// Create a pipe using a sweep.
// Create a path for the sweep.
sweepPath = startSketchOn(XZ)
|> startProfile(at = [0.05, 0.05])
|> line(end = [0, 7])
|> tangentialArc(angle = 90, radius = 5)
|> line(end = [-3, 0])
|> tangentialArc(angle = -90, radius = 5)
|> line(end = [0, 7])
sweepSketch = startSketchOn(XY)
|> startProfile(at = [2, 0])
|> arc(angleStart = 0, angleEnd = 360, radius = 2)
|> sweep(path = sweepPath)
|> appearance(
color = '#bb00ff',
metalness = 90,
roughness = 90
)
`
)
})
await page.setViewportSize({ width: 1200, height: 1000 })
await u.waitForAuthSkipAppStart()
await scene.settled(cmdBar)
await expect(page, 'expect small color widget').toHaveScreenshot({
maxDiffPixels: 100,
mask: lowerRightMasks(page),
})
})
test('code color goober opening window', async ({
page,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 57 KiB

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