Compare commits

...

5 Commits

Author SHA1 Message Date
f5ee346408 Release derive-docs 0.1.13 (#2044) 2024-04-09 17:02:16 +00:00
544a7565e3 Migrate to tauri v2 (#1400)
* Fix vite build (tauri build still broken)

* Fix yarn builds with a couple of shortcuts

* Fix file creation

* Fix documentDir behavior

* Got stream with default file

* Clean up

* Clean up

* Use 'unstable'; fix devtools callsite

The API changed a bit here, which forces us to use the unstable crate
feature. The call to open devtools is also new; it's now on the
webview not window.

Signed-off-by: Paul R. Tagliamonte <paul@kittycad.io>

* Bring back read_dir_recursive from v1

* Fix dates

* More fixes, incl. conf files

* cargo fmt

* Add Updater plugin

* Fix types

* Fix isTauri detection and updater bootup

* Schemas

* Clean up

* Disable devtools

* Attempt at fixing builds

* WIP Ubuntu dep

* WIP Ubuntu dep

* WIP keys in debug

* Enable updater only on release builds

* Reenable webtools on debug

* No linux bundles

* Typo

* Attemp at fixing --bundles none

* Manual tauri debug build

* Empty commit to trigger the CI

* Fix settings

* Empty commit to trigger the CI

* Merge branch 'main' into pierremtb/issue1349

* Add allow-create perm

* tauri-driver no cap

* Empty commit to trigger the CI

* Clean up

* Clean up

* Migrate to tauri v2
Fixes #1349

* Fix fmt

* Merge branch 'main' into pierremtb/issue1349

* Force BUILD_RELEASE: true

* Bump tauri to new beta

* Merge branch 'main' into pierremtb/issue1349

* Fix linux tests

* Fix types

* Add --verbose to tauri-action

* Move --verbose to front

* Back to tauri-driver@0.1.3 and single \ for win

* Back to latest driver, and windows wip

* Disable release conf temporarily

* Rollback to 2.0.0-beta.2

* Rollback to 2.0.0-beta.1

* Move bundle to root for src-tauri/tauri.release.conf.json

* All packages to latest (add http and shell to package.json)

* Testing latest commit for tauri-action

* Remove tauri action

* Add cat

* WIP

* Update ci.yml

* Disable release conf

* Disable rust cache

* Add tauri-action back for release builds

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Update .codespellrc

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Trigger CI

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Fix type

* Clean up

* More clean up

* Fix path concatenation with join

* Attempt at fixing linux tests

* Config clean up

* Downgrade to tauri-driver@0.1.3

* Looks like tauri v2 is actually doing better with linux package names ah!

* Change Linux apt packages

* Increase wdio connectionRetryTimeout

* Revert connectionRetryTimeout and bump tauri packages

* Back to latest tauri-driver

* Disable linux e2e tests

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Trigger CI

* Clean up

* Update snapshots

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Trigger CI

* Remove @sentry/react

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Rename migrated.json to desktop.json

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Trigger CI

* Change wasm url to http on Windows

---------

Signed-off-by: Paul R. Tagliamonte <paul@kittycad.io>
Co-authored-by: Paul R. Tagliamonte <paul@kittycad.io>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
2024-04-09 08:04:36 -04:00
979046f7e6 Clean up batch code (#2041)
* Clean up batch code

* A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu)

* Remove 'flush_batch: bool' from send_modeling_cmd

It was always being set with false, and it was
bugged for true. If true was set, the cmd would
never actually be run.

* Fix derive-docs

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-04-09 00:18:35 -05:00
07ae5106b9 Update rust dep 'h2' (#2037) 2024-04-08 18:25:47 -05:00
e9ae484332 Regenerate docs (#2040)
Rebuild KCL docs
2024-04-08 22:28:54 +00:00
112 changed files with 2400 additions and 1256 deletions

View File

@ -1,3 +1,3 @@
[codespell] [codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,absolutey,atleast
skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md skip: **/target,node_modules,build,**/Cargo.lock,./docs/kcl/*.md,./src-tauri/gen/schemas

View File

@ -125,6 +125,9 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [macos-14, ubuntu-latest, windows-latest] os: [macos-14, ubuntu-latest, windows-latest]
env:
TAURI_ARGS_MACOS: ${{ matrix.os == 'macos-14' && '--target universal-apple-darwin' || '' }}
TAURI_ARGS_UBUNTU: ${{ matrix.os == 'ubuntu-latest' && '--bundles' || '' }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -144,10 +147,12 @@ jobs:
sudo apt-get update && sudo apt-get update &&
sudo apt-get install -y sudo apt-get install -y
libgtk-3-dev libgtk-3-dev
libgtksourceview-3.0-dev libayatana-appindicator3-dev
webkit2gtk-4.0
libappindicator3-dev
webkit2gtk-driver webkit2gtk-driver
libsoup-3.0-dev
libjavascriptcoregtk-4.1-dev
libwebkit2gtk-4.1-dev
at-spi2-core
xvfb xvfb
- name: Sync node version and setup cache - name: Sync node version and setup cache
@ -161,7 +166,9 @@ jobs:
- name: Setup Rust - name: Setup Rust
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
# TODO: re-enable for Windows builds, see https://github.com/tauri-apps/tauri/issues/9045
- name: Setup Rust cache - name: Setup Rust cache
if: matrix.os != 'windows-latest'
uses: swatinem/rust-cache@v2 uses: swatinem/rust-cache@v2
with: with:
workspaces: './src-tauri -> target' workspaces: './src-tauri -> target'
@ -224,14 +231,14 @@ jobs:
with: with:
includeRelease: false includeRelease: false
includeDebug: true includeDebug: true
args: ${{ matrix.os == 'macos-14' && '--target universal-apple-darwin' || '' }} args: "${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}"
- name: Build the app (release) and sign - name: Build the app (release) and sign
uses: tauri-apps/tauri-action@v0 uses: tauri-apps/tauri-action@v0
if: ${{ env.BUILD_RELEASE == 'true' }} if: ${{ env.BUILD_RELEASE == 'true' }}
env: env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
@ -240,7 +247,7 @@ jobs:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
TAURI_CONF_ARGS: "--config ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}" TAURI_CONF_ARGS: "--config ${{ matrix.os == 'windows-latest' && 'src-tauri\\tauri.release.conf.json' || 'src-tauri/tauri.release.conf.json' }}"
with: with:
args: "${{ matrix.os == 'macos-14' && '--target universal-apple-darwin' || '' }} ${{ env.TAURI_CONF_ARGS }}" args: "${{ env.TAURI_CONF_ARGS }} ${{ env.TAURI_ARGS_MACOS }} ${{ env.TAURI_ARGS_UBUNTU }}"
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
if: matrix.os != 'ubuntu-latest' if: matrix.os != 'ubuntu-latest'
@ -250,10 +257,11 @@ jobs:
with: with:
path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*" path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*"
# TODO: re-enable linux e2e tests when possible
- name: Run e2e tests (linux only) - name: Run e2e tests (linux only)
if: matrix.os == 'ubuntu-latest' if: false
run: | run: |
cargo install tauri-driver@0.1.3 cargo install tauri-driver
source .env.${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }} source .env.${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }}
export VITE_KC_API_BASE_URL export VITE_KC_API_BASE_URL
xvfb-run yarn test:e2e:tauri xvfb-run yarn test:e2e:tauri

1
.gitignore vendored
View File

@ -51,5 +51,6 @@ e2e/playwright/export-snapshots/*
## generated files ## generated files
src/**/*.typegen.ts src/**/*.typegen.ts
src-tauri/gen
src/wasm-lib/grackle/stdlib_cube_partial.json src/wasm-lib/grackle/stdlib_cube_partial.json

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -16,7 +16,12 @@
"@open-rpc/client-js": "^1.8.1", "@open-rpc/client-js": "^1.8.1",
"@react-hook/resize-observer": "^1.2.6", "@react-hook/resize-observer": "^1.2.6",
"@replit/codemirror-interact": "^6.3.0", "@replit/codemirror-interact": "^6.3.0",
"@tauri-apps/api": "^1.5.3", "@tauri-apps/api": "^2.0.0-beta.7",
"@tauri-apps/plugin-dialog": "^2.0.0-beta.2",
"@tauri-apps/plugin-fs": "^2.0.0-beta.2",
"@tauri-apps/plugin-http": "^2.0.0-beta.2",
"@tauri-apps/plugin-os": "^2.0.0-beta.2",
"@tauri-apps/plugin-shell": "^2.0.0-beta.2",
"@testing-library/jest-dom": "^5.14.1", "@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^14.0.0", "@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.5.2", "@testing-library/user-event": "^14.5.2",
@ -48,7 +53,6 @@
"react-router-dom": "^6.22.3", "react-router-dom": "^6.22.3",
"sketch-helpers": "^0.0.4", "sketch-helpers": "^0.0.4",
"swr": "^2.2.2", "swr": "^2.2.2",
"tauri-plugin-fs-extra-api": "https://github.com/tauri-apps/tauri-plugin-fs-extra#v1",
"three": "^0.160.0", "three": "^0.160.0",
"toml": "^3.0.0", "toml": "^3.0.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
@ -86,7 +90,7 @@
"remove-importmeta": "sed -i 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\"; sed -i '' 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\" || echo \"sed for both mac and linux\"", "remove-importmeta": "sed -i 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\"; sed -i '' 's/import.meta.url/window.location.origin/g' \"./src/wasm-lib/pkg/wasm_lib.js\" || echo \"sed for both mac and linux\"",
"wasm-prep": "rm -rf src/wasm-lib/pkg && mkdir src/wasm-lib/pkg && rm -rf src/wasm-lib/kcl/bindings", "wasm-prep": "rm -rf src/wasm-lib/pkg && mkdir src/wasm-lib/pkg && rm -rf src/wasm-lib/kcl/bindings",
"lint": "eslint --fix src", "lint": "eslint --fix src",
"bump-jsons": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json && echo \"$(jq --arg v \"$VERSION\" '.package.version=$v' src-tauri/tauri.conf.json --indent 2)\" > src-tauri/tauri.conf.json", "bump-jsons": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json && echo \"$(jq --arg v \"$VERSION\" '.version=$v' src-tauri/tauri.conf.json --indent 2)\" > src-tauri/tauri.conf.json",
"postinstall": "yarn xstate:typegen", "postinstall": "yarn xstate:typegen",
"xstate:typegen": "yarn xstate typegen \"src/**/*.ts?(x)\"" "xstate:typegen": "yarn xstate typegen \"src/**/*.ts?(x)\""
}, },
@ -112,7 +116,7 @@
"@babel/plugin-proposal-private-property-in-object": "^7.21.11", "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.24.3", "@babel/preset-env": "^7.24.3",
"@playwright/test": "^1.39.0", "@playwright/test": "^1.39.0",
"@tauri-apps/cli": "^1.5.11", "@tauri-apps/cli": "^2.0.0-beta.12",
"@types/crypto-js": "^4.2.2", "@types/crypto-js": "^4.2.2",
"@types/debounce-promise": "^3.1.9", "@types/debounce-promise": "^3.1.9",
"@types/pixelmatch": "^5.2.6", "@types/pixelmatch": "^5.2.6",

2545
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,12 @@ license = ""
repository = "https://github.com/KittyCAD/modeling-app" repository = "https://github.com/KittyCAD/modeling-app"
default-run = "app" default-run = "app"
edition = "2021" edition = "2021"
rust-version = "1.60" rust-version = "1.70"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[build-dependencies] [build-dependencies]
tauri-build = { version = "1.5.1", features = [] } tauri-build = { version = "2.0.0-beta", features = [] }
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
@ -20,8 +20,13 @@ kittycad = "0.2.63"
oauth2 = "4.4.2" oauth2 = "4.4.2"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
tauri = { version = "1.6.1", features = [ "os-all", "dialog-all", "fs-all", "http-request", "path-all", "shell-open", "shell-open-api", "devtools"] } tauri = { version = "2.0.0-beta", features = [ "devtools", "unstable"] }
tauri-plugin-fs-extra = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } tauri-plugin-dialog = { version = "2.0.0-beta.0" }
tauri-plugin-fs = { version = "2.0.0-beta.0" }
tauri-plugin-http = { version = "2.0.0-beta.0" }
tauri-plugin-os = { version = "2.0.0-beta.0" }
tauri-plugin-shell = { version = "2.0.0-beta.0" }
tauri-plugin-updater = { version = "2.0.0-beta.0" }
tokio = { version = "1.37.0", features = ["time"] } tokio = { version = "1.37.0", features = ["time"] }
toml = "0.8.2" toml = "0.8.2"

View File

@ -0,0 +1,87 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main-capability",
"description": "Capability for the main window",
"context": "local",
"windows": [
"main"
],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"resources:default",
"menu:default",
"tray:default",
"fs:allow-create",
"fs:allow-read-file",
"fs:allow-read-text-file",
"fs:allow-write-file",
"fs:allow-write-text-file",
"fs:allow-read-dir",
"fs:allow-copy-file",
"fs:allow-mkdir",
"fs:allow-remove",
"fs:allow-remove",
"fs:allow-rename",
"fs:allow-exists",
"fs:allow-stat",
{
"identifier": "fs:scope",
"allow": [
{
"path": "$HOME/**/*"
},
{
"path": "$HOME/.config"
},
{
"path": "$HOME/.config/**/*"
},
{
"path": "$APPCONFIG"
},
{
"path": "$APPCONFIG/**/*"
},
{
"path": "$DOCUMENT"
},
{
"path": "$DOCUMENT/**/*"
}
]
},
"shell:allow-open",
"dialog:allow-open",
"dialog:allow-save",
"dialog:allow-message",
"dialog:allow-ask",
"dialog:allow-confirm",
{
"identifier": "http:default",
"allow": [
"https://dev.kittycad.io/*",
"https://dev.zoo.dev/*",
"https://kittycad.io/*",
"https://zoo.dev/*",
"https://api.dev.kittycad.io/*",
"https://api.dev.zoo.dev/*"
]
},
"os:allow-platform",
"os:allow-version",
"os:allow-os-type",
"os:allow-family",
"os:allow-arch",
"os:allow-exe-extension",
"os:allow-locale",
"os:allow-hostname"
],
"platforms": [
"linux",
"macOS",
"windows"
]
}

