diff --git a/bindings.ts b/bindings.ts new file mode 100644 index 0000000..7cf18cd --- /dev/null +++ b/bindings.ts @@ -0,0 +1,35 @@ +// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually. + +declare global { + interface Window { + __TAURI_INVOKE__(cmd: string, args?: Record): Promise; + } +} + +const invoke = window.__TAURI_INVOKE__; + +export function errorPopup(msg: string) { + return invoke("error_popup", { msg }) +} + +export function hide() { + return invoke("hide") +} + +export function newGroup(group: Group) { + return invoke("new_group", { group }) +} + +export function getGroups() { + return invoke("get_groups") +} + +export function updateGroup(group: Group) { + return invoke("update_group", { group }) +} + +export function deleteGroup(index: number) { + return invoke("delete_group", { index }) +} + +export type Group = { title: string; description: string; enabled: boolean; id: string; cron: string } diff --git a/package-lock.json b/package-lock.json index 40effcf..da21534 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "svelte": "^3.59.0", "svelte-check": "^3.3.1", "tailwindcss": "^3.3.2", + "tauri-specta": "^0.0.2", "typescript": "^5.0.4", "vite": "^4.3.5" } @@ -3297,6 +3298,15 @@ "node": ">=14.0.0" } }, + "node_modules/tauri-specta": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/tauri-specta/-/tauri-specta-0.0.2.tgz", + "integrity": "sha512-ZgbJ/dnqHPn7Jsux7dMx7L8zMsG05Mt6rxR+ZWuSvvfWs5t+dPdHKc/4QEO3gXdQ5h1cJDwGUaNsEFoECbYkTA==", + "dev": true, + "peerDependencies": { + "@tauri-apps/api": "^1.1.0" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", diff --git a/package.json b/package.json index 176f928..641611a 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "svelte": "^3.59.0", "svelte-check": "^3.3.1", "tailwindcss": "^3.3.2", + "tauri-specta": "^0.0.2", "typescript": "^5.0.4", "vite": "^4.3.5" }, diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 55260ec..48d13fe 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + [[package]] name = "adler" version = "1.0.2" @@ -644,6 +650,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "document-features" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e493c573fce17f00dcab13b6ac057994f3ce17d1af4dc39bfd482b83c6eb6157" +dependencies = [ + "litrs", +] + [[package]] name = "dtoa" version = "0.4.8" @@ -665,6 +680,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + [[package]] name = "embed-resource" version = "2.1.1" @@ -1359,6 +1380,18 @@ dependencies = [ "serde", ] +[[package]] +name = "indoc" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" + +[[package]] +name = "indoc" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" + [[package]] name = "infer" version = "0.12.0" @@ -1388,6 +1421,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -1555,6 +1597,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +[[package]] +name = "litrs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9275e0933cf8bb20f008924c0cb07a0692fe54d8064996520bf998de9eb79aa" + [[package]] name = "lock_api" version = "0.4.9" @@ -2401,9 +2449,11 @@ dependencies = [ "rust-macios", "serde", "serde_json", + "specta", "tauri", "tauri-build", "tauri-plugin-window-state", + "tauri-specta", "tokio", ] @@ -2762,6 +2812,37 @@ dependencies = [ "system-deps 5.0.0", ] +[[package]] +name = "specta" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95aa33f3135e656964f468db8369ac8e0b77ac957fe8cf335960202d68966d3b" +dependencies = [ + "document-features", + "indoc 1.0.9", + "once_cell", + "paste", + "serde", + "serde_json", + "specta-macros", + "tauri", + "thiserror", +] + +[[package]] +name = "specta-macros" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f66517b551b511fa78fa94bc553c7baf4a8d81c68a90e7458ea74f3de70acf6c" +dependencies = [ + "Inflector", + "itertools", + "proc-macro2", + "quote", + "syn 1.0.109", + "termcolor", +] + [[package]] name = "spin" version = "0.9.8" @@ -3113,6 +3194,21 @@ dependencies = [ "wry", ] +[[package]] +name = "tauri-specta" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23419889204476d5a70a04077d4628061a5bb667b18804a4572df2fe6ccb8ba5" +dependencies = [ + "heck 0.4.1", + "indoc 2.0.1", + "serde", + "serde_json", + "specta", + "tauri", + "thiserror", +] + [[package]] name = "tauri-utils" version = "1.3.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e096245..58319e0 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -21,6 +21,8 @@ async-cron-scheduler = "1.0" tauri-plugin-window-state = "0.1" nanoid = "0.4" atomicwrites = "0.4" +tauri-specta = { version = "1.0", features = ["javascript", "typescript"] } +specta = "1.0" [target.'cfg(target_os = "macos")'.dependencies] macos-app-nap = "0.0" diff --git a/src-tauri/src/data.rs b/src-tauri/src/data.rs index ab9d1d4..0cf40fc 100644 --- a/src-tauri/src/data.rs +++ b/src-tauri/src/data.rs @@ -1,7 +1,6 @@ use crate::notifications::Group; use atomicwrites::{AtomicFile, OverwriteBehavior}; use serde::{Deserialize, Serialize}; -use serde_json::Value; use std::env; use std::io::Write; use std::path::PathBuf; @@ -25,13 +24,6 @@ impl AppPaths { } } -pub fn to_json(data: &T) -> Result { - match serde_json::to_value(data) { - Ok(v) => Ok(v), - Err(e) => throw!("Error serializing {}", e), - } -} - pub fn ensure_parent_exists(file_path: &PathBuf) -> Result<(), String> { if let Some(parent) = file_path.parent() { if let Err(e) = std::fs::create_dir_all(parent) { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 1da4c9f..5392b00 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -22,6 +22,7 @@ macro_rules! throw { } #[command] +#[specta::specta] fn error_popup(msg: String, win: Window) { eprintln!("Error: {}", msg); thread::spawn(move || { @@ -78,6 +79,23 @@ fn main() { &ctx.config().tauri.bundle.identifier, ); + #[cfg(debug_assertions)] + { + tauri_specta::ts::export( + specta::collect_types![ + error_popup, + hide, + notifications::new_group, + notifications::get_groups, + notifications::update_group, + notifications::delete_group, + ], + "../bindings.ts", + ) + .unwrap(); + println!("Generated TS types"); + } + let app = tauri::Builder::default() .invoke_handler(tauri::generate_handler![ error_popup, @@ -219,6 +237,7 @@ fn show(app: &AppHandle) { window.set_focus().unwrap(); } #[command] +#[specta::specta] fn hide(app: AppHandle) { let window = app.get_window("main").unwrap(); window.unminimize().unwrap(); diff --git a/src-tauri/src/notifications.rs b/src-tauri/src/notifications.rs index 8ed4b95..d747546 100644 --- a/src-tauri/src/notifications.rs +++ b/src-tauri/src/notifications.rs @@ -1,10 +1,10 @@ -use crate::data::{to_json, AppPaths, RemindersFile}; +use crate::data::{AppPaths, RemindersFile}; use async_cron_scheduler::cron; use async_cron_scheduler::{Job, JobId, Scheduler}; use chrono::offset::Local; use nanoid::nanoid; use serde::{Deserialize, Serialize}; -use serde_json::Value; +use specta::Type; use std::str::FromStr; use std::sync::Mutex; use tauri::api::dialog; @@ -28,13 +28,14 @@ pub fn parse_cron(s: &str) -> Result { #[cfg(not(target_os = "macos"))] static mut APP_IDENTIFIER: Option = Option::None; -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Type)] pub struct Group { pub title: String, pub description: String, pub enabled: bool, pub id: String, #[serde(skip)] + #[specta(type = null)] pub job_id: Option, pub cron: String, } @@ -180,22 +181,27 @@ impl Instance { pub struct Data(pub Mutex); #[command] -pub async fn new_group(mut group: Group, data: State<'_, Data>) -> Result { +#[specta::specta] +pub async fn new_group(group: Group, data: State<'_, Data>) -> Result, String> { let mut data = data.0.lock().unwrap(); + let mut group = group; group.id = data.generate_id(); data.add_group(group)?; data.save()?; - to_json(&data.file.groups) + Ok(data.file.groups.clone()) } #[command] -pub async fn get_groups(data: State<'_, Data>) -> Result { +#[specta::specta] +pub async fn get_groups(data: State<'_, Data>) -> Result, String> { let data = data.0.lock().unwrap(); - to_json(&data.file.groups) + Ok(data.file.groups.clone()) } #[command] -pub async fn update_group(mut group: Group, data: State<'_, Data>) -> Result { +#[specta::specta] +pub async fn update_group(group: Group, data: State<'_, Data>) -> Result, String> { + let mut group = group; let mut data = data.0.lock().unwrap(); let i = match data.file.groups.iter().position(|g| g.id == group.id) { Some(i) => i, @@ -207,13 +213,14 @@ pub async fn update_group(mut group: Group, data: State<'_, Data>) -> Result) -> Result { +#[specta::specta] +pub async fn delete_group(index: u32, data: State<'_, Data>) -> Result, String> { let mut data = data.0.lock().unwrap(); - data.delete_group(index); + data.delete_group(index.try_into().unwrap()); data.save()?; - to_json(&data.file.groups) + Ok(data.file.groups.clone()) } diff --git a/src/App.svelte b/src/App.svelte index fe17868..32c48ef 100755 --- a/src/App.svelte +++ b/src/App.svelte @@ -5,17 +5,17 @@ import './app.css' import Item from './lib/Item.svelte' import New from './lib/New.svelte' - import { checkShortcut, runCmd } from './lib/helpers' - import type { Group } from './lib/types' + import { checkShortcut } from './lib/helpers' + import type { Group } from '../../bindings' import { onDestroy } from 'svelte' import { event, os } from '@tauri-apps/api' - import { invoke } from '@tauri-apps/api/tauri' + import commands from './lib/commands' let groupElements: Item[] = [] let focusedGroup: number | null = null let groups: Group[] = [] - runCmd('get_groups').then((g) => { + commands.getGroups().then((g) => { groups = g console.log(groups) }) @@ -58,7 +58,7 @@ { if (checkShortcut(e, 'Escape')) { - invoke('hide') + commands.hide() e.preventDefault() } }} @@ -100,10 +100,10 @@ bind:this={groupElements[i]} bind:group onUpdate={async () => { - groups = await runCmd('update_group', { group }) + groups = await commands.updateGroup(group) }} onDelete={async () => { - groups = await runCmd('delete_group', { index: i }) + groups = await commands.deleteGroup(i) }} /> diff --git a/src/global.d.ts b/src/global.d.ts deleted file mode 100644 index f413f49..0000000 --- a/src/global.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -declare type DndEvent = import('svelte-dnd-action').DndEvent -declare namespace svelte.JSX { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface HTMLAttributes { - onconsider?: (event: CustomEvent & { target: EventTarget & T }) => void - onfinalize?: (event: CustomEvent & { target: EventTarget & T }) => void - } -} diff --git a/src/lib/Edit.svelte b/src/lib/Edit.svelte index 8f518c2..c5ccf1b 100644 --- a/src/lib/Edit.svelte +++ b/src/lib/Edit.svelte @@ -1,7 +1,7 @@