Add print button (#3133)
* add print button Signed-off-by: Jess Frazelle <github@jessfraz.com> * cleanup Signed-off-by: Jess Frazelle <github@jessfraz.com> * generate more types Signed-off-by: Jess Frazelle <github@jessfraz.com> * add a github action to generate machine api-types Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * New machine-api types * actually print on the real machine Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * add more Signed-off-by: Jess Frazelle <github@jessfraz.com> * New machine-api types * get the current machine Signed-off-by: Jess Frazelle <github@jessfraz.com> * New machine-api types * know when error Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fmt Signed-off-by: Jess Frazelle <github@jessfraz.com> * add fmt Signed-off-by: Jess Frazelle <github@jessfraz.com> * New machine-api types * empty * empty * update machine api Signed-off-by: Jess Frazelle <github@jessfraz.com> * New machine-api types * empty * New machine-api types * emptuy * no circular deps Signed-off-by: Jess Frazelle <github@jessfraz.com> * New machine-api types * remove recursive dep Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Jess Frazelle <jessfraz@users.noreply.github.com>
This commit is contained in:
49
.github/workflows/generate-machine-api-types.yml
vendored
Normal file
49
.github/workflows/generate-machine-api-types.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
name: generate machine-api types
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'openapi/machine-api.json'
|
||||||
|
- '.github/workflows/generate-machine-api-types.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
jobs:
|
||||||
|
generate:
|
||||||
|
runs-on: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: '.nvmrc'
|
||||||
|
cache: 'yarn'
|
||||||
|
- run: yarn install
|
||||||
|
- run: yarn generate:machine-api
|
||||||
|
- run: yarn fmt
|
||||||
|
- name: check for changes
|
||||||
|
id: git-check
|
||||||
|
run: |
|
||||||
|
git add .
|
||||||
|
if git status | grep -q "Changes to be committed"
|
||||||
|
then echo "modified=true" >> $GITHUB_OUTPUT
|
||||||
|
else echo "modified=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
- name: Commit changes, if any
|
||||||
|
if: steps.git-check.outputs.modified == 'true'
|
||||||
|
run: |
|
||||||
|
git add .
|
||||||
|
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git config --local user.name "github-actions[bot]"
|
||||||
|
git remote set-url origin https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
|
||||||
|
git fetch origin
|
||||||
|
echo ${{ github.head_ref }}
|
||||||
|
git checkout ${{ github.head_ref }}
|
||||||
|
git commit -am "New machine-api types" || true
|
||||||
|
git push
|
||||||
|
git push origin ${{ github.head_ref }}
|
||||||
|
|
12
flake.lock
generated
12
flake.lock
generated
@ -2,11 +2,11 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1718470082,
|
"lastModified": 1721933792,
|
||||||
"narHash": "sha256-u2F0MMYE+Efc+ocruTbtU/wWHuYHWcJafp5zJ++n/YE=",
|
"narHash": "sha256-zYVwABlQnxpbaHMfX6Wt9jhyQstFYwN2XjleOJV3VVg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "3027ba73dfef68eb555fc2fa97aed4e999e74f97",
|
"rev": "2122a9b35b35719ad9a395fe783eabb092df01b1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -43,11 +43,11 @@
|
|||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1718681902,
|
"lastModified": 1721960387,
|
||||||
"narHash": "sha256-E/T7Ge6ayEQe7FVKMJqDBoHyLhRhjc6u9CmU8MyYfy0=",
|
"narHash": "sha256-o21ax+745ETGXrcgc/yUuLw1SI77ymp3xEpJt+w/kks=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "16c8ad83297c278eebe740dea5491c1708960dd1",
|
"rev": "9cbf831c5b20a53354fc12758abd05966f9f1699",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
pkg-config
|
pkg-config
|
||||||
|
|
||||||
nodejs_22
|
nodejs_22
|
||||||
|
yarn
|
||||||
]) ++ pkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs; [
|
]) ++ pkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs; [
|
||||||
libiconv
|
libiconv
|
||||||
darwin.apple_sdk.frameworks.Security
|
darwin.apple_sdk.frameworks.Security
|
||||||
|
@ -87,7 +87,8 @@
|
|||||||
"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",
|
"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)\"",
|
||||||
"make:dev": "make dev"
|
"make:dev": "make dev",
|
||||||
|
"generate:machine-api": "npx openapi-typescript ./openapi/machine-api.json -o src/lib/machine-api.d.ts"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"trailingComma": "es5",
|
"trailingComma": "es5",
|
||||||
|
59
src-tauri/Cargo.lock
generated
59
src-tauri/Cargo.lock
generated
@ -172,7 +172,9 @@ dependencies = [
|
|||||||
"kcl-lib",
|
"kcl-lib",
|
||||||
"kittycad",
|
"kittycad",
|
||||||
"log",
|
"log",
|
||||||
|
"mdns-sd",
|
||||||
"oauth2",
|
"oauth2",
|
||||||
|
"reqwest 0.12.4",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
@ -286,7 +288,7 @@ dependencies = [
|
|||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"parking",
|
"parking",
|
||||||
"polling",
|
"polling 3.7.0",
|
||||||
"rustix",
|
"rustix",
|
||||||
"slab",
|
"slab",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -1570,6 +1572,17 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flume"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -2405,6 +2418,16 @@ dependencies = [
|
|||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "if-addrs"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cabb0019d51a643781ff15c9c8a3e5dedc365c47211270f4e8f82812fedd8f0a"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.2"
|
version = "0.25.2"
|
||||||
@ -2752,7 +2775,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2896,6 +2919,19 @@ version = "0.7.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mdns-sd"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "807457e493076539ff8f202806f9dc2eaa9f13f69701da7ed38eec7a9afd1616"
|
||||||
|
dependencies = [
|
||||||
|
"flume",
|
||||||
|
"if-addrs",
|
||||||
|
"log",
|
||||||
|
"polling 2.8.0",
|
||||||
|
"socket2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.2"
|
version = "2.7.2"
|
||||||
@ -3635,6 +3671,22 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polling"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"concurrent-queue",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"pin-project-lite",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polling"
|
name = "polling"
|
||||||
version = "3.7.0"
|
version = "3.7.0"
|
||||||
@ -4871,6 +4923,9 @@ name = "spin"
|
|||||||
version = "0.9.8"
|
version = "0.9.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stable_deref_trait"
|
name = "stable_deref_trait"
|
||||||
|
@ -18,7 +18,9 @@ anyhow = "1"
|
|||||||
kcl-lib = { version = "0.2", path = "../src/wasm-lib/kcl" }
|
kcl-lib = { version = "0.2", path = "../src/wasm-lib/kcl" }
|
||||||
kittycad = "0.3.7"
|
kittycad = "0.3.7"
|
||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
|
mdns-sd = "0.11.1"
|
||||||
oauth2 = "4.4.2"
|
oauth2 = "4.4.2"
|
||||||
|
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tauri = { version = "2.0.0-beta.23", features = [ "devtools", "unstable"] }
|
tauri = { version = "2.0.0-beta.23", features = [ "devtools", "unstable"] }
|
||||||
tauri-plugin-cli = { version = "2.0.0-beta.7" }
|
tauri-plugin-cli = { version = "2.0.0-beta.7" }
|
||||||
|
@ -370,6 +370,70 @@ fn show_in_folder(app: tauri::AppHandle, path: &str) -> Result<(), InvokeError>
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SERVICE_NAME: &str = "_machine-api._tcp.local.";
|
||||||
|
|
||||||
|
async fn find_machine_api() -> Result<Option<String>> {
|
||||||
|
println!("Looking for machine API...");
|
||||||
|
// Timeout if no response is received after 5 seconds.
|
||||||
|
let timeout_duration = std::time::Duration::from_secs(5);
|
||||||
|
|
||||||
|
let mdns = mdns_sd::ServiceDaemon::new()?;
|
||||||
|
|
||||||
|
// Browse for a service type.
|
||||||
|
let receiver = mdns.browse(SERVICE_NAME)?;
|
||||||
|
let resp = tokio::time::timeout(
|
||||||
|
timeout_duration,
|
||||||
|
tokio::spawn(async move {
|
||||||
|
while let Ok(event) = receiver.recv() {
|
||||||
|
if let mdns_sd::ServiceEvent::ServiceResolved(info) = event {
|
||||||
|
if let Some(addr) = info.get_addresses().iter().next() {
|
||||||
|
return Some(format!("{}:{}", addr, info.get_port()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Shut down.
|
||||||
|
mdns.shutdown()?;
|
||||||
|
|
||||||
|
let Ok(Ok(Some(addr))) = resp else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Some(addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn get_machine_api_ip() -> Result<Option<String>, InvokeError> {
|
||||||
|
let machine_api = find_machine_api().await.map_err(InvokeError::from_anyhow)?;
|
||||||
|
|
||||||
|
Ok(machine_api)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn list_machines() -> Result<String, InvokeError> {
|
||||||
|
let machine_api = find_machine_api().await.map_err(InvokeError::from_anyhow)?;
|
||||||
|
|
||||||
|
let Some(machine_api) = machine_api else {
|
||||||
|
// Empty array.
|
||||||
|
return Ok("[]".to_string());
|
||||||
|
};
|
||||||
|
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let response = client
|
||||||
|
.get(format!("http://{}/machines", machine_api))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| InvokeError::from_anyhow(e.into()))?;
|
||||||
|
|
||||||
|
let text = response.text().await.map_err(|e| InvokeError::from_anyhow(e.into()))?;
|
||||||
|
Ok(text)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn open_url_sync(app: &tauri::AppHandle, url: &url::Url) {
|
fn open_url_sync(app: &tauri::AppHandle, url: &url::Url) {
|
||||||
log::debug!("Opening URL: {:?}", url);
|
log::debug!("Opening URL: {:?}", url);
|
||||||
@ -417,6 +481,8 @@ fn main() -> Result<()> {
|
|||||||
read_project_settings_file,
|
read_project_settings_file,
|
||||||
write_project_settings_file,
|
write_project_settings_file,
|
||||||
rename_project_directory,
|
rename_project_directory,
|
||||||
|
get_machine_api_ip,
|
||||||
|
list_machines
|
||||||
])
|
])
|
||||||
.plugin(tauri_plugin_cli::init())
|
.plugin(tauri_plugin_cli::init())
|
||||||
.plugin(tauri_plugin_deep_link::init())
|
.plugin(tauri_plugin_deep_link::init())
|
||||||
|
@ -124,7 +124,11 @@ function CommandBarHeader({ children }: React.PropsWithChildren<{}>) {
|
|||||||
4
|
4
|
||||||
)
|
)
|
||||||
) : typeof argValue === 'object' ? (
|
) : typeof argValue === 'object' ? (
|
||||||
JSON.stringify(argValue)
|
arg.valueSummary ? (
|
||||||
|
arg.valueSummary(argValue)
|
||||||
|
) : (
|
||||||
|
JSON.stringify(argValue)
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<em>{argValue}</em>
|
<em>{argValue}</em>
|
||||||
)
|
)
|
||||||
|
@ -541,6 +541,16 @@ const CustomIconMap = {
|
|||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
),
|
),
|
||||||
|
printer3d: (
|
||||||
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M16 5H4V7.5H7V7V6H8H9H10V7V7.5H16V5ZM17 7.5V8.5V15V16V17H16V16H15H14H6H5H4V17H3V16V15V8.5V7.5V5V4H4H16H17V5V7.5ZM4 8.5V15H5V13.5V13H5.5H14.5H15V13.5V15H16V8.5H10V9H9V10L8.5 10.5L8 10V9H7V8.5H4ZM14 14V15H6V14H14ZM8 7H9V8H8V7Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
),
|
||||||
polygon: (
|
polygon: (
|
||||||
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<path
|
||||||
|
@ -10,6 +10,7 @@ import { coreDump } from 'lang/wasm'
|
|||||||
import toast from 'react-hot-toast'
|
import toast from 'react-hot-toast'
|
||||||
import { CoreDumpManager } from 'lib/coredump'
|
import { CoreDumpManager } from 'lib/coredump'
|
||||||
import openWindow from 'lib/openWindow'
|
import openWindow from 'lib/openWindow'
|
||||||
|
import { NetworkMachineIndicator } from './NetworkMachineIndicator'
|
||||||
|
|
||||||
export function LowerRightControls({
|
export function LowerRightControls({
|
||||||
children,
|
children,
|
||||||
@ -100,6 +101,7 @@ export function LowerRightControls({
|
|||||||
Settings
|
Settings
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Link>
|
</Link>
|
||||||
|
<NetworkMachineIndicator className={linkOverrideClassName} />
|
||||||
<NetworkHealthIndicator />
|
<NetworkHealthIndicator />
|
||||||
<HelpMenu />
|
<HelpMenu />
|
||||||
</menu>
|
</menu>
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
editorManager,
|
editorManager,
|
||||||
sceneEntitiesManager,
|
sceneEntitiesManager,
|
||||||
} from 'lib/singletons'
|
} from 'lib/singletons'
|
||||||
|
import { machineManager } from 'lib/machineManager'
|
||||||
import { useHotkeys } from 'react-hotkeys-hook'
|
import { useHotkeys } from 'react-hotkeys-hook'
|
||||||
import { applyConstraintHorzVertDistance } from './Toolbar/SetHorzVertDistance'
|
import { applyConstraintHorzVertDistance } from './Toolbar/SetHorzVertDistance'
|
||||||
import {
|
import {
|
||||||
@ -77,6 +78,7 @@ import { err, trap } from 'lib/trap'
|
|||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { modelingMachineEvent } from 'editor/manager'
|
import { modelingMachineEvent } from 'editor/manager'
|
||||||
import { hasValidFilletSelection } from 'lang/modifyAst/addFillet'
|
import { hasValidFilletSelection } from 'lang/modifyAst/addFillet'
|
||||||
|
import { ExportIntent } from 'lang/std/engineConnection'
|
||||||
|
|
||||||
type MachineContext<T extends AnyStateMachine> = {
|
type MachineContext<T extends AnyStateMachine> = {
|
||||||
state: StateFrom<T>
|
state: StateFrom<T>
|
||||||
@ -351,8 +353,57 @@ export const ModelingMachineProvider = ({
|
|||||||
|
|
||||||
return {}
|
return {}
|
||||||
}),
|
}),
|
||||||
|
Make: async (_, event) => {
|
||||||
|
if (event.type !== 'Make' || TEST) return
|
||||||
|
// Check if we already have an export intent.
|
||||||
|
if (engineCommandManager.exportIntent) {
|
||||||
|
toast.error('Already exporting')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Set the export intent.
|
||||||
|
engineCommandManager.exportIntent = ExportIntent.Make
|
||||||
|
|
||||||
|
console.log('making', event.data)
|
||||||
|
// Set the current machine.
|
||||||
|
machineManager.currentMachine = event.data.machine
|
||||||
|
|
||||||
|
const format: Models['OutputFormat_type'] = {
|
||||||
|
type: 'stl',
|
||||||
|
coords: {
|
||||||
|
forward: {
|
||||||
|
axis: 'y',
|
||||||
|
direction: 'negative',
|
||||||
|
},
|
||||||
|
up: {
|
||||||
|
axis: 'z',
|
||||||
|
direction: 'positive',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
storage: 'ascii',
|
||||||
|
units: defaultUnit.current,
|
||||||
|
selection: { type: 'default_scene' },
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.promise(
|
||||||
|
exportFromEngine({
|
||||||
|
format: format,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
loading: 'Starting print...',
|
||||||
|
success: 'Started print successfully',
|
||||||
|
error: 'Error while starting print',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
'Engine export': async (_, event) => {
|
'Engine export': async (_, event) => {
|
||||||
if (event.type !== 'Export' || TEST) return
|
if (event.type !== 'Export' || TEST) return
|
||||||
|
if (engineCommandManager.exportIntent) {
|
||||||
|
toast.error('Already exporting')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Set the export intent.
|
||||||
|
engineCommandManager.exportIntent = ExportIntent.Save
|
||||||
|
|
||||||
console.log('exporting', event.data)
|
console.log('exporting', event.data)
|
||||||
const format = {
|
const format = {
|
||||||
...event.data,
|
...event.data,
|
||||||
|
@ -13,6 +13,7 @@ import { CustomIconName } from 'components/CustomIcon'
|
|||||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||||
import { IconDefinition } from '@fortawesome/free-solid-svg-icons'
|
import { IconDefinition } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { useKclContext } from 'lang/KclProvider'
|
import { useKclContext } from 'lang/KclProvider'
|
||||||
|
import { machineManager } from 'lib/machineManager'
|
||||||
|
|
||||||
interface ModelingSidebarProps {
|
interface ModelingSidebarProps {
|
||||||
paneOpacity: '' | 'opacity-20' | 'opacity-40'
|
paneOpacity: '' | 'opacity-20' | 'opacity-40'
|
||||||
@ -45,7 +46,30 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
|||||||
data: { name: 'Export', groupId: 'modeling' },
|
data: { name: 'Export', groupId: 'modeling' },
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'make',
|
||||||
|
title: 'Make part',
|
||||||
|
icon: 'printer3d',
|
||||||
|
iconClassName: '!p-0',
|
||||||
|
keybinding: 'Ctrl + Shift + M',
|
||||||
|
action: async () => {
|
||||||
|
commandBarSend({
|
||||||
|
type: 'Find and select command',
|
||||||
|
data: { name: 'Make', groupId: 'modeling' },
|
||||||
|
})
|
||||||
|
},
|
||||||
|
hide: () => machineManager.machineCount() === 0,
|
||||||
|
hideOnPlatform: 'web',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
const filteredActions: SidebarAction[] = sidebarActions.filter(
|
||||||
|
(action) =>
|
||||||
|
(!action.hide || (action.hide instanceof Function && !action.hide())) &&
|
||||||
|
(!action.hideOnPlatform ||
|
||||||
|
(isTauri()
|
||||||
|
? action.hideOnPlatform === 'web'
|
||||||
|
: action.hideOnPlatform === 'desktop'))
|
||||||
|
)
|
||||||
|
|
||||||
// // Filter out the debug panel if it's not supposed to be shown
|
// // Filter out the debug panel if it's not supposed to be shown
|
||||||
// // TODO: abstract out for allowing user to configure which panes to show
|
// // TODO: abstract out for allowing user to configure which panes to show
|
||||||
@ -135,23 +159,30 @@ export function ModelingSidebar({ paneOpacity }: ModelingSidebarProps) {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<hr className="w-full border-chalkboard-20 dark:border-chalkboard-80" />
|
{filteredActions.length > 0 && (
|
||||||
<ul id="sidebar-actions" className="w-fit p-2 flex flex-col gap-2">
|
<>
|
||||||
{sidebarActions.map((action) => (
|
<hr className="w-full border-chalkboard-20 dark:border-chalkboard-80" />
|
||||||
<ModelingPaneButton
|
<ul
|
||||||
key={action.id}
|
id="sidebar-actions"
|
||||||
paneConfig={{
|
className="w-fit p-2 flex flex-col gap-2"
|
||||||
id: action.id,
|
>
|
||||||
title: action.title,
|
{filteredActions.map((action) => (
|
||||||
icon: action.icon,
|
<ModelingPaneButton
|
||||||
keybinding: action.keybinding,
|
key={action.id}
|
||||||
iconClassName: action.iconClassName,
|
paneConfig={{
|
||||||
iconSize: 'md',
|
id: action.id,
|
||||||
}}
|
title: action.title,
|
||||||
onClick={action.action}
|
icon: action.icon,
|
||||||
/>
|
keybinding: action.keybinding,
|
||||||
))}
|
iconClassName: action.iconClassName,
|
||||||
</ul>
|
iconSize: 'md',
|
||||||
|
}}
|
||||||
|
onClick={action.action}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
<ul
|
<ul
|
||||||
id="pane-section"
|
id="pane-section"
|
||||||
@ -277,4 +308,5 @@ export type SidebarAction = {
|
|||||||
keybinding: string
|
keybinding: string
|
||||||
action: () => void
|
action: () => void
|
||||||
hideOnPlatform?: 'desktop' | 'web'
|
hideOnPlatform?: 'desktop' | 'web'
|
||||||
|
hide?: boolean | (() => boolean)
|
||||||
}
|
}
|
||||||
|
@ -103,8 +103,8 @@ export const NetworkHealthIndicator = () => {
|
|||||||
'rounded-sm ' + overallConnectionStateColor[overallState].bg
|
'rounded-sm ' + overallConnectionStateColor[overallState].bg
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Tooltip position="top-right">
|
<Tooltip position="top-right" wrapperClassName="ui-open:hidden">
|
||||||
Network Health ({NETWORK_HEALTH_TEXT[overallState]})
|
Network health ({NETWORK_HEALTH_TEXT[overallState]})
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
<Popover.Panel
|
<Popover.Panel
|
||||||
|
62
src/components/NetworkMachineIndicator.tsx
Normal file
62
src/components/NetworkMachineIndicator.tsx
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { Popover } from '@headlessui/react'
|
||||||
|
import Tooltip from './Tooltip'
|
||||||
|
import { machineManager } from 'lib/machineManager'
|
||||||
|
import { isTauri } from 'lib/isTauri'
|
||||||
|
import { CustomIcon } from './CustomIcon'
|
||||||
|
|
||||||
|
export const NetworkMachineIndicator = ({
|
||||||
|
className,
|
||||||
|
}: {
|
||||||
|
className?: string
|
||||||
|
}) => {
|
||||||
|
const machineCount = Object.keys(machineManager.machines).length
|
||||||
|
return isTauri() ? (
|
||||||
|
<Popover className="relative">
|
||||||
|
<Popover.Button
|
||||||
|
className={
|
||||||
|
'flex items-center p-0 border-none bg-transparent dark:bg-transparent relative ' +
|
||||||
|
(className || '')
|
||||||
|
}
|
||||||
|
data-testid="network-machine-toggle"
|
||||||
|
>
|
||||||
|
<CustomIcon name="printer3d" className="w-5 h-5" />
|
||||||
|
{machineCount > 0 && (
|
||||||
|
<p aria-hidden className="flex items-center justify-center text-xs">
|
||||||
|
{machineCount}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<Tooltip position="top-right" wrapperClassName="ui-open:hidden">
|
||||||
|
Network machines ({machineCount})
|
||||||
|
</Tooltip>
|
||||||
|
</Popover.Button>
|
||||||
|
<Popover.Panel
|
||||||
|
className="absolute right-0 left-auto bottom-full mb-1 w-64 flex flex-col gap-1 align-stretch bg-chalkboard-10 dark:bg-chalkboard-90 rounded shadow-lg border border-solid border-chalkboard-20/50 dark:border-chalkboard-80/50 text-sm"
|
||||||
|
data-testid="network-popover"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between p-2 rounded-t-sm bg-chalkboard-20 dark:bg-chalkboard-80">
|
||||||
|
<h2 className="text-sm font-sans font-normal">Network machines</h2>
|
||||||
|
<p
|
||||||
|
data-testid="network"
|
||||||
|
className="font-bold text-xs uppercase px-2 py-1 rounded-sm"
|
||||||
|
>
|
||||||
|
{machineCount}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{machineCount > 0 && (
|
||||||
|
<ul className="divide-y divide-chalkboard-20 dark:divide-chalkboard-80">
|
||||||
|
{Object.entries(machineManager.machines).map(
|
||||||
|
([hostname, machine]) => (
|
||||||
|
<li key={hostname} className={'px-2 py-4 gap-1 last:mb-0 '}>
|
||||||
|
<p className="">{machine.model || machine.manufacturer}</p>
|
||||||
|
<p className="text-chalkboard-60 dark:text-chalkboard-50 text-xs">
|
||||||
|
Hostname {hostname}
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</Popover.Panel>
|
||||||
|
</Popover>
|
||||||
|
) : null
|
||||||
|
}
|
@ -12,6 +12,7 @@ import { useCommandsContext } from 'hooks/useCommandsContext'
|
|||||||
import { CustomIcon } from './CustomIcon'
|
import { CustomIcon } from './CustomIcon'
|
||||||
import { useLspContext } from './LspProvider'
|
import { useLspContext } from './LspProvider'
|
||||||
import { engineCommandManager } from 'lib/singletons'
|
import { engineCommandManager } from 'lib/singletons'
|
||||||
|
import { machineManager } from 'lib/machineManager'
|
||||||
import usePlatform from 'hooks/usePlatform'
|
import usePlatform from 'hooks/usePlatform'
|
||||||
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
|
import { useAbsoluteFilePath } from 'hooks/useAbsoluteFilePath'
|
||||||
import Tooltip from './Tooltip'
|
import Tooltip from './Tooltip'
|
||||||
@ -90,12 +91,14 @@ function ProjectMenuPopover({
|
|||||||
const { commandBarState, commandBarSend } = useCommandsContext()
|
const { commandBarState, commandBarSend } = useCommandsContext()
|
||||||
const { onProjectClose } = useLspContext()
|
const { onProjectClose } = useLspContext()
|
||||||
const exportCommandInfo = { name: 'Export', groupId: 'modeling' }
|
const exportCommandInfo = { name: 'Export', groupId: 'modeling' }
|
||||||
|
const makeCommandInfo = { name: 'Make', groupId: 'modeling' }
|
||||||
const findCommand = (obj: { name: string; groupId: string }) =>
|
const findCommand = (obj: { name: string; groupId: string }) =>
|
||||||
Boolean(
|
Boolean(
|
||||||
commandBarState.context.commands.find(
|
commandBarState.context.commands.find(
|
||||||
(c) => c.name === obj.name && c.groupId === obj.groupId
|
(c) => c.name === obj.name && c.groupId === obj.groupId
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
const machineCount = machineManager.machineCount()
|
||||||
|
|
||||||
// We filter this memoized list so that no orphan "break" elements are rendered.
|
// We filter this memoized list so that no orphan "break" elements are rendered.
|
||||||
const projectMenuItems = useMemo<(ActionButtonProps | 'break')[]>(
|
const projectMenuItems = useMemo<(ActionButtonProps | 'break')[]>(
|
||||||
@ -144,6 +147,32 @@ function ProjectMenuPopover({
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
'break',
|
'break',
|
||||||
|
{
|
||||||
|
id: 'make',
|
||||||
|
Element: 'button',
|
||||||
|
className: !isTauri() ? 'hidden' : '',
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<span>Make current part</span>
|
||||||
|
{!findCommand(makeCommandInfo) && (
|
||||||
|
<Tooltip
|
||||||
|
position="right"
|
||||||
|
wrapperClassName="!max-w-none min-w-fit"
|
||||||
|
>
|
||||||
|
Awaiting engine connection
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
disabled: !findCommand(makeCommandInfo) || machineCount === 0,
|
||||||
|
onClick: () => {
|
||||||
|
commandBarSend({
|
||||||
|
type: 'Find and select command',
|
||||||
|
data: makeCommandInfo,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'break',
|
||||||
{
|
{
|
||||||
id: 'go-home',
|
id: 'go-home',
|
||||||
Element: 'button',
|
Element: 'button',
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 373 KiB After Width: | Height: | Size: 374 KiB |
@ -13,6 +13,8 @@ import {
|
|||||||
createArtifactGraph,
|
createArtifactGraph,
|
||||||
} from 'lang/std/artifactGraph'
|
} from 'lang/std/artifactGraph'
|
||||||
import { useModelingContext } from 'hooks/useModelingContext'
|
import { useModelingContext } from 'hooks/useModelingContext'
|
||||||
|
import { exportMake } from 'lib/exportMake'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
|
||||||
// TODO(paultag): This ought to be tweakable.
|
// TODO(paultag): This ought to be tweakable.
|
||||||
const pingIntervalMs = 10000
|
const pingIntervalMs = 10000
|
||||||
@ -30,6 +32,11 @@ interface NewTrackArgs {
|
|||||||
mediaStream: MediaStream
|
mediaStream: MediaStream
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ExportIntent {
|
||||||
|
Save = 'save',
|
||||||
|
Make = 'make',
|
||||||
|
}
|
||||||
|
|
||||||
type ClientMetrics = Models['ClientMetrics_type']
|
type ClientMetrics = Models['ClientMetrics_type']
|
||||||
|
|
||||||
interface WebRTCClientMetrics extends ClientMetrics {
|
interface WebRTCClientMetrics extends ClientMetrics {
|
||||||
@ -1153,6 +1160,12 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
reject: (reason: any) => void
|
reject: (reason: any) => void
|
||||||
commandId: string
|
commandId: string
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Export intent traxcks the intent of the export. If it is null there is no
|
||||||
|
* export in progress. Otherwise it is an enum value of the intent.
|
||||||
|
* Another export cannot be started if one is already in progress.
|
||||||
|
*/
|
||||||
|
private _exportIntent: ExportIntent | null = null
|
||||||
_commandLogCallBack: (command: CommandLog[]) => void = () => {}
|
_commandLogCallBack: (command: CommandLog[]) => void = () => {}
|
||||||
resolveReady = () => {}
|
resolveReady = () => {}
|
||||||
/** Folks should realize that wait for ready does not get called _everytime_
|
/** Folks should realize that wait for ready does not get called _everytime_
|
||||||
@ -1205,6 +1218,14 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
modelingSend: ReturnType<typeof useModelingContext>['send'] =
|
modelingSend: ReturnType<typeof useModelingContext>['send'] =
|
||||||
(() => {}) as any
|
(() => {}) as any
|
||||||
|
|
||||||
|
set exportIntent(intent: ExportIntent | null) {
|
||||||
|
this._exportIntent = intent
|
||||||
|
}
|
||||||
|
|
||||||
|
get exportIntent() {
|
||||||
|
return this._exportIntent
|
||||||
|
}
|
||||||
|
|
||||||
start({
|
start({
|
||||||
disableWebRTC = false,
|
disableWebRTC = false,
|
||||||
setMediaStream,
|
setMediaStream,
|
||||||
@ -1382,9 +1403,36 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
// because in all other cases we send JSON strings. But in the case of
|
// because in all other cases we send JSON strings. But in the case of
|
||||||
// export we send a binary blob.
|
// export we send a binary blob.
|
||||||
// Pass this to our export function.
|
// Pass this to our export function.
|
||||||
exportSave(event.data).then(() => {
|
if (this.exportIntent === null) {
|
||||||
this.pendingExport?.resolve(null)
|
toast.error(
|
||||||
}, this.pendingExport?.reject)
|
'Export intent was not set, but export data was received'
|
||||||
|
)
|
||||||
|
console.error(
|
||||||
|
'Export intent was not set, but export data was received'
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.exportIntent) {
|
||||||
|
case ExportIntent.Save: {
|
||||||
|
exportSave(event.data).then(() => {
|
||||||
|
this.pendingExport?.resolve(null)
|
||||||
|
}, this.pendingExport?.reject)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case ExportIntent.Make: {
|
||||||
|
exportMake(event.data).then((result) => {
|
||||||
|
if (result) {
|
||||||
|
this.pendingExport?.resolve(null)
|
||||||
|
} else {
|
||||||
|
this.pendingExport?.reject('Failed to make export')
|
||||||
|
}
|
||||||
|
}, this.pendingExport?.reject)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set the export intent back to null.
|
||||||
|
this.exportIntent = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1688,7 +1736,13 @@ export class EngineCommandManager extends EventTarget {
|
|||||||
return Promise.resolve(null)
|
return Promise.resolve(null)
|
||||||
} else if (cmd.type === 'export') {
|
} else if (cmd.type === 'export') {
|
||||||
const promise = new Promise<null>((resolve, reject) => {
|
const promise = new Promise<null>((resolve, reject) => {
|
||||||
this.pendingExport = { resolve, reject, commandId: command.cmd_id }
|
this.pendingExport = {
|
||||||
|
resolve,
|
||||||
|
reject: () => {
|
||||||
|
this.exportIntent = null
|
||||||
|
},
|
||||||
|
commandId: command.cmd_id,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
this.engineConnection?.send(command)
|
this.engineConnection?.send(command)
|
||||||
return promise
|
return promise
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { Models } from '@kittycad/lib'
|
import { Models } from '@kittycad/lib'
|
||||||
import { StateMachineCommandSetConfig, KclCommandValue } from 'lib/commandTypes'
|
import { StateMachineCommandSetConfig, KclCommandValue } from 'lib/commandTypes'
|
||||||
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
|
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
|
||||||
|
import { components } from 'lib/machine-api'
|
||||||
import { Selections } from 'lib/selections'
|
import { Selections } from 'lib/selections'
|
||||||
|
import { machineManager } from 'lib/machineManager'
|
||||||
import { modelingMachine, SketchTool } from 'machines/modelingMachine'
|
import { modelingMachine, SketchTool } from 'machines/modelingMachine'
|
||||||
|
|
||||||
type OutputFormat = Models['OutputFormat_type']
|
type OutputFormat = Models['OutputFormat_type']
|
||||||
@ -22,6 +24,9 @@ export type ModelingCommandSchema = {
|
|||||||
type: OutputTypeKey
|
type: OutputTypeKey
|
||||||
storage?: StorageUnion
|
storage?: StorageUnion
|
||||||
}
|
}
|
||||||
|
Make: {
|
||||||
|
machine: components['schemas']['Machine']
|
||||||
|
}
|
||||||
Extrude: {
|
Extrude: {
|
||||||
selection: Selections // & { type: 'face' } would be cool to lock that down
|
selection: Selections // & { type: 'face' } would be cool to lock that down
|
||||||
// result: (typeof EXTRUSION_RESULTS)[number]
|
// result: (typeof EXTRUSION_RESULTS)[number]
|
||||||
@ -160,6 +165,36 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig<
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Make: {
|
||||||
|
hide: 'web',
|
||||||
|
displayName: 'Make',
|
||||||
|
description:
|
||||||
|
'Export the current part and send to a 3D printer on the network.',
|
||||||
|
icon: 'printer3d',
|
||||||
|
needsReview: true,
|
||||||
|
args: {
|
||||||
|
machine: {
|
||||||
|
inputType: 'options',
|
||||||
|
required: true,
|
||||||
|
valueSummary: (machine: components['schemas']['Machine']) =>
|
||||||
|
machine.model || machine.manufacturer,
|
||||||
|
options: () => {
|
||||||
|
return Object.entries(machineManager.machines).map(
|
||||||
|
([hostname, machine]) => ({
|
||||||
|
name: `${machine.model || machine.manufacturer}, ${hostname}`,
|
||||||
|
isCurrent: false,
|
||||||
|
value: machine as components['schemas']['Machine'],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
defaultValue: () => {
|
||||||
|
return Object.values(
|
||||||
|
machineManager.machines
|
||||||
|
)[0] as components['schemas']['Machine']
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
Extrude: {
|
Extrude: {
|
||||||
description: 'Pull a sketch into 3D along its normal or perpendicular.',
|
description: 'Pull a sketch into 3D along its normal or perpendicular.',
|
||||||
icon: 'extrude',
|
icon: 'extrude',
|
||||||
|
@ -111,6 +111,10 @@ export type CommandArgumentConfig<
|
|||||||
machineContext?: C
|
machineContext?: C
|
||||||
) => boolean)
|
) => boolean)
|
||||||
skip?: boolean
|
skip?: boolean
|
||||||
|
/** For showing a summary display of the current value, such as in
|
||||||
|
* the command bar's header
|
||||||
|
*/
|
||||||
|
valueSummary?: (value: OutputType) => string
|
||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
inputType: 'options'
|
inputType: 'options'
|
||||||
@ -172,6 +176,10 @@ export type CommandArgument<
|
|||||||
) => boolean)
|
) => boolean)
|
||||||
skip?: boolean
|
skip?: boolean
|
||||||
machineActor: InterpreterFrom<T>
|
machineActor: InterpreterFrom<T>
|
||||||
|
/** For showing a summary display of the current value, such as in
|
||||||
|
* the command bar's header
|
||||||
|
*/
|
||||||
|
valueSummary?: (value: OutputType) => string
|
||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
inputType: Extract<CommandInputType, 'options'>
|
inputType: Extract<CommandInputType, 'options'>
|
||||||
|
@ -52,17 +52,22 @@ export function createMachineCommand<
|
|||||||
return null
|
return null
|
||||||
} else if (commandConfig instanceof Array) {
|
} else if (commandConfig instanceof Array) {
|
||||||
return commandConfig
|
return commandConfig
|
||||||
.map((config) =>
|
.map((config) => {
|
||||||
createMachineCommand({
|
const recursiveCommandBarConfig: Partial<
|
||||||
|
StateMachineCommandSetConfig<T, S>
|
||||||
|
> = {
|
||||||
|
[type]: config,
|
||||||
|
}
|
||||||
|
return createMachineCommand({
|
||||||
groupId,
|
groupId,
|
||||||
type,
|
type,
|
||||||
state,
|
state,
|
||||||
send,
|
send,
|
||||||
actor,
|
actor,
|
||||||
commandBarConfig: { [type]: config },
|
commandBarConfig: recursiveCommandBarConfig,
|
||||||
onCancel,
|
onCancel,
|
||||||
})
|
})
|
||||||
)
|
})
|
||||||
.filter((c) => c !== null) as Command<T, typeof type, S[typeof type]>[]
|
.filter((c) => c !== null) as Command<T, typeof type, S[typeof type]>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,6 +150,7 @@ export function buildCommandArgument<
|
|||||||
required: arg.required,
|
required: arg.required,
|
||||||
skip: arg.skip,
|
skip: arg.skip,
|
||||||
machineActor,
|
machineActor,
|
||||||
|
valueSummary: arg.valueSummary,
|
||||||
} satisfies Omit<CommandArgument<O, T>, 'inputType'>
|
} satisfies Omit<CommandArgument<O, T>, 'inputType'>
|
||||||
|
|
||||||
if (arg.inputType === 'options') {
|
if (arg.inputType === 'options') {
|
||||||
|
74
src/lib/exportMake.ts
Normal file
74
src/lib/exportMake.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { deserialize_files } from 'wasm-lib/pkg/wasm_lib'
|
||||||
|
import { machineManager } from './machineManager'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
import { components } from './machine-api'
|
||||||
|
import ModelingAppFile from './modelingAppFile'
|
||||||
|
|
||||||
|
// Make files locally from an export call.
|
||||||
|
export async function exportMake(data: ArrayBuffer): Promise<Response | null> {
|
||||||
|
if (machineManager.machineCount() === 0) {
|
||||||
|
console.error('No machines available')
|
||||||
|
toast.error('No machines available')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const machineApiIp = machineManager.machineApiIp
|
||||||
|
if (!machineApiIp) {
|
||||||
|
console.error('No machine api ip available')
|
||||||
|
toast.error('No machine api ip available')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentMachine = machineManager.currentMachine
|
||||||
|
if (!currentMachine) {
|
||||||
|
console.error('No current machine available')
|
||||||
|
toast.error('No current machine available')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
let machineId = null
|
||||||
|
if ('id' in currentMachine) {
|
||||||
|
machineId = currentMachine.id
|
||||||
|
} else if ('hostname' in currentMachine && currentMachine.hostname) {
|
||||||
|
machineId = currentMachine.hostname
|
||||||
|
} else if ('ip' in currentMachine && currentMachine.ip) {
|
||||||
|
machineId = currentMachine.ip
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!machineId) {
|
||||||
|
console.error('No machine id available', currentMachine)
|
||||||
|
toast.error('No machine id available')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const params: components['schemas']['PrintParameters'] = {
|
||||||
|
machine_id: machineId,
|
||||||
|
job_name: 'Exported Job', // TODO: make this the project name.
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
console.log('params', params)
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('params', JSON.stringify(params))
|
||||||
|
let files: ModelingAppFile[] = deserialize_files(new Uint8Array(data))
|
||||||
|
let file = files[0]
|
||||||
|
const fileBlob = new Blob([new Uint8Array(file.contents)], {
|
||||||
|
type: 'text/plain',
|
||||||
|
})
|
||||||
|
formData.append('file', fileBlob, file.name)
|
||||||
|
console.log('formData', formData)
|
||||||
|
|
||||||
|
const response = await fetch('http://' + machineApiIp + '/print', {
|
||||||
|
mode: 'no-cors',
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('response', response)
|
||||||
|
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error exporting', error)
|
||||||
|
toast.error('Error exporting')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
@ -5,11 +5,7 @@ import { save } from '@tauri-apps/plugin-dialog'
|
|||||||
import { writeFile } from '@tauri-apps/plugin-fs'
|
import { writeFile } from '@tauri-apps/plugin-fs'
|
||||||
|
|
||||||
import JSZip from 'jszip'
|
import JSZip from 'jszip'
|
||||||
|
import ModelingAppFile from './modelingAppFile'
|
||||||
interface ModelingAppFile {
|
|
||||||
name: string
|
|
||||||
contents: number[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const save_ = async (file: ModelingAppFile) => {
|
const save_ = async (file: ModelingAppFile) => {
|
||||||
try {
|
try {
|
||||||
@ -51,7 +47,7 @@ const save_ = async (file: ModelingAppFile) => {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// TODO: do something real with the error.
|
// TODO: do something real with the error.
|
||||||
console.log('export error', e)
|
console.error('export error', e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
925
src/lib/machine-api.d.ts
vendored
Normal file
925
src/lib/machine-api.d.ts
vendored
Normal file
@ -0,0 +1,925 @@
|
|||||||
|
/**
|
||||||
|
* This file was auto-generated by openapi-typescript.
|
||||||
|
* Do not make direct changes to the file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface paths {
|
||||||
|
'/': {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
/** Return the OpenAPI schema in JSON format. */
|
||||||
|
get: operations['api_get_schema']
|
||||||
|
put?: never
|
||||||
|
post?: never
|
||||||
|
delete?: never
|
||||||
|
options?: never
|
||||||
|
head?: never
|
||||||
|
patch?: never
|
||||||
|
trace?: never
|
||||||
|
}
|
||||||
|
'/machines': {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
/** List available machines and their statuses */
|
||||||
|
get: operations['get_machines']
|
||||||
|
put?: never
|
||||||
|
post?: never
|
||||||
|
delete?: never
|
||||||
|
options?: never
|
||||||
|
head?: never
|
||||||
|
patch?: never
|
||||||
|
trace?: never
|
||||||
|
}
|
||||||
|
'/machines/{id}': {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
/** Get the status of a specific machine */
|
||||||
|
get: operations['get_machine']
|
||||||
|
put?: never
|
||||||
|
post?: never
|
||||||
|
delete?: never
|
||||||
|
options?: never
|
||||||
|
head?: never
|
||||||
|
patch?: never
|
||||||
|
trace?: never
|
||||||
|
}
|
||||||
|
'/ping': {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
/** Return pong. */
|
||||||
|
get: operations['ping']
|
||||||
|
put?: never
|
||||||
|
post?: never
|
||||||
|
delete?: never
|
||||||
|
options?: never
|
||||||
|
head?: never
|
||||||
|
patch?: never
|
||||||
|
trace?: never
|
||||||
|
}
|
||||||
|
'/print': {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
get?: never
|
||||||
|
put?: never
|
||||||
|
/** Print a given file. File must be a sliceable 3D model. */
|
||||||
|
post: operations['print_file']
|
||||||
|
delete?: never
|
||||||
|
options?: never
|
||||||
|
head?: never
|
||||||
|
patch?: never
|
||||||
|
trace?: never
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export type webhooks = Record<string, never>
|
||||||
|
export interface components {
|
||||||
|
schemas: {
|
||||||
|
/** @description The type of accessory. */
|
||||||
|
AccessoryType: 'none'
|
||||||
|
/** @description Error information from a response. */
|
||||||
|
Error: {
|
||||||
|
error_code?: string
|
||||||
|
message: string
|
||||||
|
request_id: string
|
||||||
|
}
|
||||||
|
/** @description An info command. */
|
||||||
|
Info: {
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'get_version'
|
||||||
|
/** @description The info module. */
|
||||||
|
module: components['schemas']['InfoModule'][]
|
||||||
|
/** @description The reason of the info command. */
|
||||||
|
reason?: components['schemas']['Reason'] | null
|
||||||
|
/** @description The result of the info command. */
|
||||||
|
result: components['schemas']['Result']
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description An info module. */
|
||||||
|
InfoModule: {
|
||||||
|
/** @description The hardware version. */
|
||||||
|
hw_ver: string
|
||||||
|
/** @description The loader version. */
|
||||||
|
loader_ver?: string | null
|
||||||
|
/** @description The module name. */
|
||||||
|
name: string
|
||||||
|
/** @description The ota version. */
|
||||||
|
ota_ver?: string | null
|
||||||
|
/** @description The project name. */
|
||||||
|
project_name?: string | null
|
||||||
|
/** @description The serial number. */
|
||||||
|
sn: string
|
||||||
|
/** @description The software version. */
|
||||||
|
sw_ver: string
|
||||||
|
}
|
||||||
|
/** @description The mode for the led. */
|
||||||
|
LedMode: 'on' | 'off' | 'flashing'
|
||||||
|
/** @description The node for the led. */
|
||||||
|
LedNode: 'chamber_light' | 'work_light'
|
||||||
|
/** @description Details for a 3d printer connected over USB. */
|
||||||
|
Machine:
|
||||||
|
| {
|
||||||
|
id: string
|
||||||
|
manufacturer: string
|
||||||
|
model: string
|
||||||
|
port: string
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'UsbPrinter'
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
/** @description The hostname of the printer. */
|
||||||
|
hostname?: string | null
|
||||||
|
/**
|
||||||
|
* Format: ip
|
||||||
|
* @description The IP address of the printer.
|
||||||
|
*/
|
||||||
|
ip: string
|
||||||
|
/** @description The manufacturer of the printer. */
|
||||||
|
manufacturer: components['schemas']['NetworkPrinterManufacturer']
|
||||||
|
/** @description The model of the printer. */
|
||||||
|
model?: string | null
|
||||||
|
/**
|
||||||
|
* Format: uint16
|
||||||
|
* @description The port of the printer.
|
||||||
|
*/
|
||||||
|
port?: number | null
|
||||||
|
/** @description The serial number of the printer. */
|
||||||
|
serial?: string | null
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'NetworkPrinter'
|
||||||
|
}
|
||||||
|
/** @description A message from a machine. */
|
||||||
|
Message:
|
||||||
|
| {
|
||||||
|
UsbPrinter: components['schemas']['Message2']
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
NetworkPrinter: components['schemas']['Message3']
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @description A message from the printer.
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
Message2: 'ok'
|
||||||
|
/** @description A message from the printer. */
|
||||||
|
Message3:
|
||||||
|
| {
|
||||||
|
Bambu: components['schemas']['Message4']
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
Formlabs: Record<string, never>
|
||||||
|
}
|
||||||
|
/** @description A message from/to the printer. */
|
||||||
|
Message4:
|
||||||
|
| {
|
||||||
|
print: components['schemas']['Print']
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
info: components['schemas']['Info']
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
system: components['schemas']['System']
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
json: unknown
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
unknown: string | null
|
||||||
|
}
|
||||||
|
/** @description Network printer manufacturer. */
|
||||||
|
NetworkPrinterManufacturer: 'Bambu' | 'Formlabs'
|
||||||
|
/** @description A nozzle type. */
|
||||||
|
NozzleType: 'hardened_steel' | 'stainless_steel'
|
||||||
|
/** @description The response from the `/ping` endpoint. */
|
||||||
|
Pong: {
|
||||||
|
/** @description The pong response. */
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
/** @description A print command. */
|
||||||
|
Print:
|
||||||
|
| ({
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'ams_control'
|
||||||
|
/** @description The param. */
|
||||||
|
param?: string | null
|
||||||
|
/** @description The reason for the message. */
|
||||||
|
reason: components['schemas']['Reason']
|
||||||
|
/** @description The result of the command. */
|
||||||
|
result: components['schemas']['Result']
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
| ({
|
||||||
|
/** @description The ams. */
|
||||||
|
ams?: components['schemas']['PrintAms'] | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The ams rfid status.
|
||||||
|
*/
|
||||||
|
ams_rfid_status?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The ams status.
|
||||||
|
*/
|
||||||
|
ams_status?: number | null
|
||||||
|
/** @description The aux part fan. */
|
||||||
|
aux_part_fan?: boolean | null
|
||||||
|
/**
|
||||||
|
* Format: double
|
||||||
|
* @description The target bed temperature.
|
||||||
|
*/
|
||||||
|
bed_target_temper?: number | null
|
||||||
|
/**
|
||||||
|
* Format: double
|
||||||
|
* @description The bed temperature.
|
||||||
|
*/
|
||||||
|
bed_temper?: number | null
|
||||||
|
/** @description The big fan 1 speed. */
|
||||||
|
big_fan1_speed?: string | null
|
||||||
|
/** @description The big fan 2 speed. */
|
||||||
|
big_fan2_speed?: string | null
|
||||||
|
/**
|
||||||
|
* Format: double
|
||||||
|
* @description The chamber temperature.
|
||||||
|
*/
|
||||||
|
chamber_temper?: number | null
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'push_status'
|
||||||
|
/** @description The cooling fan speed. */
|
||||||
|
cooling_fan_speed?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The fan gear.
|
||||||
|
*/
|
||||||
|
fan_gear?: number | null
|
||||||
|
/** @description Force upgrade? */
|
||||||
|
force_upgrade?: boolean | null
|
||||||
|
/** @description The gcode file. */
|
||||||
|
gcode_file?: string | null
|
||||||
|
/** @description The gcode file prepare percent. */
|
||||||
|
gcode_file_prepare_percent?: string | null
|
||||||
|
/** @description The gcode state. */
|
||||||
|
gcode_state?: string | null
|
||||||
|
/** @description The heatbreak fan speed. */
|
||||||
|
heatbreak_fan_speed?: string | null
|
||||||
|
/** @description The hms. */
|
||||||
|
hms?: unknown[] | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The home flag.
|
||||||
|
*/
|
||||||
|
home_flag?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The hw switch state.
|
||||||
|
*/
|
||||||
|
hw_switch_state?: number | null
|
||||||
|
/** @description The ipcam. */
|
||||||
|
ipcam?: components['schemas']['PrintIpcam'] | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The layer num.
|
||||||
|
*/
|
||||||
|
layer_num?: number | null
|
||||||
|
/** @description The lifecycle. */
|
||||||
|
lifecycle?: string | null
|
||||||
|
/** @description The lights report. */
|
||||||
|
lights_report?: components['schemas']['PrintLightsReport'][] | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The percentage of the print completed.
|
||||||
|
*/
|
||||||
|
mc_percent?: number | null
|
||||||
|
/** @description The mc print line number. */
|
||||||
|
mc_print_line_number?: string | null
|
||||||
|
/** @description The print stage. */
|
||||||
|
mc_print_stage?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The mc print sub stage.
|
||||||
|
*/
|
||||||
|
mc_print_sub_stage?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The remaining time of the print.
|
||||||
|
*/
|
||||||
|
mc_remaining_time?: number | null
|
||||||
|
/** @description The mess production state. */
|
||||||
|
mess_production_state?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The message.
|
||||||
|
*/
|
||||||
|
msg?: number | null
|
||||||
|
/** @description The nozzle diameter. */
|
||||||
|
nozzle_diameter?: string | null
|
||||||
|
/**
|
||||||
|
* Format: double
|
||||||
|
* @description The target nozzle temperature.
|
||||||
|
*/
|
||||||
|
nozzle_target_temper?: number | null
|
||||||
|
/**
|
||||||
|
* Format: double
|
||||||
|
* @description The nozzle temperature.
|
||||||
|
*/
|
||||||
|
nozzle_temper?: number | null
|
||||||
|
/** @description The nozzle type. */
|
||||||
|
nozzle_type?: components['schemas']['NozzleType'] | null
|
||||||
|
/** @description Online status. */
|
||||||
|
online?: components['schemas']['PrintOnline'] | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The print error.
|
||||||
|
*/
|
||||||
|
print_error?: number | null
|
||||||
|
/** @description The print type. */
|
||||||
|
print_type?: string | null
|
||||||
|
/** @description The profile id. */
|
||||||
|
profile_id?: string | null
|
||||||
|
/** @description The project id. */
|
||||||
|
project_id?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The queue est.
|
||||||
|
*/
|
||||||
|
queue_est?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The queue number.
|
||||||
|
*/
|
||||||
|
queue_number?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The queue sts.
|
||||||
|
*/
|
||||||
|
queue_sts?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The queue total.
|
||||||
|
*/
|
||||||
|
queue_total?: number | null
|
||||||
|
/** @description The s obj. */
|
||||||
|
s_obj?: unknown[] | null
|
||||||
|
/** @description Sdcard? */
|
||||||
|
sdcard?: boolean | null
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The spd lvl.
|
||||||
|
*/
|
||||||
|
spd_lvl?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The spd mag.
|
||||||
|
*/
|
||||||
|
spd_mag?: number | null
|
||||||
|
/** @description The stg. */
|
||||||
|
stg?: unknown[] | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The stg cur.
|
||||||
|
*/
|
||||||
|
stg_cur?: number | null
|
||||||
|
/** @description The subtask id. */
|
||||||
|
subtask_id?: string | null
|
||||||
|
/** @description The subtask name. */
|
||||||
|
subtask_name?: string | null
|
||||||
|
/** @description The task id. */
|
||||||
|
task_id?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The total layer num.
|
||||||
|
*/
|
||||||
|
total_layer_num?: number | null
|
||||||
|
/** @description The upgrade state. */
|
||||||
|
upgrade_state?: components['schemas']['PrintUpgradeState'] | null
|
||||||
|
/** @description The upload. */
|
||||||
|
upload?: components['schemas']['PrintUpload'] | null
|
||||||
|
/** @description The tray. */
|
||||||
|
vt_tray?: components['schemas']['PrintTray'] | null
|
||||||
|
/** @description The wifi signal. */
|
||||||
|
wifi_signal?: string | null
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
| ({
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'gcode_line'
|
||||||
|
/** @description The gcode line. */
|
||||||
|
param?: string | null
|
||||||
|
/** @description The reason for the message. */
|
||||||
|
reason: components['schemas']['Reason']
|
||||||
|
/** @description The result of the command. */
|
||||||
|
result: components['schemas']['Result']
|
||||||
|
/** @description The return code. */
|
||||||
|
return_code?: string | null
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The source.
|
||||||
|
*/
|
||||||
|
source?: number | null
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
| ({
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'project_file'
|
||||||
|
/** @description The gcode file. */
|
||||||
|
gcode_file?: string | null
|
||||||
|
/** @description The profile id. */
|
||||||
|
profile_id: string
|
||||||
|
/** @description The project id. */
|
||||||
|
project_id: string
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
/** @description The subtask id. */
|
||||||
|
subtask_id: string
|
||||||
|
/** @description The subtask name. */
|
||||||
|
subtask_name: string
|
||||||
|
/** @description The task id. */
|
||||||
|
task_id: string
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
| ({
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'pause'
|
||||||
|
/** @description The reason for the message. */
|
||||||
|
reason: components['schemas']['Reason']
|
||||||
|
/** @description The result of the command. */
|
||||||
|
result: components['schemas']['Result']
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
| ({
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'resume'
|
||||||
|
/** @description The reason for the message. */
|
||||||
|
reason: components['schemas']['Reason']
|
||||||
|
/** @description The result of the command. */
|
||||||
|
result: components['schemas']['Result']
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
| ({
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'stop'
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
| ({
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'extrusion_cali_get'
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
/** @description The print ams. */
|
||||||
|
PrintAms: {
|
||||||
|
/** @description The ams. */
|
||||||
|
ams?: components['schemas']['PrintAmsData'][] | null
|
||||||
|
/** @description The ams exist bits. */
|
||||||
|
ams_exist_bits?: string | null
|
||||||
|
/** @description The insert flag. */
|
||||||
|
insert_flag?: boolean | null
|
||||||
|
/** @description The power on flag. */
|
||||||
|
power_on_flag?: boolean | null
|
||||||
|
/** @description The tray exist bits. */
|
||||||
|
tray_exist_bits?: string | null
|
||||||
|
/** @description The tray is bbl bits. */
|
||||||
|
tray_is_bbl_bits?: string | null
|
||||||
|
/** @description The tray now. */
|
||||||
|
tray_now?: string | null
|
||||||
|
/** @description The tray pre. */
|
||||||
|
tray_pre?: string | null
|
||||||
|
/** @description The tray read done bits. */
|
||||||
|
tray_read_done_bits?: string | null
|
||||||
|
/** @description The tray reading bits. */
|
||||||
|
tray_reading_bits?: string | null
|
||||||
|
/** @description The tray tar. */
|
||||||
|
tray_tar?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The version.
|
||||||
|
*/
|
||||||
|
version?: number | null
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description The print ams data. */
|
||||||
|
PrintAmsData: {
|
||||||
|
/** @description The humidity. */
|
||||||
|
humidity: string
|
||||||
|
/** @description The id. */
|
||||||
|
id: string
|
||||||
|
/** @description The temperature. */
|
||||||
|
temp: string
|
||||||
|
/** @description The tray. */
|
||||||
|
tray: components['schemas']['PrintTray'][]
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description The print ipcam. */
|
||||||
|
PrintIpcam: {
|
||||||
|
/** @description The ipcam dev. */
|
||||||
|
ipcam_dev?: string | null
|
||||||
|
/** @description The ipcam record. */
|
||||||
|
ipcam_record?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The mode bits.
|
||||||
|
*/
|
||||||
|
mode_bits?: number | null
|
||||||
|
/** @description The timelapse. */
|
||||||
|
timelapse?: string | null
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description The response from the `/print` endpoint. */
|
||||||
|
PrintJobResponse: {
|
||||||
|
/** @description The job id used for this print. */
|
||||||
|
job_id: string
|
||||||
|
/** @description The parameters used for this print. */
|
||||||
|
parameters: components['schemas']['PrintParameters']
|
||||||
|
}
|
||||||
|
/** @description A print lights report. */
|
||||||
|
PrintLightsReport: {
|
||||||
|
/** @description The mode. */
|
||||||
|
mode: components['schemas']['LedMode']
|
||||||
|
/** @description The node. */
|
||||||
|
node: components['schemas']['LedNode']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description The print online. */
|
||||||
|
PrintOnline: {
|
||||||
|
/** @description The ahb. */
|
||||||
|
ahb: boolean
|
||||||
|
/** @description The rfid. */
|
||||||
|
rfid?: boolean | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The version.
|
||||||
|
*/
|
||||||
|
version: number
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description Parameters for printing. */
|
||||||
|
PrintParameters: {
|
||||||
|
/** @description The name for the job. */
|
||||||
|
job_name: string
|
||||||
|
/** @description The machine id to print to. */
|
||||||
|
machine_id: string
|
||||||
|
}
|
||||||
|
/** @description The print tray. */
|
||||||
|
PrintTray: {
|
||||||
|
/** @description The bed temperature. */
|
||||||
|
bed_temp?: string | null
|
||||||
|
/** @description The bed temperature type. */
|
||||||
|
bed_temp_type?: string | null
|
||||||
|
/** @description The id. */
|
||||||
|
id: string
|
||||||
|
/**
|
||||||
|
* Format: double
|
||||||
|
* @description The tray k.
|
||||||
|
*/
|
||||||
|
k?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The tray n.
|
||||||
|
*/
|
||||||
|
n?: number | null
|
||||||
|
/** @description The nozzle temperature max. */
|
||||||
|
nozzle_temp_max?: string | null
|
||||||
|
/** @description The nozzle temperature min. */
|
||||||
|
nozzle_temp_min?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The tray remain.
|
||||||
|
*/
|
||||||
|
remain?: number | null
|
||||||
|
/** @description The tag uid. */
|
||||||
|
tag_uid?: string | null
|
||||||
|
/** @description The tray color. */
|
||||||
|
tray_color?: string | null
|
||||||
|
/** @description The tray diameter. */
|
||||||
|
tray_diameter?: string | null
|
||||||
|
/** @description The tray id name. */
|
||||||
|
tray_id_name?: string | null
|
||||||
|
/** @description The tray info index. */
|
||||||
|
tray_info_idx?: string | null
|
||||||
|
/** @description The tray sub brands. */
|
||||||
|
tray_sub_brands?: string | null
|
||||||
|
/** @description The tray temperature. */
|
||||||
|
tray_temp?: string | null
|
||||||
|
/** @description The tray time. */
|
||||||
|
tray_time?: string | null
|
||||||
|
/** @description The tray type. */
|
||||||
|
tray_type?: string | null
|
||||||
|
/** @description The tray uuid. */
|
||||||
|
tray_uuid?: string | null
|
||||||
|
/** @description The tray weight. */
|
||||||
|
tray_weight?: string | null
|
||||||
|
/** @description The xcam info. */
|
||||||
|
xcam_info?: string | null
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description A print upgrade state. */
|
||||||
|
PrintUpgradeState: {
|
||||||
|
/** @description The consistency request. */
|
||||||
|
consistency_request?: boolean | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The dis state.
|
||||||
|
*/
|
||||||
|
dis_state?: number | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The error code.
|
||||||
|
*/
|
||||||
|
err_code?: number | null
|
||||||
|
/** @description Force upgrade? */
|
||||||
|
force_upgrade?: boolean | null
|
||||||
|
/** @description The message. */
|
||||||
|
message?: string | null
|
||||||
|
/** @description The module. */
|
||||||
|
module?: string | null
|
||||||
|
/** @description The new version list. */
|
||||||
|
new_ver_list?: unknown[] | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The new version state.
|
||||||
|
*/
|
||||||
|
new_version_state?: number | null
|
||||||
|
/** @description The progress. */
|
||||||
|
progress?: string | null
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The sequence id.
|
||||||
|
*/
|
||||||
|
sequence_id?: number | null
|
||||||
|
/** @description The status. */
|
||||||
|
status?: string | null
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description The print upload. */
|
||||||
|
PrintUpload: {
|
||||||
|
/** @description The message. */
|
||||||
|
message: string
|
||||||
|
/**
|
||||||
|
* Format: int64
|
||||||
|
* @description The progress.
|
||||||
|
*/
|
||||||
|
progress: number
|
||||||
|
/** @description The status. */
|
||||||
|
status: string
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
/** @description A reason for a message. */
|
||||||
|
Reason:
|
||||||
|
| 'SUCCESS'
|
||||||
|
| 'FAIL'
|
||||||
|
| {
|
||||||
|
UNKNOWN: string
|
||||||
|
}
|
||||||
|
/** @description The result of a message. */
|
||||||
|
Result: 'SUCCESS' | 'FAIL'
|
||||||
|
/** @description The sequence id type. */
|
||||||
|
SequenceId: string | number
|
||||||
|
/** @description A system command. */
|
||||||
|
System:
|
||||||
|
| ({
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'ledctrl'
|
||||||
|
/**
|
||||||
|
* Format: uint32
|
||||||
|
* @description The interval time.
|
||||||
|
*/
|
||||||
|
interval_time: number
|
||||||
|
/** @description The LED mode. */
|
||||||
|
led_mode: components['schemas']['LedMode']
|
||||||
|
/** @description The LED node. */
|
||||||
|
led_node: components['schemas']['LedNode']
|
||||||
|
/**
|
||||||
|
* Format: uint32
|
||||||
|
* @description The LED off time.
|
||||||
|
*/
|
||||||
|
led_off_time: number
|
||||||
|
/**
|
||||||
|
* Format: uint32
|
||||||
|
* @description The LED on time.
|
||||||
|
*/
|
||||||
|
led_on_time: number
|
||||||
|
/**
|
||||||
|
* Format: uint32
|
||||||
|
* @description The loop times.
|
||||||
|
*/
|
||||||
|
loop_times: number
|
||||||
|
/** @description The reason for the message. */
|
||||||
|
reason?: components['schemas']['Reason'] | null
|
||||||
|
/** @description The result of the command. */
|
||||||
|
result: components['schemas']['Result']
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
| ({
|
||||||
|
/** @description The accessory type. */
|
||||||
|
accessory_type: components['schemas']['AccessoryType']
|
||||||
|
/** @description The aux part fan. */
|
||||||
|
aux_part_fan: boolean
|
||||||
|
/** @enum {string} */
|
||||||
|
command: 'get_accessories'
|
||||||
|
/**
|
||||||
|
* Format: double
|
||||||
|
* @description The nozzle diameter.
|
||||||
|
*/
|
||||||
|
nozzle_diameter: number
|
||||||
|
/** @description The nozzle type. */
|
||||||
|
nozzle_type: components['schemas']['NozzleType']
|
||||||
|
/** @description The reason for the message. */
|
||||||
|
reason?: components['schemas']['Reason'] | null
|
||||||
|
/** @description The result of the command. */
|
||||||
|
result: components['schemas']['Result']
|
||||||
|
/** @description The sequence id. */
|
||||||
|
sequence_id: components['schemas']['SequenceId']
|
||||||
|
} & {
|
||||||
|
[key: string]: unknown
|
||||||
|
})
|
||||||
|
}
|
||||||
|
responses: {
|
||||||
|
/** @description Error */
|
||||||
|
Error: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown
|
||||||
|
}
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parameters: never
|
||||||
|
requestBodies: never
|
||||||
|
headers: never
|
||||||
|
pathItems: never
|
||||||
|
}
|
||||||
|
export type $defs = Record<string, never>
|
||||||
|
export interface operations {
|
||||||
|
api_get_schema: {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
requestBody?: never
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown
|
||||||
|
}
|
||||||
|
content: {
|
||||||
|
'application/json': unknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'4XX': components['responses']['Error']
|
||||||
|
'5XX': components['responses']['Error']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get_machines: {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
requestBody?: never
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown
|
||||||
|
}
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
[key: string]: components['schemas']['Machine']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'4XX': components['responses']['Error']
|
||||||
|
'5XX': components['responses']['Error']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get_machine: {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path: {
|
||||||
|
/** @description The machine ID. */
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
requestBody?: never
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown
|
||||||
|
}
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Message']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'4XX': components['responses']['Error']
|
||||||
|
'5XX': components['responses']['Error']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ping: {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
requestBody?: never
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown
|
||||||
|
}
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Pong']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'4XX': components['responses']['Error']
|
||||||
|
'5XX': components['responses']['Error']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print_file: {
|
||||||
|
parameters: {
|
||||||
|
query?: never
|
||||||
|
header?: never
|
||||||
|
path?: never
|
||||||
|
cookie?: never
|
||||||
|
}
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
'multipart/form-data': string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responses: {
|
||||||
|
/** @description successful operation */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown
|
||||||
|
}
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['PrintJobResponse']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'4XX': components['responses']['Error']
|
||||||
|
'5XX': components['responses']['Error']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
src/lib/machineManager.ts
Normal file
74
src/lib/machineManager.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { isTauri } from './isTauri'
|
||||||
|
import { components } from './machine-api'
|
||||||
|
import { getMachineApiIp, listMachines } from './tauri'
|
||||||
|
|
||||||
|
export class MachineManager {
|
||||||
|
private _isTauri: boolean = isTauri()
|
||||||
|
private _machines: {
|
||||||
|
[key: string]: components['schemas']['Machine']
|
||||||
|
} = {}
|
||||||
|
private _machineApiIp: string | null = null
|
||||||
|
private _currentMachine: components['schemas']['Machine'] | null = null
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
if (!this._isTauri) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateMachines()
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
if (!this._isTauri) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a background job to update the machines every ten seconds.
|
||||||
|
setInterval(() => {
|
||||||
|
this.updateMachineApiIp()
|
||||||
|
this.updateMachines()
|
||||||
|
}, 10000)
|
||||||
|
}
|
||||||
|
|
||||||
|
get machines(): {
|
||||||
|
[key: string]: components['schemas']['Machine']
|
||||||
|
} {
|
||||||
|
return this._machines
|
||||||
|
}
|
||||||
|
|
||||||
|
machineCount(): number {
|
||||||
|
return Object.keys(this._machines).length
|
||||||
|
}
|
||||||
|
|
||||||
|
get machineApiIp(): string | null {
|
||||||
|
return this._machineApiIp
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentMachine(): components['schemas']['Machine'] | null {
|
||||||
|
return this._currentMachine
|
||||||
|
}
|
||||||
|
|
||||||
|
set currentMachine(machine: components['schemas']['Machine'] | null) {
|
||||||
|
this._currentMachine = machine
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateMachines(): Promise<void> {
|
||||||
|
if (!this._isTauri) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this._machines = await listMachines()
|
||||||
|
console.log('Machines:', this._machines)
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateMachineApiIp(): Promise<void> {
|
||||||
|
if (!this._isTauri) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this._machineApiIp = await getMachineApiIp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const machineManager = new MachineManager()
|
||||||
|
machineManager.start()
|
4
src/lib/modelingAppFile.ts
Normal file
4
src/lib/modelingAppFile.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export default interface ModelingAppFile {
|
||||||
|
name: string
|
||||||
|
contents: number[]
|
||||||
|
}
|
@ -9,6 +9,7 @@ import { FileEntry } from 'wasm-lib/kcl/bindings/FileEntry'
|
|||||||
import { ProjectState } from 'wasm-lib/kcl/bindings/ProjectState'
|
import { ProjectState } from 'wasm-lib/kcl/bindings/ProjectState'
|
||||||
import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute'
|
import { ProjectRoute } from 'wasm-lib/kcl/bindings/ProjectRoute'
|
||||||
import { isTauri } from './isTauri'
|
import { isTauri } from './isTauri'
|
||||||
|
import { components } from './machine-api'
|
||||||
|
|
||||||
// Get the app state from tauri.
|
// Get the app state from tauri.
|
||||||
export async function getState(): Promise<ProjectState | undefined> {
|
export async function getState(): Promise<ProjectState | undefined> {
|
||||||
@ -26,6 +27,19 @@ export async function setState(state: ProjectState | undefined): Promise<void> {
|
|||||||
return await invoke('set_state', { state })
|
return await invoke('set_state', { state })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List machines on the local network.
|
||||||
|
export async function listMachines(): Promise<{
|
||||||
|
[key: string]: components['schemas']['Machine']
|
||||||
|
}> {
|
||||||
|
let machines: string = await invoke<string>('list_machines')
|
||||||
|
return JSON.parse(machines)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the machine-api ip address.
|
||||||
|
export async function getMachineApiIp(): Promise<string | null> {
|
||||||
|
return await invoke<string | null>('get_machine_api_ip')
|
||||||
|
}
|
||||||
|
|
||||||
export async function renameProjectDirectory(
|
export async function renameProjectDirectory(
|
||||||
projectPath: string,
|
projectPath: string,
|
||||||
newName: string
|
newName: string
|
||||||
|
@ -202,6 +202,7 @@ export type ModelingMachineEvent =
|
|||||||
| { type: 'Constrain remove constraints'; data?: PathToNode }
|
| { type: 'Constrain remove constraints'; data?: PathToNode }
|
||||||
| { type: 'Re-execute' }
|
| { type: 'Re-execute' }
|
||||||
| { type: 'Export'; data: ModelingCommandSchema['Export'] }
|
| { type: 'Export'; data: ModelingCommandSchema['Export'] }
|
||||||
|
| { type: 'Make'; data: ModelingCommandSchema['Make'] }
|
||||||
| { type: 'Extrude'; data?: ModelingCommandSchema['Extrude'] }
|
| { type: 'Extrude'; data?: ModelingCommandSchema['Extrude'] }
|
||||||
| { type: 'Fillet'; data?: ModelingCommandSchema['Fillet'] }
|
| { type: 'Fillet'; data?: ModelingCommandSchema['Fillet'] }
|
||||||
| {
|
| {
|
||||||
@ -334,6 +335,13 @@ export const modelingMachine = createMachine(
|
|||||||
actions: 'Engine export',
|
actions: 'Engine export',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Make: {
|
||||||
|
target: 'idle',
|
||||||
|
internal: true,
|
||||||
|
cond: 'Has exportable geometry',
|
||||||
|
actions: 'Make',
|
||||||
|
},
|
||||||
|
|
||||||
'Delete selection': {
|
'Delete selection': {
|
||||||
target: 'idle',
|
target: 'idle',
|
||||||
cond: 'has valid selection for deletion',
|
cond: 'has valid selection for deletion',
|
||||||
|
12
src/wasm-lib/Cargo.lock
generated
12
src/wasm-lib/Cargo.lock
generated
@ -335,6 +335,12 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder-lite"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -1251,12 +1257,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.1"
|
version = "0.25.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11"
|
checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"byteorder",
|
"byteorder-lite",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"png",
|
"png",
|
||||||
]
|
]
|
||||||
|
@ -27,7 +27,7 @@ pub async fn execute_and_snapshot(code: &str, units: UnitLength) -> anyhow::Resu
|
|||||||
// Save the snapshot locally, to that temporary file.
|
// Save the snapshot locally, to that temporary file.
|
||||||
std::fs::write(&output_file, snapshot.contents.0)?;
|
std::fs::write(&output_file, snapshot.contents.0)?;
|
||||||
// Decode the snapshot, return it.
|
// Decode the snapshot, return it.
|
||||||
let img = image::io::Reader::open(output_file).unwrap().decode()?;
|
let img = image::ImageReader::open(output_file).unwrap().decode()?;
|
||||||
Ok(img)
|
Ok(img)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user