View File

@ -4,11 +4,15 @@
use std::env; use std::env;
use std::fs; use std::fs;
use std::io::Read; use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use oauth2::TokenResponse; use oauth2::TokenResponse;
use serde::Serialize;
use std::process::Command; use std::process::Command;
use tauri::{InvokeError, Manager}; use tauri::ipc::InvokeError;
use tauri_plugin_shell::ShellExt;
const DEFAULT_HOST: &str = "https://api.kittycad.io"; const DEFAULT_HOST: &str = "https://api.kittycad.io";
/// This command returns the a json string parse from a toml file at the path. /// This command returns the a json string parse from a toml file at the path.
@ -24,6 +28,56 @@ fn read_toml(path: &str) -> Result<String, InvokeError> {
Ok(value) Ok(value)
} }
/// From https://github.com/tauri-apps/tauri/blob/1.x/core/tauri/src/api/dir.rs#L51
/// Removed from tauri v2
#[derive(Debug, Serialize)]
pub struct DiskEntry {
/// The path to the entry.
pub path: PathBuf,
/// The name of the entry (file name with extension or directory name).
pub name: Option<String>,
/// The children of this entry if it's a directory.
#[serde(skip_serializing_if = "Option::is_none")]
pub children: Option<Vec<DiskEntry>>,
}
/// From https://github.com/tauri-apps/tauri/blob/1.x/core/tauri/src/api/dir.rs#L51
/// Removed from tauri v2
fn is_dir<P: AsRef<Path>>(path: P) -> Result<bool> {
std::fs::metadata(path)
.map(|md| md.is_dir())
.map_err(Into::into)
}
/// From https://github.com/tauri-apps/tauri/blob/1.x/core/tauri/src/api/dir.rs#L51
/// Removed from tauri v2
#[tauri::command]
fn read_dir_recursive(path: &str) -> Result<Vec<DiskEntry>, InvokeError> {
let mut files_and_dirs: Vec<DiskEntry> = vec![];
// let path = path.as_ref();
for entry in fs::read_dir(path).map_err(|e| InvokeError::from_anyhow(e.into()))? {
let path = entry
.map_err(|e| InvokeError::from_anyhow(e.into()))?
.path();
if let Ok(flag) = is_dir(&path) {
files_and_dirs.push(DiskEntry {
path: path.clone(),
children: if flag {
Some(read_dir_recursive(path.to_str().expect("No path"))?)
} else {
None
},
name: path
.file_name()
.map(|name| name.to_string_lossy())
.map(|name| name.to_string()),
});
}
}
Ok(files_and_dirs)
}
/// This command returns a string that is the contents of a file at the path. /// This command returns a string that is the contents of a file at the path.
#[tauri::command] #[tauri::command]
fn read_txt_file(path: &str) -> Result<String, InvokeError> { fn read_txt_file(path: &str) -> Result<String, InvokeError> {
@ -85,7 +139,8 @@ async fn login(app: tauri::AppHandle, host: &str) -> Result<String, InvokeError>
fs::write("/tmp/kittycad_user_code", details.user_code().secret()) fs::write("/tmp/kittycad_user_code", details.user_code().secret())
.expect("Unable to write /tmp/kittycad_user_code file"); .expect("Unable to write /tmp/kittycad_user_code file");
} else { } else {
tauri::api::shell::open(&app.shell_scope(), auth_uri.secret(), None) app.shell()
.open(auth_uri.secret(), None)
.map_err(|e| InvokeError::from_anyhow(e.into()))?; .map_err(|e| InvokeError::from_anyhow(e.into()))?;
} }
@ -165,12 +220,15 @@ fn show_in_folder(path: String) {
fn main() { fn main() {
tauri::Builder::default() tauri::Builder::default()
.setup(|_app| { .setup(|_app| {
#[cfg(debug_assertions)] // only include this code on debug builds #[cfg(debug_assertions)]
{ {
let window = _app.get_window("main").unwrap(); use tauri::Manager;
// comment out the below if you don't devtools to open everytime. _app.get_webview("main").unwrap().open_devtools();
// it's useful because otherwise devtools shuts everytime rust code changes. }
window.open_devtools(); #[cfg(not(debug_assertions))]
{
_app.handle()
.plugin(tauri_plugin_updater::Builder::new().build())?;
} }
Ok(()) Ok(())
}) })
@ -179,9 +237,14 @@ fn main() {
login, login,
read_toml, read_toml,
read_txt_file, read_txt_file,
read_dir_recursive,
show_in_folder, show_in_folder,
]) ])
.plugin(tauri_plugin_fs_extra::init()) .plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_shell::init())
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");
} }

