Compare commits
5 Commits
v0.17.3
...
derive-doc
Author | SHA1 | Date | |
---|---|---|---|
f5ee346408 | |||
544a7565e3 | |||
979046f7e6 | |||
07ae5106b9 | |||
e9ae484332 |
@ -1,3 +1,3 @@
|
||||
[codespell]
|
||||
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
|
||||
|
26
.github/workflows/ci.yml
vendored
@ -125,6 +125,9 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@ -144,10 +147,12 @@ jobs:
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y
|
||||
libgtk-3-dev
|
||||
libgtksourceview-3.0-dev
|
||||
webkit2gtk-4.0
|
||||
libappindicator3-dev
|
||||
libayatana-appindicator3-dev
|
||||
webkit2gtk-driver
|
||||
libsoup-3.0-dev
|
||||
libjavascriptcoregtk-4.1-dev
|
||||
libwebkit2gtk-4.1-dev
|
||||
at-spi2-core
|
||||
xvfb
|
||||
|
||||
- name: Sync node version and setup cache
|
||||
@ -161,7 +166,9 @@ jobs:
|
||||
- name: Setup Rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
# TODO: re-enable for Windows builds, see https://github.com/tauri-apps/tauri/issues/9045
|
||||
- name: Setup Rust cache
|
||||
if: matrix.os != 'windows-latest'
|
||||
uses: swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: './src-tauri -> target'
|
||||
@ -224,14 +231,14 @@ jobs:
|
||||
with:
|
||||
includeRelease: false
|
||||
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
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
if: ${{ env.BUILD_RELEASE == 'true' }}
|
||||
env:
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
||||
@ -240,7 +247,7 @@ jobs:
|
||||
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' }}"
|
||||
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
|
||||
if: matrix.os != 'ubuntu-latest'
|
||||
@ -250,10 +257,11 @@ jobs:
|
||||
with:
|
||||
path: "${{ env.PREFIX }}/${{ env.MODE }}/bundle/*/*"
|
||||
|
||||
# TODO: re-enable linux e2e tests when possible
|
||||
- name: Run e2e tests (linux only)
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
if: false
|
||||
run: |
|
||||
cargo install tauri-driver@0.1.3
|
||||
cargo install tauri-driver
|
||||
source .env.${{ env.BUILD_RELEASE == 'true' && 'production' || 'development' }}
|
||||
export VITE_KC_API_BASE_URL
|
||||
xvfb-run yarn test:e2e:tauri
|
||||
|
1
.gitignore
vendored
@ -51,5 +51,6 @@ e2e/playwright/export-snapshots/*
|
||||
|
||||
## generated files
|
||||
src/**/*.typegen.ts
|
||||
src-tauri/gen
|
||||
|
||||
src/wasm-lib/grackle/stdlib_cube_partial.json
|
||||
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
12
package.json
@ -16,7 +16,12 @@
|
||||
"@open-rpc/client-js": "^1.8.1",
|
||||
"@react-hook/resize-observer": "^1.2.6",
|
||||
"@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/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
@ -48,7 +53,6 @@
|
||||
"react-router-dom": "^6.22.3",
|
||||
"sketch-helpers": "^0.0.4",
|
||||
"swr": "^2.2.2",
|
||||
"tauri-plugin-fs-extra-api": "https://github.com/tauri-apps/tauri-plugin-fs-extra#v1",
|
||||
"three": "^0.160.0",
|
||||
"toml": "^3.0.0",
|
||||
"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\"",
|
||||
"wasm-prep": "rm -rf src/wasm-lib/pkg && mkdir src/wasm-lib/pkg && rm -rf src/wasm-lib/kcl/bindings",
|
||||
"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",
|
||||
"xstate:typegen": "yarn xstate typegen \"src/**/*.ts?(x)\""
|
||||
},
|
||||
@ -112,7 +116,7 @@
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@babel/preset-env": "^7.24.3",
|
||||
"@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/debounce-promise": "^3.1.9",
|
||||
"@types/pixelmatch": "^5.2.6",
|
||||
|
2545
src-tauri/Cargo.lock
generated
@ -7,12 +7,12 @@ license = ""
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
default-run = "app"
|
||||
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
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.5.1", features = [] }
|
||||
tauri-build = { version = "2.0.0-beta", features = [] }
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
@ -20,8 +20,13 @@ kittycad = "0.2.63"
|
||||
oauth2 = "4.4.2"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
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-plugin-fs-extra = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
|
||||
tauri = { version = "2.0.0-beta", features = [ "devtools", "unstable"] }
|
||||
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"] }
|
||||
toml = "0.8.2"
|
||||
|
||||
|
87
src-tauri/capabilities/desktop.json
Normal 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"
|
||||
]
|
||||
}
|
@ -4,11 +4,15 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use oauth2::TokenResponse;
|
||||
use serde::Serialize;
|
||||
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";
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[tauri::command]
|
||||
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())
|
||||
.expect("Unable to write /tmp/kittycad_user_code file");
|
||||
} 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()))?;
|
||||
}
|
||||
|
||||
@ -165,12 +220,15 @@ fn show_in_folder(path: String) {
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.setup(|_app| {
|
||||
#[cfg(debug_assertions)] // only include this code on debug builds
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let window = _app.get_window("main").unwrap();
|
||||
// comment out the below if you don't devtools to open everytime.
|
||||
// it's useful because otherwise devtools shuts everytime rust code changes.
|
||||
window.open_devtools();
|
||||
use tauri::Manager;
|
||||
_app.get_webview("main").unwrap().open_devtools();
|
||||
}
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
_app.handle()
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
@ -179,9 +237,14 @@ fn main() {
|
||||
login,
|
||||
read_toml,
|
||||
read_txt_file,
|
||||
read_dir_recursive,
|
||||
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!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
@ -1,90 +1,9 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn start",
|
||||
"devPath": "http://localhost:3000",
|
||||
"distDir": "../build"
|
||||
},
|
||||
"package": {
|
||||
"productName": "zoo-modeling-app",
|
||||
"version": "0.17.3"
|
||||
},
|
||||
"tauri": {
|
||||
"allowlist": {
|
||||
"all": false,
|
||||
"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": {
|
||||
"all": true
|
||||
},
|
||||
"shell": {
|
||||
"open": true
|
||||
},
|
||||
"path": {
|
||||
"all": true
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"identifier": "dev.zoo.modeling-app",
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all"
|
||||
},
|
||||
"app": {
|
||||
"security": {
|
||||
"csp": null
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"fullscreen": false,
|
||||
@ -94,5 +13,47 @@
|
||||
"width": 1800
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"beforeDevCommand": "yarn start",
|
||||
"devUrl": "http://localhost:3000",
|
||||
"frontendDist": "../build"
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"category": "DeveloperTool",
|
||||
"copyright": "",
|
||||
"externalBin": [],
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"linux": {
|
||||
"deb": {
|
||||
"depends": []
|
||||
}
|
||||
},
|
||||
"longDescription": "",
|
||||
"macOS": {
|
||||
"entitlements": null,
|
||||
"exceptionDomain": "",
|
||||
"frameworks": [],
|
||||
"providerShortName": null,
|
||||
"signingIdentity": null
|
||||
},
|
||||
"resources": [],
|
||||
"shortDescription": "",
|
||||
"targets": "all"
|
||||
},
|
||||
"identifier": "dev.zoo.modeling-app",
|
||||
"plugins": {
|
||||
"shell": {
|
||||
"open": true
|
||||
}
|
||||
},
|
||||
"productName": "Zoo Modeling App",
|
||||
"version": "0.17.3"
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"package": {
|
||||
"productName": "Zoo Modeling App"
|
||||
}
|
||||
}
|
@ -1,6 +1,13 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"tauri": {
|
||||
"bundle": {
|
||||
"windows": {
|
||||
"certificateThumbprint": "F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D",
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "http://timestamp.digicert.com"
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"updater": {
|
||||
"active": true,
|
||||
"endpoints": [
|
||||
@ -8,14 +15,6 @@
|
||||
],
|
||||
"dialog": true,
|
||||
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUzNzA4MjBEQjFBRTY4NzYKUldSMmFLNnhEWUp3NCtsT21Jd05wQktOaGVkOVp6MUFma0hNTDRDSnI2RkJJTEZOWG1ncFhqcU8K"
|
||||
},
|
||||
"bundle": {
|
||||
"identifier": "io.kittycad.modeling-app",
|
||||
"windows": {
|
||||
"certificateThumbprint": "F4C9A52FF7BC26EE5E054946F6B11DEEA94C748D",
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "http://timestamp.digicert.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/schema.json",
|
||||
"package": {
|
||||
"productName": "Zoo Modeling App"
|
||||
}
|
||||
}
|
@ -254,7 +254,7 @@ export const Toolbar = () => {
|
||||
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"
|
||||
>
|
||||
{platform === 'darwin' ? '⌘K' : 'Ctrl+/'}
|
||||
{platform === 'macos' ? '⌘K' : 'Ctrl+/'}
|
||||
</ActionButton>
|
||||
</div>
|
||||
)
|
||||
|
@ -54,7 +54,7 @@ export const AppHeader = ({
|
||||
>
|
||||
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">
|
||||
{platform === 'darwin' ? '⌘K' : 'Ctrl+/'}
|
||||
{platform === 'macos' ? '⌘K' : 'Ctrl+/'}
|
||||
</kbd>
|
||||
</ActionButton>
|
||||
)}
|
||||
|
@ -14,16 +14,10 @@ import {
|
||||
} from 'xstate'
|
||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||
import { fileMachine } from 'machines/fileMachine'
|
||||
import {
|
||||
createDir,
|
||||
removeDir,
|
||||
removeFile,
|
||||
renameFile,
|
||||
writeFile,
|
||||
} from '@tauri-apps/api/fs'
|
||||
import { mkdir, remove, rename, create } from '@tauri-apps/plugin-fs'
|
||||
import { readProject } from 'lib/tauriFS'
|
||||
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'
|
||||
|
||||
type MachineContext<T extends AnyStateMachine> = {
|
||||
@ -56,7 +50,7 @@ export const FileMachineProvider = ({
|
||||
commandBarSend({ type: 'Close' })
|
||||
navigate(
|
||||
`${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
|
||||
|
||||
if (event.data.makeDir) {
|
||||
await createDir(context.selectedDirectory.path + sep + name)
|
||||
await mkdir(await join(context.selectedDirectory.path, name))
|
||||
} else {
|
||||
await writeFile(
|
||||
await create(
|
||||
context.selectedDirectory.path +
|
||||
sep +
|
||||
sep() +
|
||||
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
|
||||
let name = newName ? newName : DEFAULT_FILE_NAME
|
||||
|
||||
await renameFile(
|
||||
context.selectedDirectory.path + sep + oldName,
|
||||
context.selectedDirectory.path +
|
||||
sep +
|
||||
name +
|
||||
(name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT)
|
||||
await rename(
|
||||
await join(context.selectedDirectory.path, oldName),
|
||||
(await join(context.selectedDirectory.path, name)) +
|
||||
(name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT),
|
||||
{}
|
||||
)
|
||||
return (
|
||||
oldName !== name && `Successfully renamed "${oldName}" to "${name}"`
|
||||
@ -117,11 +109,11 @@ export const FileMachineProvider = ({
|
||||
const isDir = !!event.data.children
|
||||
|
||||
if (isDir) {
|
||||
await removeDir(event.data.path, {
|
||||
await remove(event.data.path, {
|
||||
recursive: true,
|
||||
}).catch((e) => console.error('Error deleting directory', e))
|
||||
} else {
|
||||
await removeFile(event.data.path).catch((e) =>
|
||||
await remove(event.data.path).catch((e) =>
|
||||
console.error('Error deleting file', e)
|
||||
)
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { type IndexLoaderData } from 'lib/types'
|
||||
import type { FileEntry, IndexLoaderData } from 'lib/types'
|
||||
import { paths } from 'lib/paths'
|
||||
import { ActionButton } from './ActionButton'
|
||||
import Tooltip from './Tooltip'
|
||||
import { FileEntry } from '@tauri-apps/api/fs'
|
||||
import { Dispatch, useEffect, useRef, useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Dialog, Disclosure } from '@headlessui/react'
|
||||
|
@ -13,7 +13,7 @@ import { Extension } from '@codemirror/state'
|
||||
import { LanguageSupport } from '@codemirror/language'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { paths } from 'lib/paths'
|
||||
import { FileEntry } from '@tauri-apps/api/fs'
|
||||
import { FileEntry } from 'lib/types'
|
||||
|
||||
const DEFAULT_FILE_NAME: string = 'main.kcl'
|
||||
|
||||
|
@ -136,7 +136,10 @@ function ProjectCard({
|
||||
}`}
|
||||
</span>
|
||||
<span className="text-chalkboard-60 text-xs">
|
||||
Edited {getDisplayedTime(project.entrypointMetadata.modifiedAt)}
|
||||
Edited{' '}
|
||||
{project.entrypointMetadata.mtime
|
||||
? getDisplayedTime(project.entrypointMetadata.mtime)
|
||||
: 'never'}
|
||||
</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">
|
||||
<ActionButton
|
||||
|
@ -17,23 +17,24 @@ const projectWellFormed = {
|
||||
},
|
||||
],
|
||||
entrypointMetadata: {
|
||||
accessedAt: now,
|
||||
atime: now,
|
||||
blksize: 32,
|
||||
blocks: 32,
|
||||
createdAt: now,
|
||||
birthtime: now,
|
||||
dev: 1,
|
||||
gid: 1,
|
||||
ino: 1,
|
||||
isDir: false,
|
||||
isDirectory: false,
|
||||
isFile: true,
|
||||
isSymlink: false,
|
||||
mode: 1,
|
||||
modifiedAt: now,
|
||||
mtime: now,
|
||||
nlink: 1,
|
||||
permissions: { readonly: false, mode: 1 },
|
||||
readonly: false,
|
||||
rdev: 1,
|
||||
size: 32,
|
||||
uid: 1,
|
||||
fileAttributes: null,
|
||||
},
|
||||
} satisfies ProjectWithEntryPointMetadata
|
||||
|
||||
|
@ -87,7 +87,7 @@ function ProjectMenuPopover({
|
||||
<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">
|
||||
{isTauri() && file?.name
|
||||
? file.name.slice(file.name.lastIndexOf(sep) + 1)
|
||||
? file.name.slice(file.name.lastIndexOf(sep()) + 1)
|
||||
: APP_NAME}
|
||||
</span>
|
||||
{isTauri() && project?.name && (
|
||||
@ -135,7 +135,7 @@ function ProjectMenuPopover({
|
||||
data-testid="createdAt"
|
||||
>
|
||||
Created{' '}
|
||||
{project.entrypointMetadata.createdAt.toLocaleDateString()}
|
||||
{project.entrypointMetadata.birthtime?.toLocaleDateString()}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
@ -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 { useEffect, useState } from 'react'
|
||||
|
||||
@ -14,9 +14,9 @@ export default function usePlatform() {
|
||||
void getPlatform()
|
||||
} else {
|
||||
if (navigator.userAgent.indexOf('Mac') !== -1) {
|
||||
setPlatformName('darwin')
|
||||
setPlatformName('macos')
|
||||
} else if (navigator.userAgent.indexOf('Win') !== -1) {
|
||||
setPlatformName('win32')
|
||||
setPlatformName('windows')
|
||||
} else if (navigator.userAgent.indexOf('Linux') !== -1) {
|
||||
setPlatformName('linux')
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import { bracket } from 'lib/exampleKcl'
|
||||
import { getNodeFromPath } from './queryAst'
|
||||
import { Params } from 'react-router-dom'
|
||||
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'
|
||||
|
||||
const PERSIST_CODE_TOKEN = 'persistCode'
|
||||
|
@ -1,10 +1,8 @@
|
||||
import {
|
||||
readDir,
|
||||
readBinaryFile,
|
||||
exists as tauriExists,
|
||||
} from '@tauri-apps/api/fs'
|
||||
import { readFile, exists as tauriExists } from '@tauri-apps/plugin-fs'
|
||||
import { isTauri } from 'lib/isTauri'
|
||||
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.
|
||||
/// 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}`)
|
||||
})
|
||||
.then((file) => {
|
||||
return readBinaryFile(file)
|
||||
return readFile(file)
|
||||
})
|
||||
}
|
||||
|
||||
@ -71,7 +69,9 @@ class FileSystemManager {
|
||||
throw new Error(`Error joining dir: ${error}`)
|
||||
})
|
||||
.then((p) => {
|
||||
readDir(p, { recursive: true })
|
||||
invoke<FileEntry[]>('read_dir_recursive', {
|
||||
path: p,
|
||||
})
|
||||
.catch((error) => {
|
||||
throw new Error(`Error reading dir: ${error}`)
|
||||
})
|
||||
|
@ -78,7 +78,7 @@ const initialise = async () => {
|
||||
: window.location.origin.includes('tauri://localhost')
|
||||
? 'tauri://localhost' // custom protocol for macOS
|
||||
: window.location.origin.includes('tauri.localhost')
|
||||
? 'https://tauri.localhost' // fallback for Windows
|
||||
? 'http://tauri.localhost' // fallback for Windows
|
||||
: window.location.origin.includes('localhost')
|
||||
? 'http://localhost:3000'
|
||||
: window.location.origin && window.location.origin !== 'null'
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { isTauri } from './isTauri'
|
||||
import { deserialize_files } from '../wasm-lib/pkg/wasm_lib'
|
||||
import { browserSaveFile } from './browserSaveFile'
|
||||
import { save } from '@tauri-apps/api/dialog'
|
||||
import { writeBinaryFile } from '@tauri-apps/api/fs'
|
||||
import { save } from '@tauri-apps/plugin-dialog'
|
||||
import { writeFile } from '@tauri-apps/plugin-fs'
|
||||
|
||||
import JSZip from 'jszip'
|
||||
|
||||
@ -26,7 +26,7 @@ const save_ = async (file: ModelingAppFile) => {
|
||||
}
|
||||
|
||||
// Write the file.
|
||||
await writeBinaryFile(filePath, file.contents)
|
||||
await writeFile(filePath, new Uint8Array(file.contents))
|
||||
} else {
|
||||
// Download the file to the user's computer.
|
||||
// Now we need to download the files to the user's downloads folder.
|
||||
|
@ -1,6 +1,6 @@
|
||||
export function isTauri(): boolean {
|
||||
if (globalThis.window && typeof globalThis.window !== 'undefined') {
|
||||
return '__TAURI__' in globalThis.window
|
||||
return '__TAURI_INTERNALS__' in globalThis.window
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ export const BROWSER_PATH = `%2F${BROWSER_PROJECT_NAME}%2F${BROWSER_FILE_NAME}${
|
||||
|
||||
export function getProjectMetaByRouteId(id?: string, defaultDir = '') {
|
||||
if (!id) return undefined
|
||||
const s = isTauri() ? sep : '/'
|
||||
const s = isTauri() ? sep() : '/'
|
||||
|
||||
const decodedId = decodeURIComponent(id).replace(/\/$/, '') // remove trailing slash
|
||||
const projectAndFile =
|
||||
|
@ -1,5 +1,10 @@
|
||||
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 { getProjectMetaByRouteId, paths } from './paths'
|
||||
import { BROWSER_PATH } from 'lib/paths'
|
||||
@ -15,11 +20,11 @@ import {
|
||||
initializeProjectDirectory,
|
||||
} from './tauriFS'
|
||||
import makeUrlPathRelative from './makeUrlPathRelative'
|
||||
import { sep } from '@tauri-apps/api/path'
|
||||
import { readDir, readTextFile } from '@tauri-apps/api/fs'
|
||||
import { metadata } from 'tauri-plugin-fs-extra-api'
|
||||
import { join, sep } from '@tauri-apps/api/path'
|
||||
import { readTextFile, stat } from '@tauri-apps/plugin-fs'
|
||||
import { kclManager } from 'lib/singletons'
|
||||
import { fileSystemManager } from 'lang/std/fileSystemManager'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
// The root loader simply resolves the settings and any errors that
|
||||
// occurred during the settings load
|
||||
@ -81,7 +86,7 @@ export const fileLoader: LoaderFunction = async ({
|
||||
if (!currentFileName || !currentFilePath) {
|
||||
return redirect(
|
||||
`${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
|
||||
// until we support setting a project's entrypoint file
|
||||
const code = await readTextFile(currentFilePath)
|
||||
const entrypointMetadata = await metadata(
|
||||
projectPath + sep + PROJECT_ENTRYPOINT
|
||||
const entrypointMetadata = await stat(
|
||||
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)
|
||||
|
||||
// Set the file system manager to the project path
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
} from 'lib/cameraControls'
|
||||
import { isTauri } from 'lib/isTauri'
|
||||
import { useRef } from 'react'
|
||||
import { open } from '@tauri-apps/api/dialog'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { CustomIcon } from 'components/CustomIcon'
|
||||
import Tooltip from 'components/Tooltip'
|
||||
|
||||
|
@ -6,9 +6,8 @@ import {
|
||||
import { Setting, createSettings, settings } from 'lib/settings/initialSettings'
|
||||
import { SaveSettingsPayload, SettingsLevel } from './settingsTypes'
|
||||
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 { remove, writeTextFile, exists } from '@tauri-apps/plugin-fs'
|
||||
|
||||
/**
|
||||
* We expect the settings to be stored in a TOML file
|
||||
@ -91,7 +90,7 @@ async function writeOrClearPersistedSettings(
|
||||
)
|
||||
} else {
|
||||
if (isTauri() && (await exists(settingsFilePath))) {
|
||||
await removeFile(settingsFilePath)
|
||||
await remove(settingsFilePath)
|
||||
}
|
||||
localStorage.removeItem(settingsFilePath)
|
||||
}
|
||||
|
@ -43,12 +43,12 @@ export function getSortFunction(sortBy: string) {
|
||||
a: ProjectWithEntryPointMetadata,
|
||||
b: ProjectWithEntryPointMetadata
|
||||
) => {
|
||||
if (a.entrypointMetadata?.modifiedAt && b.entrypointMetadata?.modifiedAt) {
|
||||
if (a.entrypointMetadata?.mtime && b.entrypointMetadata?.mtime) {
|
||||
return !sortBy || sortBy.includes('desc')
|
||||
? b.entrypointMetadata.modifiedAt.getTime() -
|
||||
a.entrypointMetadata.modifiedAt.getTime()
|
||||
: a.entrypointMetadata.modifiedAt.getTime() -
|
||||
b.entrypointMetadata.modifiedAt.getTime()
|
||||
? b.entrypointMetadata.mtime.getTime() -
|
||||
a.entrypointMetadata.mtime.getTime()
|
||||
: a.entrypointMetadata.mtime.getTime() -
|
||||
b.entrypointMetadata.mtime.getTime()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { FileEntry } from '@tauri-apps/api/fs'
|
||||
import {
|
||||
deepFileFilter,
|
||||
getNextProjectIndex,
|
||||
@ -6,6 +5,7 @@ import {
|
||||
interpolateProjectNameWithIndex,
|
||||
isRelevantFileOrDir,
|
||||
} from './tauriFS'
|
||||
import type { FileEntry } from './types'
|
||||
import { MAX_PADDING } from './constants'
|
||||
|
||||
describe('Test project name utility functions', () => {
|
||||
|
@ -1,15 +1,20 @@
|
||||
import {
|
||||
FileEntry,
|
||||
createDir,
|
||||
mkdir,
|
||||
exists,
|
||||
readDir,
|
||||
readTextFile,
|
||||
writeTextFile,
|
||||
} from '@tauri-apps/api/fs'
|
||||
import { appConfigDir, documentDir, homeDir, sep } from '@tauri-apps/api/path'
|
||||
stat,
|
||||
} 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 { type ProjectWithEntryPointMetadata } from 'lib/types'
|
||||
import { metadata } from 'tauri-plugin-fs-extra-api'
|
||||
import type { FileEntry, ProjectWithEntryPointMetadata } from 'lib/types'
|
||||
import {
|
||||
FILE_EXT,
|
||||
INDEX_IDENTIFIER,
|
||||
@ -33,10 +38,10 @@ export async function getInitialDefaultDir() {
|
||||
try {
|
||||
dir = await documentDir()
|
||||
} 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
|
||||
@ -96,7 +101,7 @@ async function testAndCreateDir(
|
||||
if (dirExists instanceof Error) {
|
||||
returnValue.error = dirExists
|
||||
} else if (dirExists === false) {
|
||||
const newDirCreated = await createDir(directory, { recursive: true }).catch(
|
||||
const newDirCreated = await mkdir(directory, { recursive: true }).catch(
|
||||
(e) => {
|
||||
console.error(
|
||||
`Error creating directory ${directory}. Original error:`,
|
||||
@ -129,14 +134,12 @@ export function isProjectDirectory(fileOrDir: Partial<FileEntry>) {
|
||||
// and return the valid projects
|
||||
export async function getProjectsInDir(projectDir: string) {
|
||||
const readProjects = (
|
||||
await readDir(projectDir, {
|
||||
recursive: true,
|
||||
})
|
||||
await invoke<FileEntry[]>('read_dir_recursive', { path: projectDir })
|
||||
).filter(isProjectDirectory)
|
||||
|
||||
const projectsWithMetadata = await Promise.all(
|
||||
readProjects.map(async (p) => ({
|
||||
entrypointMetadata: await metadata(p.path + sep + PROJECT_ENTRYPOINT),
|
||||
entrypointMetadata: await stat(await join(p.path, PROJECT_ENTRYPOINT)),
|
||||
...p,
|
||||
}))
|
||||
)
|
||||
@ -196,8 +199,8 @@ export function deepFileFilterFlat(
|
||||
// Read the contents of a project directory
|
||||
// and return all relevant files and sub-directories recursively
|
||||
export async function readProject(projectDir: string) {
|
||||
const readFiles = await readDir(projectDir, {
|
||||
recursive: true,
|
||||
const readFiles = await invoke<FileEntry[]>('read_dir_recursive', {
|
||||
path: projectDir,
|
||||
})
|
||||
|
||||
return deepFileFilter(readFiles, isRelevantFileOrDir)
|
||||
@ -285,29 +288,29 @@ export async function createNewProject(
|
||||
|
||||
const dirExists = await exists(path)
|
||||
if (!dirExists) {
|
||||
await createDir(path, { recursive: true }).catch((err) => {
|
||||
await mkdir(path, { recursive: true }).catch((err) => {
|
||||
console.error('Error creating new directory:', err)
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
await writeTextFile(path + sep + PROJECT_ENTRYPOINT, initCode).catch(
|
||||
await writeTextFile(await join(path, PROJECT_ENTRYPOINT), initCode).catch(
|
||||
(err) => {
|
||||
console.error('Error creating new file:', err)
|
||||
throw err
|
||||
}
|
||||
)
|
||||
|
||||
const m = await metadata(path)
|
||||
const m = await stat(path)
|
||||
|
||||
return {
|
||||
name: path.slice(path.lastIndexOf(sep) + 1),
|
||||
name: path.slice(path.lastIndexOf(sep()) + 1),
|
||||
path: path,
|
||||
entrypointMetadata: m,
|
||||
children: [
|
||||
{
|
||||
name: PROJECT_ENTRYPOINT,
|
||||
path: path + sep + PROJECT_ENTRYPOINT,
|
||||
path: await join(path, PROJECT_ENTRYPOINT),
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
@ -371,17 +374,17 @@ export async function getUserSettingsFilePath(
|
||||
filename: string = SETTINGS_FILE_EXT
|
||||
) {
|
||||
const dir = await appConfigDir()
|
||||
return dir + filename
|
||||
return await join(dir, filename)
|
||||
}
|
||||
|
||||
export async function readSettingsFile(
|
||||
path: string
|
||||
): Promise<Partial<SaveSettingsPayload>> {
|
||||
const dir = path.slice(0, path.lastIndexOf(sep))
|
||||
const dir = path.slice(0, path.lastIndexOf(sep()))
|
||||
|
||||
const dirExists = await exists(dir)
|
||||
if (!dirExists) {
|
||||
await createDir(dir, { recursive: true })
|
||||
await mkdir(dir, { recursive: true })
|
||||
}
|
||||
|
||||
const settingsExist = dirExists ? await exists(path) : false
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { type Metadata } from 'tauri-plugin-fs-extra-api'
|
||||
import { type FileEntry } from '@tauri-apps/api/fs'
|
||||
import { type FileInfo } from '@tauri-apps/plugin-fs'
|
||||
|
||||
export type IndexLoaderData = {
|
||||
code: string | null
|
||||
@ -14,12 +13,25 @@ export type FileLoaderData = {
|
||||
}
|
||||
|
||||
export type ProjectWithEntryPointMetadata = FileEntry & {
|
||||
entrypointMetadata: Metadata
|
||||
entrypointMetadata: FileInfo
|
||||
}
|
||||
export type HomeLoaderData = {
|
||||
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
|
||||
type Join<K, P> = K extends string | number
|
||||
? P extends string | number
|
||||
|
@ -2,7 +2,7 @@ import { createMachine, assign } from 'xstate'
|
||||
import { Models } from '@kittycad/lib'
|
||||
import withBaseURL from '../lib/withBaseURL'
|
||||
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'
|
||||
|
||||
const SKIP_AUTH =
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { assign, createMachine } from 'xstate'
|
||||
import { type ProjectWithEntryPointMetadata } from 'lib/types'
|
||||
import { FileEntry } from '@tauri-apps/api/fs'
|
||||
import type { FileEntry, ProjectWithEntryPointMetadata } from 'lib/types'
|
||||
|
||||
export const fileMachine = createMachine(
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { FormEvent, useEffect } from 'react'
|
||||
import { removeDir, renameFile } from '@tauri-apps/api/fs'
|
||||
import { remove, rename } from '@tauri-apps/plugin-fs'
|
||||
import {
|
||||
createNewProject,
|
||||
getNextProjectIndex,
|
||||
@ -31,7 +31,7 @@ import {
|
||||
import useStateMachineCommands from '../hooks/useStateMachineCommands'
|
||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
||||
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 { useHotkeys } from 'react-hotkeys-hook'
|
||||
import { isTauri } from 'lib/isTauri'
|
||||
@ -76,7 +76,7 @@ const Home = () => {
|
||||
event: EventFrom<typeof homeMachine>
|
||||
) => {
|
||||
if (event.data && 'name' in event.data) {
|
||||
let projectPath = context.defaultDirectory + sep + event.data.name
|
||||
let projectPath = context.defaultDirectory + sep() + event.data.name
|
||||
onProjectOpen(
|
||||
{
|
||||
name: event.data.name,
|
||||
@ -109,7 +109,7 @@ const Home = () => {
|
||||
name = interpolateProjectNameWithIndex(name, nextIndex)
|
||||
}
|
||||
|
||||
await createNewProject(context.defaultDirectory + sep + name)
|
||||
await createNewProject(await join(context.defaultDirectory, name))
|
||||
|
||||
return `Successfully created "${name}"`
|
||||
},
|
||||
@ -124,9 +124,10 @@ const Home = () => {
|
||||
name = interpolateProjectNameWithIndex(name, nextIndex)
|
||||
}
|
||||
|
||||
await renameFile(
|
||||
context.defaultDirectory + sep + oldName,
|
||||
context.defaultDirectory + sep + name
|
||||
await rename(
|
||||
await join(context.defaultDirectory, oldName),
|
||||
await join(context.defaultDirectory, name),
|
||||
{}
|
||||
)
|
||||
return `Successfully renamed "${oldName}" to "${name}"`
|
||||
},
|
||||
@ -134,7 +135,7 @@ const Home = () => {
|
||||
context: ContextFrom<typeof homeMachine>,
|
||||
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,
|
||||
})
|
||||
return `Successfully deleted "${event.data.name}"`
|
||||
|
@ -22,7 +22,7 @@ export default function CmdK() {
|
||||
<h2 className="text-2xl font-bold">Command Bar</h2>
|
||||
<p className="my-4">
|
||||
Press{' '}
|
||||
{platformName === 'darwin' ? (
|
||||
{platformName === 'macos' ? (
|
||||
<>
|
||||
<kbd className={kbdClasses}>⌘K</kbd>
|
||||
</>
|
||||
|
@ -19,7 +19,7 @@ import { useNavigate } from 'react-router-dom'
|
||||
import { paths } from 'lib/paths'
|
||||
import { useEffect } from 'react'
|
||||
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'
|
||||
|
||||
function OnboardingWithNewFile() {
|
||||
@ -45,12 +45,12 @@ function OnboardingWithNewFile() {
|
||||
nextIndex
|
||||
)
|
||||
const newFile = await createNewProject(
|
||||
projectDirectory.current + sep + name,
|
||||
await join(projectDirectory.current, name),
|
||||
bracket
|
||||
)
|
||||
navigate(
|
||||
`${paths.FILE}/${encodeURIComponent(
|
||||
newFile.path + sep + PROJECT_ENTRYPOINT
|
||||
await join(newFile.path, PROJECT_ENTRYPOINT)
|
||||
)}${paths.ONBOARDING.INDEX}`
|
||||
)
|
||||
}
|
||||
|
@ -19,11 +19,11 @@ import {
|
||||
interpolateProjectNameWithIndex,
|
||||
} from 'lib/tauriFS'
|
||||
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 { isTauri } from 'lib/isTauri'
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import toast from 'react-hot-toast'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import React, { Fragment, useMemo, useRef, useState } from 'react'
|
||||
import { Setting } from 'lib/settings/initialSettings'
|
||||
import decamelize from 'decamelize'
|
||||
@ -49,7 +49,7 @@ export const Settings = () => {
|
||||
location.pathname
|
||||
.replace(paths.FILE + '/', '')
|
||||
.replace(paths.SETTINGS, '')
|
||||
.slice(0, decodeURI(location.pathname).lastIndexOf(sep))
|
||||
.slice(0, decodeURI(location.pathname).lastIndexOf(sep()))
|
||||
)
|
||||
: undefined
|
||||
const [settingsLevel, setSettingsLevel] = useState<SettingsLevel>(
|
||||
@ -90,7 +90,7 @@ export const Settings = () => {
|
||||
nextIndex
|
||||
)
|
||||
const newFile = await createNewProject(
|
||||
defaultDirectory + sep + name,
|
||||
await join(defaultDirectory, name),
|
||||
bracket
|
||||
)
|
||||
navigate(`${paths.FILE}/${encodeURIComponent(newFile.path)}`)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ActionButton } from '../components/ActionButton'
|
||||
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 { Themes, getSystemTheme } from '../lib/theme'
|
||||
import { paths } from 'lib/paths'
|
||||
|
25
src/wasm-lib/Cargo.lock
generated
@ -927,7 +927,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive-docs"
|
||||
version = "0.1.12"
|
||||
version = "0.1.13"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"anyhow",
|
||||
@ -944,23 +944,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "diesel_derives"
|
||||
version = "2.1.3"
|
||||
@ -1460,9 +1443,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.25"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb"
|
||||
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
@ -1879,7 +1862,7 @@ dependencies = [
|
||||
"criterion",
|
||||
"dashmap",
|
||||
"databake",
|
||||
"derive-docs 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive-docs",
|
||||
"expectorate",
|
||||
"futures",
|
||||
"gltf-json",
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.12"
|
||||
version = "0.1.13"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -793,7 +793,6 @@ fn generate_code_block_test(
|
||||
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -809,7 +808,6 @@ fn generate_code_block_test(
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -39,7 +39,6 @@ mod test_examples_show {
|
||||
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -66,7 +65,6 @@ mod test_examples_show {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
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);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -163,7 +160,6 @@ mod test_examples_show {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -39,7 +39,6 @@ mod test_examples_show {
|
||||
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -66,7 +65,6 @@ mod test_examples_show {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -39,7 +39,6 @@ mod test_examples_my_func {
|
||||
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -66,7 +65,6 @@ mod test_examples_my_func {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
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);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -163,7 +160,6 @@ mod test_examples_my_func {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -40,7 +40,6 @@ mod test_examples_import {
|
||||
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -67,7 +66,6 @@ mod test_examples_import {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
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);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -165,7 +162,6 @@ mod test_examples_import {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -39,7 +39,6 @@ mod test_examples_line_to {
|
||||
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -66,7 +65,6 @@ mod test_examples_line_to {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
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);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -163,7 +160,6 @@ mod test_examples_line_to {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -39,7 +39,6 @@ mod test_examples_min {
|
||||
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -66,7 +65,6 @@ mod test_examples_min {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
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);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -163,7 +160,6 @@ mod test_examples_min {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -39,7 +39,6 @@ mod test_examples_show {
|
||||
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -66,7 +65,6 @@ mod test_examples_show {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|
@ -39,7 +39,6 @@ mod test_examples_import {
|
||||
let (x, y) = crate::std::utils::get_camera_zoom_magnitude_per_unit_length(units);
|
||||
ctx.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::DefaultCameraLookAt {
|
||||
@ -66,7 +65,6 @@ mod test_examples_import {
|
||||
let resp = ctx
|
||||
.engine
|
||||
.send_modeling_cmd(
|
||||
false,
|
||||
uuid::Uuid::new_v4(),
|
||||
crate::executor::SourceRange::default(),
|
||||
kittycad::types::ModelingCmd::TakeSnapshot {
|
||||
|