View File

@ -1,63 +1,28 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/schema.json", "$schema": "../node_modules/@tauri-apps/cli/schema.json",
"build": { "app": {
"beforeDevCommand": "yarn start", "security": {
"devPath": "http://localhost:3000", "csp": null
"distDir": "../build"
}, },
"package": { "windows": [
"productName": "zoo-modeling-app", {
"version": "0.17.3" "fullscreen": false,
}, "height": 1200,
"tauri": { "resizable": true,
"allowlist": { "title": "Zoo Modeling App",
"all": false, "width": 1800
"dialog": { }
"all": true,
"ask": true,
"confirm": true,
"message": true,
"open": true,
"save": true
},
"fs": {
"scope": [
"$HOME/**/*",
"$APPCONFIG",
"$APPCONFIG/**/*",
"$DOCUMENT",
"$DOCUMENT/**/*"
],
"all": true
},
"http": {
"request": true,
"scope": [
"https://dev.kittycad.io/*",
"https://dev.zoo.dev/*",
"https://kittycad.io/*",
"https://zoo.dev/*",
"https://api.dev.kittycad.io/*",
"https://api.dev.zoo.dev/*"
] ]
}, },
"os": { "build": {
"all": true "beforeDevCommand": "yarn start",
}, "devUrl": "http://localhost:3000",
"shell": { "frontendDist": "../build"
"open": true
},
"path": {
"all": true
}
}, },
"bundle": { "bundle": {
"active": true, "active": true,
"category": "DeveloperTool", "category": "DeveloperTool",
"copyright": "", "copyright": "",
"deb": {
"depends": []
},
"externalBin": [], "externalBin": [],
"icon": [ "icon": [
"icons/32x32.png", "icons/32x32.png",
@ -66,7 +31,11 @@
"icons/icon.icns", "icons/icon.icns",
"icons/icon.ico" "icons/icon.ico"
], ],
"identifier": "dev.zoo.modeling-app", "linux": {
"deb": {
"depends": []
}
},
"longDescription": "", "longDescription": "",
"macOS": { "macOS": {
"entitlements": null, "entitlements": null,
@ -79,20 +48,12 @@
"shortDescription": "", "shortDescription": "",
"targets": "all" "targets": "all"
}, },
"security": { "identifier": "dev.zoo.modeling-app",
"csp": null "plugins": {
"shell": {
"open": true
}
}, },
"updater": { "productName": "Zoo Modeling App",
"active": false "version": "0.17.3"
},
"windows": [
{
"fullscreen": false,
"height": 1200,
"resizable": true,
"title": "Zoo Modeling App",
"width": 1800
}
]
}
} }

View File

@ -1,6 +0,0 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"package": {
"productName": "Zoo Modeling App"
}
}

View File

@ -1,6 +1,13 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/schema.json", "$schema": "../node_modules/@tauri-apps/cli/schema.json",
"tauri": { "bundle": {
"windows": {
"certificateThumbprint": "F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D",
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com"
}
},
"plugins": {
"updater": { "updater": {
"active": true, "active": true,
"endpoints": [ "endpoints": [
@ -8,14 +15,6 @@
], ],
"dialog": true, "dialog": true,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUzNzA4MjBEQjFBRTY4NzYKUldSMmFLNnhEWUp3NCtsT21Jd05wQktOaGVkOVp6MUFma0hNTDRDSnI2RkJJTEZOWG1ncFhqcU8K" "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUzNzA4MjBEQjFBRTY4NzYKUldSMmFLNnhEWUp3NCtsT21Jd05wQktOaGVkOVp6MUFma0hNTDRDSnI2RkJJTEZOWG1ncFhqcU8K"
},
"bundle": {
"identifier": "io.kittycad.modeling-app",
"windows": {
"certificateThumbprint": "F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D",
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com"
}
} }
} }
} }

View File

@ -1,6 +0,0 @@
{
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
"package": {
"productName": "Zoo Modeling App"
}
}

View File

@ -254,7 +254,7 @@ export const Toolbar = () => {
onClick={() => commandBarSend({ type: 'Open' })} onClick={() => commandBarSend({ type: 'Open' })}
className="rounded-r-full pr-4 self-stretch border-primary/30 hover:border-primary dark:border-chalkboard-80 dark:bg-chalkboard-80 text-primary" className="rounded-r-full pr-4 self-stretch border-primary/30 hover:border-primary dark:border-chalkboard-80 dark:bg-chalkboard-80 text-primary"
> >
{platform === 'darwin' ? '⌘K' : 'Ctrl+/'} {platform === 'macos' ? '⌘K' : 'Ctrl+/'}
</ActionButton> </ActionButton>
</div> </div>
) )

View File

@ -54,7 +54,7 @@ export const AppHeader = ({
> >
Command Palette{' '} Command Palette{' '}
<kbd className="bg-primary/10 dark:bg-chalkboard-100 dark:text-primary inline-block px-1 py-0.5 border-primary dark:border-chalkboard-90"> <kbd className="bg-primary/10 dark:bg-chalkboard-100 dark:text-primary inline-block px-1 py-0.5 border-primary dark:border-chalkboard-90">
{platform === 'darwin' ? '⌘K' : 'Ctrl+/'} {platform === 'macos' ? '⌘K' : 'Ctrl+/'}
</kbd> </kbd>
</ActionButton> </ActionButton>
)} )}

View File

@ -14,16 +14,10 @@ import {
} from 'xstate' } from 'xstate'
import { useCommandsContext } from 'hooks/useCommandsContext' import { useCommandsContext } from 'hooks/useCommandsContext'
import { fileMachine } from 'machines/fileMachine' import { fileMachine } from 'machines/fileMachine'
import { import { mkdir, remove, rename, create } from '@tauri-apps/plugin-fs'
createDir,
removeDir,
removeFile,
renameFile,
writeFile,
} from '@tauri-apps/api/fs'
import { readProject } from 'lib/tauriFS' import { readProject } from 'lib/tauriFS'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { sep } from '@tauri-apps/api/path' import { join, sep } from '@tauri-apps/api/path'
import { DEFAULT_FILE_NAME, FILE_EXT } from 'lib/constants' import { DEFAULT_FILE_NAME, FILE_EXT } from 'lib/constants'
type MachineContext<T extends AnyStateMachine> = { type MachineContext<T extends AnyStateMachine> = {
@ -56,7 +50,7 @@ export const FileMachineProvider = ({
commandBarSend({ type: 'Close' }) commandBarSend({ type: 'Close' })
navigate( navigate(
`${paths.FILE}/${encodeURIComponent( `${paths.FILE}/${encodeURIComponent(
context.selectedDirectory + sep + event.data.name context.selectedDirectory + sep() + event.data.name
)}` )}`
) )
} }
@ -79,14 +73,13 @@ export const FileMachineProvider = ({
let name = event.data.name.trim() || DEFAULT_FILE_NAME let name = event.data.name.trim() || DEFAULT_FILE_NAME
if (event.data.makeDir) { if (event.data.makeDir) {
await createDir(context.selectedDirectory.path + sep + name) await mkdir(await join(context.selectedDirectory.path, name))
} else { } else {
await writeFile( await create(
context.selectedDirectory.path + context.selectedDirectory.path +
sep + sep() +
name + name +
(name.endsWith(FILE_EXT) ? '' : FILE_EXT), (name.endsWith(FILE_EXT) ? '' : FILE_EXT)
''
) )
} }
@ -99,12 +92,11 @@ export const FileMachineProvider = ({
const { oldName, newName, isDir } = event.data const { oldName, newName, isDir } = event.data
let name = newName ? newName : DEFAULT_FILE_NAME let name = newName ? newName : DEFAULT_FILE_NAME
await renameFile( await rename(
context.selectedDirectory.path + sep + oldName, await join(context.selectedDirectory.path, oldName),
context.selectedDirectory.path + (await join(context.selectedDirectory.path, name)) +
sep + (name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT),
name + {}
(name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT)
) )
return ( return (
oldName !== name && `Successfully renamed "${oldName}" to "${name}"` oldName !== name && `Successfully renamed "${oldName}" to "${name}"`
@ -117,11 +109,11 @@ export const FileMachineProvider = ({
const isDir = !!event.data.children const isDir = !!event.data.children
if (isDir) { if (isDir) {
await removeDir(event.data.path, { await remove(event.data.path, {
recursive: true, recursive: true,
}).catch((e) => console.error('Error deleting directory', e)) }).catch((e) => console.error('Error deleting directory', e))
} else { } else {
await removeFile(event.data.path).catch((e) => await remove(event.data.path).catch((e) =>
console.error('Error deleting file', e) console.error('Error deleting file', e)
) )
} }

View File

@ -1,8 +1,7 @@
import { type IndexLoaderData } from 'lib/types' import type { FileEntry, IndexLoaderData } from 'lib/types'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'
import { ActionButton } from './ActionButton' import { ActionButton } from './ActionButton'
import Tooltip from './Tooltip' import Tooltip from './Tooltip'
import { FileEntry } from '@tauri-apps/api/fs'
import { Dispatch, useEffect, useRef, useState } from 'react' import { Dispatch, useEffect, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { Dialog, Disclosure } from '@headlessui/react' import { Dialog, Disclosure } from '@headlessui/react'

View File

@ -13,7 +13,7 @@ import { Extension } from '@codemirror/state'
import { LanguageSupport } from '@codemirror/language' import { LanguageSupport } from '@codemirror/language'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'
import { FileEntry } from '@tauri-apps/api/fs' import { FileEntry } from 'lib/types'
const DEFAULT_FILE_NAME: string = 'main.kcl' const DEFAULT_FILE_NAME: string = 'main.kcl'

View File

@ -136,7 +136,10 @@ function ProjectCard({
}`} }`}
</span> </span>
<span className="text-chalkboard-60 text-xs"> <span className="text-chalkboard-60 text-xs">
Edited {getDisplayedTime(project.entrypointMetadata.modifiedAt)} Edited{' '}
{project.entrypointMetadata.mtime
? getDisplayedTime(project.entrypointMetadata.mtime)
: 'never'}
</span> </span>
<div className="absolute z-10 bottom-2 right-2 flex gap-1 items-center opacity-0 group-hover:opacity-100 group-focus-within:opacity-100"> <div className="absolute z-10 bottom-2 right-2 flex gap-1 items-center opacity-0 group-hover:opacity-100 group-focus-within:opacity-100">
<ActionButton <ActionButton

View File

@ -17,23 +17,24 @@ const projectWellFormed = {
}, },
], ],
entrypointMetadata: { entrypointMetadata: {
accessedAt: now, atime: now,
blksize: 32, blksize: 32,
blocks: 32, blocks: 32,
createdAt: now, birthtime: now,
dev: 1, dev: 1,
gid: 1, gid: 1,
ino: 1, ino: 1,
isDir: false, isDirectory: false,
isFile: true, isFile: true,
isSymlink: false, isSymlink: false,
mode: 1, mode: 1,
modifiedAt: now, mtime: now,
nlink: 1, nlink: 1,
permissions: { readonly: false, mode: 1 }, readonly: false,
rdev: 1, rdev: 1,
size: 32, size: 32,
uid: 1, uid: 1,
fileAttributes: null,
}, },
} satisfies ProjectWithEntryPointMetadata } satisfies ProjectWithEntryPointMetadata

View File

@ -87,7 +87,7 @@ function ProjectMenuPopover({
<div className="flex flex-col items-start py-0.5"> <div className="flex flex-col items-start py-0.5">
<span className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block"> <span className="hidden text-sm text-chalkboard-110 dark:text-chalkboard-20 whitespace-nowrap lg:block">
{isTauri() && file?.name {isTauri() && file?.name
? file.name.slice(file.name.lastIndexOf(sep) + 1) ? file.name.slice(file.name.lastIndexOf(sep()) + 1)
: APP_NAME} : APP_NAME}
</span> </span>
{isTauri() && project?.name && ( {isTauri() && project?.name && (
@ -135,7 +135,7 @@ function ProjectMenuPopover({
data-testid="createdAt" data-testid="createdAt"
> >
Created{' '} Created{' '}
{project.entrypointMetadata.createdAt.toLocaleDateString()} {project.entrypointMetadata.birthtime?.toLocaleDateString()}
</p> </p>
)} )}
</div> </div>

View File

@ -1,4 +1,4 @@
import { Platform, platform } from '@tauri-apps/api/os' import { Platform, platform } from '@tauri-apps/plugin-os'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
@ -14,9 +14,9 @@ export default function usePlatform() {
void getPlatform() void getPlatform()
} else { } else {
if (navigator.userAgent.indexOf('Mac') !== -1) { if (navigator.userAgent.indexOf('Mac') !== -1) {
setPlatformName('darwin') setPlatformName('macos')
} else if (navigator.userAgent.indexOf('Win') !== -1) { } else if (navigator.userAgent.indexOf('Win') !== -1) {
setPlatformName('win32') setPlatformName('windows')
} else if (navigator.userAgent.indexOf('Linux') !== -1) { } else if (navigator.userAgent.indexOf('Linux') !== -1) {
setPlatformName('linux') setPlatformName('linux')
} }

View File

@ -20,7 +20,7 @@ import { bracket } from 'lib/exampleKcl'
import { getNodeFromPath } from './queryAst' import { getNodeFromPath } from './queryAst'
import { Params } from 'react-router-dom' import { Params } from 'react-router-dom'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { writeTextFile } from '@tauri-apps/api/fs' import { writeTextFile } from '@tauri-apps/plugin-fs'
import { toast } from 'react-hot-toast' import { toast } from 'react-hot-toast'
const PERSIST_CODE_TOKEN = 'persistCode' const PERSIST_CODE_TOKEN = 'persistCode'

View File

@ -1,10 +1,8 @@
import { import { readFile, exists as tauriExists } from '@tauri-apps/plugin-fs'
readDir,
readBinaryFile,
exists as tauriExists,
} from '@tauri-apps/api/fs'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { join } from '@tauri-apps/api/path' import { join } from '@tauri-apps/api/path'
import { invoke } from '@tauri-apps/api/core'
import { FileEntry } from 'lib/types'
/// FileSystemManager is a class that provides a way to read files from the local file system. /// FileSystemManager is a class that provides a way to read files from the local file system.
/// It assumes that you are in a project since it is solely used by the std lib /// It assumes that you are in a project since it is solely used by the std lib
@ -37,7 +35,7 @@ class FileSystemManager {
throw new Error(`Error reading file: ${error}`) throw new Error(`Error reading file: ${error}`)
}) })
.then((file) => { .then((file) => {
return readBinaryFile(file) return readFile(file)
}) })
} }
@ -71,7 +69,9 @@ class FileSystemManager {
throw new Error(`Error joining dir: ${error}`) throw new Error(`Error joining dir: ${error}`)
}) })
.then((p) => { .then((p) => {
readDir(p, { recursive: true }) invoke<FileEntry[]>('read_dir_recursive', {
path: p,
})
.catch((error) => { .catch((error) => {
throw new Error(`Error reading dir: ${error}`) throw new Error(`Error reading dir: ${error}`)
}) })

View File

@ -78,7 +78,7 @@ const initialise = async () => {
: window.location.origin.includes('tauri://localhost') : window.location.origin.includes('tauri://localhost')
? 'tauri://localhost' // custom protocol for macOS ? 'tauri://localhost' // custom protocol for macOS
: window.location.origin.includes('tauri.localhost') : window.location.origin.includes('tauri.localhost')
? 'https://tauri.localhost' // fallback for Windows ? 'http://tauri.localhost' // fallback for Windows
: window.location.origin.includes('localhost') : window.location.origin.includes('localhost')
? 'http://localhost:3000' ? 'http://localhost:3000'
: window.location.origin && window.location.origin !== 'null' : window.location.origin && window.location.origin !== 'null'

View File

@ -1,8 +1,8 @@
import { isTauri } from './isTauri' import { isTauri } from './isTauri'
import { deserialize_files } from '../wasm-lib/pkg/wasm_lib' import { deserialize_files } from '../wasm-lib/pkg/wasm_lib'
import { browserSaveFile } from './browserSaveFile' import { browserSaveFile } from './browserSaveFile'
import { save } from '@tauri-apps/api/dialog' import { save } from '@tauri-apps/plugin-dialog'
import { writeBinaryFile } from '@tauri-apps/api/fs' import { writeFile } from '@tauri-apps/plugin-fs'
import JSZip from 'jszip' import JSZip from 'jszip'
@ -26,7 +26,7 @@ const save_ = async (file: ModelingAppFile) => {
} }
// Write the file. // Write the file.
await writeBinaryFile(filePath, file.contents) await writeFile(filePath, new Uint8Array(file.contents))
} else { } else {
// Download the file to the user's computer. // Download the file to the user's computer.
// Now we need to download the files to the user's downloads folder. // Now we need to download the files to the user's downloads folder.

View File

@ -1,6 +1,6 @@
export function isTauri(): boolean { export function isTauri(): boolean {
if (globalThis.window && typeof globalThis.window !== 'undefined') { if (globalThis.window && typeof globalThis.window !== 'undefined') {
return '__TAURI__' in globalThis.window return '__TAURI_INTERNALS__' in globalThis.window
} }
return false return false
} }

View File

@ -27,7 +27,7 @@ export const BROWSER_PATH = `%2F${BROWSER_PROJECT_NAME}%2F${BROWSER_FILE_NAME}${
export function getProjectMetaByRouteId(id?: string, defaultDir = '') { export function getProjectMetaByRouteId(id?: string, defaultDir = '') {
if (!id) return undefined if (!id) return undefined
const s = isTauri() ? sep : '/' const s = isTauri() ? sep() : '/'
const decodedId = decodeURIComponent(id).replace(/\/$/, '') // remove trailing slash const decodedId = decodeURIComponent(id).replace(/\/$/, '') // remove trailing slash
const projectAndFile = const projectAndFile =

View File

@ -1,5 +1,10 @@
import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom' import { ActionFunction, LoaderFunction, redirect } from 'react-router-dom'
import { FileLoaderData, HomeLoaderData, IndexLoaderData } from './types' import {
FileEntry,
FileLoaderData,
HomeLoaderData,
IndexLoaderData,
} from './types'
import { isTauri } from './isTauri' import { isTauri } from './isTauri'
import { getProjectMetaByRouteId, paths } from './paths' import { getProjectMetaByRouteId, paths } from './paths'
import { BROWSER_PATH } from 'lib/paths' import { BROWSER_PATH } from 'lib/paths'
@ -15,11 +20,11 @@ import {
initializeProjectDirectory, initializeProjectDirectory,
} from './tauriFS' } from './tauriFS'
import makeUrlPathRelative from './makeUrlPathRelative' import makeUrlPathRelative from './makeUrlPathRelative'
import { sep } from '@tauri-apps/api/path' import { join, sep } from '@tauri-apps/api/path'
import { readDir, readTextFile } from '@tauri-apps/api/fs' import { readTextFile, stat } from '@tauri-apps/plugin-fs'
import { metadata } from 'tauri-plugin-fs-extra-api'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { fileSystemManager } from 'lang/std/fileSystemManager' import { fileSystemManager } from 'lang/std/fileSystemManager'
import { invoke } from '@tauri-apps/api/core'
// The root loader simply resolves the settings and any errors that // The root loader simply resolves the settings and any errors that
// occurred during the settings load // occurred during the settings load
@ -81,7 +86,7 @@ export const fileLoader: LoaderFunction = async ({
if (!currentFileName || !currentFilePath) { if (!currentFileName || !currentFilePath) {
return redirect( return redirect(
`${paths.FILE}/${encodeURIComponent( `${paths.FILE}/${encodeURIComponent(
`${params.id}${isTauri() ? sep : '/'}${PROJECT_ENTRYPOINT}` `${params.id}${isTauri() ? sep() : '/'}${PROJECT_ENTRYPOINT}`
)}` )}`
) )
} }
@ -89,10 +94,12 @@ export const fileLoader: LoaderFunction = async ({
// TODO: PROJECT_ENTRYPOINT is hardcoded // TODO: PROJECT_ENTRYPOINT is hardcoded
// until we support setting a project's entrypoint file // until we support setting a project's entrypoint file
const code = await readTextFile(currentFilePath) const code = await readTextFile(currentFilePath)
const entrypointMetadata = await metadata( const entrypointMetadata = await stat(
projectPath + sep + PROJECT_ENTRYPOINT await join(projectPath, PROJECT_ENTRYPOINT)
) )
const children = await readDir(projectPath, { recursive: true }) const children = await invoke<FileEntry[]>('read_dir_recursive', {
path: projectPath,
})
kclManager.setCodeAndExecute(code, false) kclManager.setCodeAndExecute(code, false)
// Set the file system manager to the project path // Set the file system manager to the project path

View File

@ -14,7 +14,7 @@ import {
} from 'lib/cameraControls' } from 'lib/cameraControls'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { useRef } from 'react' import { useRef } from 'react'
import { open } from '@tauri-apps/api/dialog' import { open } from '@tauri-apps/plugin-dialog'
import { CustomIcon } from 'components/CustomIcon' import { CustomIcon } from 'components/CustomIcon'
import Tooltip from 'components/Tooltip' import Tooltip from 'components/Tooltip'

View File

@ -6,9 +6,8 @@ import {
import { Setting, createSettings, settings } from 'lib/settings/initialSettings' import { Setting, createSettings, settings } from 'lib/settings/initialSettings'
import { SaveSettingsPayload, SettingsLevel } from './settingsTypes' import { SaveSettingsPayload, SettingsLevel } from './settingsTypes'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { removeFile, writeTextFile } from '@tauri-apps/api/fs'
import { exists } from 'tauri-plugin-fs-extra-api'
import * as TOML from '@iarna/toml' import * as TOML from '@iarna/toml'
import { remove, writeTextFile, exists } from '@tauri-apps/plugin-fs'
/** /**
* We expect the settings to be stored in a TOML file * We expect the settings to be stored in a TOML file
@ -91,7 +90,7 @@ async function writeOrClearPersistedSettings(
) )
} else { } else {
if (isTauri() && (await exists(settingsFilePath))) { if (isTauri() && (await exists(settingsFilePath))) {
await removeFile(settingsFilePath) await remove(settingsFilePath)
} }
localStorage.removeItem(settingsFilePath) localStorage.removeItem(settingsFilePath)
} }

View File

@ -43,12 +43,12 @@ export function getSortFunction(sortBy: string) {
a: ProjectWithEntryPointMetadata, a: ProjectWithEntryPointMetadata,
b: ProjectWithEntryPointMetadata b: ProjectWithEntryPointMetadata
) => { ) => {
if (a.entrypointMetadata?.modifiedAt && b.entrypointMetadata?.modifiedAt) { if (a.entrypointMetadata?.mtime && b.entrypointMetadata?.mtime) {
return !sortBy || sortBy.includes('desc') return !sortBy || sortBy.includes('desc')
? b.entrypointMetadata.modifiedAt.getTime() - ? b.entrypointMetadata.mtime.getTime() -
a.entrypointMetadata.modifiedAt.getTime() a.entrypointMetadata.mtime.getTime()
: a.entrypointMetadata.modifiedAt.getTime() - : a.entrypointMetadata.mtime.getTime() -
b.entrypointMetadata.modifiedAt.getTime() b.entrypointMetadata.mtime.getTime()
} }
return 0 return 0
} }

View File

@ -1,4 +1,3 @@
import { FileEntry } from '@tauri-apps/api/fs'
import { import {
deepFileFilter, deepFileFilter,
getNextProjectIndex, getNextProjectIndex,
@ -6,6 +5,7 @@ import {
interpolateProjectNameWithIndex, interpolateProjectNameWithIndex,
isRelevantFileOrDir, isRelevantFileOrDir,
} from './tauriFS' } from './tauriFS'
import type { FileEntry } from './types'
import { MAX_PADDING } from './constants' import { MAX_PADDING } from './constants'
describe('Test project name utility functions', () => { describe('Test project name utility functions', () => {

View File

@ -1,15 +1,20 @@
import { import {
FileEntry, mkdir,
createDir,
exists, exists,
readDir,
readTextFile, readTextFile,
writeTextFile, writeTextFile,
} from '@tauri-apps/api/fs' stat,
import { appConfigDir, documentDir, homeDir, sep } from '@tauri-apps/api/path' } from '@tauri-apps/plugin-fs'
import { invoke } from '@tauri-apps/api/core'
import {
appConfigDir,
documentDir,
homeDir,
join,
sep,
} from '@tauri-apps/api/path'
import { isTauri } from './isTauri' import { isTauri } from './isTauri'
import { type ProjectWithEntryPointMetadata } from 'lib/types' import type { FileEntry, ProjectWithEntryPointMetadata } from 'lib/types'
import { metadata } from 'tauri-plugin-fs-extra-api'
import { import {
FILE_EXT, FILE_EXT,
INDEX_IDENTIFIER, INDEX_IDENTIFIER,
@ -33,10 +38,10 @@ export async function getInitialDefaultDir() {
try { try {
dir = await documentDir() dir = await documentDir()
} catch (e) { } catch (e) {
dir = `${await homeDir()}Documents/` // for headless Linux (eg. Github Actions) dir = await join(await homeDir(), 'Documents') // for headless Linux (eg. Github Actions)
} }
return dir + PROJECT_FOLDER return await join(dir, PROJECT_FOLDER)
} }
// Initializes the project directory and returns the path // Initializes the project directory and returns the path
@ -96,7 +101,7 @@ async function testAndCreateDir(
if (dirExists instanceof Error) { if (dirExists instanceof Error) {
returnValue.error = dirExists returnValue.error = dirExists
} else if (dirExists === false) { } else if (dirExists === false) {
const newDirCreated = await createDir(directory, { recursive: true }).catch( const newDirCreated = await mkdir(directory, { recursive: true }).catch(
(e) => { (e) => {
console.error( console.error(
`Error creating directory ${directory}. Original error:`, `Error creating directory ${directory}. Original error:`,
@ -129,14 +134,12 @@ export function isProjectDirectory(fileOrDir: Partial<FileEntry>) {
// and return the valid projects // and return the valid projects
export async function getProjectsInDir(projectDir: string) { export async function getProjectsInDir(projectDir: string) {
const readProjects = ( const readProjects = (
await readDir(projectDir, { await invoke<FileEntry[]>('read_dir_recursive', { path: projectDir })
recursive: true,
})
).filter(isProjectDirectory) ).filter(isProjectDirectory)
const projectsWithMetadata = await Promise.all( const projectsWithMetadata = await Promise.all(
readProjects.map(async (p) => ({ readProjects.map(async (p) => ({
entrypointMetadata: await metadata(p.path + sep + PROJECT_ENTRYPOINT), entrypointMetadata: await stat(await join(p.path, PROJECT_ENTRYPOINT)),
...p, ...p,
})) }))
) )
@ -196,8 +199,8 @@ export function deepFileFilterFlat(
// Read the contents of a project directory // Read the contents of a project directory
// and return all relevant files and sub-directories recursively // and return all relevant files and sub-directories recursively
export async function readProject(projectDir: string) { export async function readProject(projectDir: string) {
const readFiles = await readDir(projectDir, { const readFiles = await invoke<FileEntry[]>('read_dir_recursive', {
recursive: true, path: projectDir,
}) })
return deepFileFilter(readFiles, isRelevantFileOrDir) return deepFileFilter(readFiles, isRelevantFileOrDir)
@ -285,29 +288,29 @@ export async function createNewProject(
const dirExists = await exists(path) const dirExists = await exists(path)
if (!dirExists) { if (!dirExists) {
await createDir(path, { recursive: true }).catch((err) => { await mkdir(path, { recursive: true }).catch((err) => {
console.error('Error creating new directory:', err) console.error('Error creating new directory:', err)
throw err throw err
}) })
} }
await writeTextFile(path + sep + PROJECT_ENTRYPOINT, initCode).catch( await writeTextFile(await join(path, PROJECT_ENTRYPOINT), initCode).catch(
(err) => { (err) => {
console.error('Error creating new file:', err) console.error('Error creating new file:', err)
throw err throw err
} }
) )
const m = await metadata(path) const m = await stat(path)
return { return {
name: path.slice(path.lastIndexOf(sep) + 1), name: path.slice(path.lastIndexOf(sep()) + 1),
path: path, path: path,
entrypointMetadata: m, entrypointMetadata: m,
children: [ children: [
{ {
name: PROJECT_ENTRYPOINT, name: PROJECT_ENTRYPOINT,
path: path + sep + PROJECT_ENTRYPOINT, path: await join(path, PROJECT_ENTRYPOINT),
children: [], children: [],
}, },
], ],
@ -371,17 +374,17 @@ export async function getUserSettingsFilePath(
filename: string = SETTINGS_FILE_EXT filename: string = SETTINGS_FILE_EXT
) { ) {
const dir = await appConfigDir() const dir = await appConfigDir()
return dir + filename return await join(dir, filename)
} }
export async function readSettingsFile( export async function readSettingsFile(
path: string path: string
): Promise<Partial<SaveSettingsPayload>> { ): Promise<Partial<SaveSettingsPayload>> {
const dir = path.slice(0, path.lastIndexOf(sep)) const dir = path.slice(0, path.lastIndexOf(sep()))
const dirExists = await exists(dir) const dirExists = await exists(dir)
if (!dirExists) { if (!dirExists) {
await createDir(dir, { recursive: true }) await mkdir(dir, { recursive: true })
} }
const settingsExist = dirExists ? await exists(path) : false const settingsExist = dirExists ? await exists(path) : false

View File

@ -1,5 +1,4 @@
import { type Metadata } from 'tauri-plugin-fs-extra-api' import { type FileInfo } from '@tauri-apps/plugin-fs'
import { type FileEntry } from '@tauri-apps/api/fs'
export type IndexLoaderData = { export type IndexLoaderData = {
code: string | null code: string | null
@ -14,12 +13,25 @@ export type FileLoaderData = {
} }
export type ProjectWithEntryPointMetadata = FileEntry & { export type ProjectWithEntryPointMetadata = FileEntry & {
entrypointMetadata: Metadata entrypointMetadata: FileInfo
} }
export type HomeLoaderData = { export type HomeLoaderData = {
projects: ProjectWithEntryPointMetadata[] projects: ProjectWithEntryPointMetadata[]
} }
// From https://github.com/tauri-apps/tauri/blob/1.x/tooling/api/src/fs.ts#L159
// Removed from tauri v2
export interface FileEntry {
path: string
/**
* Name of the directory/file
* can be null if the path terminates with `..`
*/
name?: string
/** Children of this entry if it's a directory; null otherwise */
children?: FileEntry[]
}
// From the very helpful @jcalz on StackOverflow: https://stackoverflow.com/a/58436959/22753272 // From the very helpful @jcalz on StackOverflow: https://stackoverflow.com/a/58436959/22753272
type Join<K, P> = K extends string | number type Join<K, P> = K extends string | number
? P extends string | number ? P extends string | number

View File

@ -2,7 +2,7 @@ import { createMachine, assign } from 'xstate'
import { Models } from '@kittycad/lib' import { Models } from '@kittycad/lib'
import withBaseURL from '../lib/withBaseURL' import withBaseURL from '../lib/withBaseURL'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { invoke } from '@tauri-apps/api' import { invoke } from '@tauri-apps/api/core'
import { VITE_KC_API_BASE_URL } from 'env' import { VITE_KC_API_BASE_URL } from 'env'
const SKIP_AUTH = const SKIP_AUTH =

View File

@ -1,6 +1,5 @@
import { assign, createMachine } from 'xstate' import { assign, createMachine } from 'xstate'
import { type ProjectWithEntryPointMetadata } from 'lib/types' import type { FileEntry, ProjectWithEntryPointMetadata } from 'lib/types'
import { FileEntry } from '@tauri-apps/api/fs'
export const fileMachine = createMachine( export const fileMachine = createMachine(
{ {

View File

@ -1,5 +1,5 @@
import { FormEvent, useEffect } from 'react' import { FormEvent, useEffect } from 'react'
import { removeDir, renameFile } from '@tauri-apps/api/fs' import { remove, rename } from '@tauri-apps/plugin-fs'
import { import {
createNewProject, createNewProject,
getNextProjectIndex, getNextProjectIndex,
@ -31,7 +31,7 @@ import {
import useStateMachineCommands from '../hooks/useStateMachineCommands' import useStateMachineCommands from '../hooks/useStateMachineCommands'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext' import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useCommandsContext } from 'hooks/useCommandsContext' import { useCommandsContext } from 'hooks/useCommandsContext'
import { sep } from '@tauri-apps/api/path' import { join, sep } from '@tauri-apps/api/path'
import { homeCommandBarConfig } from 'lib/commandBarConfigs/homeCommandConfig' import { homeCommandBarConfig } from 'lib/commandBarConfigs/homeCommandConfig'
import { useHotkeys } from 'react-hotkeys-hook' import { useHotkeys } from 'react-hotkeys-hook'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
@ -76,7 +76,7 @@ const Home = () => {
event: EventFrom<typeof homeMachine> event: EventFrom<typeof homeMachine>
) => { ) => {
if (event.data && 'name' in event.data) { if (event.data && 'name' in event.data) {
let projectPath = context.defaultDirectory + sep + event.data.name let projectPath = context.defaultDirectory + sep() + event.data.name
onProjectOpen( onProjectOpen(
{ {
name: event.data.name, name: event.data.name,
@ -109,7 +109,7 @@ const Home = () => {
name = interpolateProjectNameWithIndex(name, nextIndex) name = interpolateProjectNameWithIndex(name, nextIndex)
} }
await createNewProject(context.defaultDirectory + sep + name) await createNewProject(await join(context.defaultDirectory, name))
return `Successfully created "${name}"` return `Successfully created "${name}"`
}, },
@ -124,9 +124,10 @@ const Home = () => {
name = interpolateProjectNameWithIndex(name, nextIndex) name = interpolateProjectNameWithIndex(name, nextIndex)
} }
await renameFile( await rename(
context.defaultDirectory + sep + oldName, await join(context.defaultDirectory, oldName),
context.defaultDirectory + sep + name await join(context.defaultDirectory, name),
{}
) )
return `Successfully renamed "${oldName}" to "${name}"` return `Successfully renamed "${oldName}" to "${name}"`
}, },
@ -134,7 +135,7 @@ const Home = () => {
context: ContextFrom<typeof homeMachine>, context: ContextFrom<typeof homeMachine>,
event: EventFrom<typeof homeMachine, 'Delete project'> event: EventFrom<typeof homeMachine, 'Delete project'>
) => { ) => {
await removeDir(context.defaultDirectory + sep + event.data.name, { await remove(await join(context.defaultDirectory, event.data.name), {
recursive: true, recursive: true,
}) })
return `Successfully deleted "${event.data.name}"` return `Successfully deleted "${event.data.name}"`

View File

@ -22,7 +22,7 @@ export default function CmdK() {
<h2 className="text-2xl font-bold">Command Bar</h2> <h2 className="text-2xl font-bold">Command Bar</h2>
<p className="my-4"> <p className="my-4">
Press{' '} Press{' '}
{platformName === 'darwin' ? ( {platformName === 'macos' ? (
<> <>
<kbd className={kbdClasses}>K</kbd> <kbd className={kbdClasses}>K</kbd>
</> </>

View File

@ -19,7 +19,7 @@ import { useNavigate } from 'react-router-dom'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'
import { useEffect } from 'react' import { useEffect } from 'react'
import { kclManager } from 'lib/singletons' import { kclManager } from 'lib/singletons'
import { sep } from '@tauri-apps/api/path' import { join } from '@tauri-apps/api/path'
import { APP_NAME, PROJECT_ENTRYPOINT } from 'lib/constants' import { APP_NAME, PROJECT_ENTRYPOINT } from 'lib/constants'
function OnboardingWithNewFile() { function OnboardingWithNewFile() {
@ -45,12 +45,12 @@ function OnboardingWithNewFile() {
nextIndex nextIndex
) )
const newFile = await createNewProject( const newFile = await createNewProject(
projectDirectory.current + sep + name, await join(projectDirectory.current, name),
bracket bracket
) )
navigate( navigate(
`${paths.FILE}/${encodeURIComponent( `${paths.FILE}/${encodeURIComponent(
newFile.path + sep + PROJECT_ENTRYPOINT await join(newFile.path, PROJECT_ENTRYPOINT)
)}${paths.ONBOARDING.INDEX}` )}${paths.ONBOARDING.INDEX}`
) )
} }

View File

@ -19,11 +19,11 @@ import {
interpolateProjectNameWithIndex, interpolateProjectNameWithIndex,
} from 'lib/tauriFS' } from 'lib/tauriFS'
import { ONBOARDING_PROJECT_NAME } from './Onboarding' import { ONBOARDING_PROJECT_NAME } from './Onboarding'
import { sep } from '@tauri-apps/api/path' import { join, sep } from '@tauri-apps/api/path'
import { bracket } from 'lib/exampleKcl' import { bracket } from 'lib/exampleKcl'
import { isTauri } from 'lib/isTauri' import { isTauri } from 'lib/isTauri'
import { invoke } from '@tauri-apps/api'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
import { invoke } from '@tauri-apps/api/core'
import React, { Fragment, useMemo, useRef, useState } from 'react' import React, { Fragment, useMemo, useRef, useState } from 'react'
import { Setting } from 'lib/settings/initialSettings' import { Setting } from 'lib/settings/initialSettings'
import decamelize from 'decamelize' import decamelize from 'decamelize'
@ -49,7 +49,7 @@ export const Settings = () => {
location.pathname location.pathname
.replace(paths.FILE + '/', '') .replace(paths.FILE + '/', '')
.replace(paths.SETTINGS, '') .replace(paths.SETTINGS, '')
.slice(0, decodeURI(location.pathname).lastIndexOf(sep)) .slice(0, decodeURI(location.pathname).lastIndexOf(sep()))
) )
: undefined : undefined
const [settingsLevel, setSettingsLevel] = useState<SettingsLevel>( const [settingsLevel, setSettingsLevel] = useState<SettingsLevel>(
@ -90,7 +90,7 @@ export const Settings = () => {
nextIndex nextIndex
) )
const newFile = await createNewProject( const newFile = await createNewProject(
defaultDirectory + sep + name, await join(defaultDirectory, name),
bracket bracket
) )
navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`) navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`)

View File

@ -1,6 +1,6 @@
import { ActionButton } from '../components/ActionButton' import { ActionButton } from '../components/ActionButton'
import { isTauri } from '../lib/isTauri' import { isTauri } from '../lib/isTauri'
import { invoke } from '@tauri-apps/api/tauri' import { invoke } from '@tauri-apps/api/core'
import { VITE_KC_SITE_BASE_URL, VITE_KC_API_BASE_URL } from '../env' import { VITE_KC_SITE_BASE_URL, VITE_KC_API_BASE_URL } from '../env'
import { Themes, getSystemTheme } from '../lib/theme' import { Themes, getSystemTheme } from '../lib/theme'
import { paths } from 'lib/paths' import { paths } from 'lib/paths'

View File

@ -927,7 +927,7 @@ dependencies = [
[[package]] [[package]]
name = "derive-docs" name = "derive-docs"
version = "0.1.12" version = "0.1.13"
dependencies = [ dependencies = [
"Inflector", "Inflector",
"anyhow", "anyhow",
@ -944,23 +944,6 @@ dependencies = [
"syn 2.0.58", "syn 2.0.58",
] ]
[[package]]
name = "derive-docs"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138b94245509a9dd516008788b585c34847829cf37b40a758b4aa581cf94f147"
dependencies = [
"Inflector",
"convert_case",
"once_cell",
"proc-macro2",
"quote",
"regex",
"serde",
"serde_tokenstream",
"syn 2.0.58",
]
[[package]] [[package]]
name = "diesel_derives" name = "diesel_derives"
version = "2.1.3" version = "2.1.3"
@ -1460,9 +1443,9 @@ dependencies = [
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.3.25" version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb" checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@ -1879,7 +1862,7 @@ dependencies = [
"criterion", "criterion",
"dashmap", "dashmap",
"databake", "databake",
"derive-docs 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "derive-docs",
"expectorate", "expectorate",
"futures", "futures",
"gltf-json", "gltf-json",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "derive-docs" name = "derive-docs"
description = "A tool for generating documentation from Rust derive macros" description = "A tool for generating documentation from Rust derive macros"
version = "0.1.12" version = "0.1.13"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app" repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -793,7 +793,6 @@ fn generate_code_block_test(
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -809,7 +808,6 @@ fn generate_code_block_test(
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

View File

@ -39,7 +39,6 @@ mod test_examples_show {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -66,7 +65,6 @@ mod test_examples_show {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {
@ -136,7 +134,6 @@ mod test_examples_show {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -163,7 +160,6 @@ mod test_examples_show {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

View File

@ -39,7 +39,6 @@ mod test_examples_show {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -66,7 +65,6 @@ mod test_examples_show {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

View File

@ -39,7 +39,6 @@ mod test_examples_my_func {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -66,7 +65,6 @@ mod test_examples_my_func {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {
@ -136,7 +134,6 @@ mod test_examples_my_func {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -163,7 +160,6 @@ mod test_examples_my_func {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

View File

@ -40,7 +40,6 @@ mod test_examples_import {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -67,7 +66,6 @@ mod test_examples_import {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {
@ -138,7 +136,6 @@ mod test_examples_import {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -165,7 +162,6 @@ mod test_examples_import {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

View File

@ -39,7 +39,6 @@ mod test_examples_line_to {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -66,7 +65,6 @@ mod test_examples_line_to {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {
@ -136,7 +134,6 @@ mod test_examples_line_to {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -163,7 +160,6 @@ mod test_examples_line_to {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

View File

@ -39,7 +39,6 @@ mod test_examples_min {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -66,7 +65,6 @@ mod test_examples_min {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {
@ -136,7 +134,6 @@ mod test_examples_min {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -163,7 +160,6 @@ mod test_examples_min {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

View File

@ -39,7 +39,6 @@ mod test_examples_show {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -66,7 +65,6 @@ mod test_examples_show {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

View File

@ -39,7 +39,6 @@ mod test_examples_import {
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units); let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
ctx.engine ctx.engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::DefaultCameraLookAt { kittycad::types::ModelingCmd::DefaultCameraLookAt {
@ -66,7 +65,6 @@ mod test_examples_import {
let resp = ctx let resp = ctx
.engine .engine
.send_modeling_cmd( .send_modeling_cmd(
false,
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
crate::executor::SourceRange::default(), crate::executor::SourceRange::default(),
kittycad::types::ModelingCmd::TakeSnapshot { kittycad::types::ModelingCmd::TakeSnapshot {

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