diff --git a/Cargo.lock b/Cargo.lock index bac8c60ae..0f5f28572 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -724,6 +724,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "bstr" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +dependencies = [ + "memchr", + "once_cell", + "regex-automata", + "serde", +] + [[package]] name = "builtin-psl-connectors" version = "0.1.0" @@ -732,7 +744,7 @@ dependencies = [ "connection-string", "either", "enumflags2 0.7.5", - "indoc", + "indoc 1.0.8", "lsp-types", "once_cell", "psl-core", @@ -1053,7 +1065,7 @@ version = "4.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" dependencies = [ - "heck 0.4.0", + "heck 0.4.1", "proc-macro-error", "proc-macro2", "quote", @@ -1076,7 +1088,7 @@ dependencies = [ "anyhow", "clap", "hex", - "indoc", + "indoc 1.0.8", "sd-crypto", "tokio", ] @@ -1807,7 +1819,7 @@ version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?tag=pcr-0.6.5#7cc20cc54a7ab0b5e38c81901826939a91a17ba0" dependencies = [ "colored", - "indoc", + "indoc 1.0.8", "pest", ] @@ -1898,7 +1910,7 @@ dependencies = [ "cuid", "either", "enumflags2 0.7.5", - "indoc", + "indoc 1.0.8", "prisma-value", "psl-core", "schema-ast", @@ -2054,7 +2066,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ - "heck 0.4.0", + "heck 0.4.1", "proc-macro2", "quote", "syn 1.0.107", @@ -2674,7 +2686,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a68131a662b04931e71891fb14aaf65ee4b44d08e8abc10f49e77418c86c64" dependencies = [ "anyhow", - "heck 0.4.0", + "heck 0.4.1", "proc-macro-crate 1.2.1", "proc-macro-error", "proc-macro2", @@ -2705,7 +2717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" dependencies = [ "aho-corasick", - "bstr", + "bstr 0.2.17", "fnv", "log", "regex", @@ -2890,9 +2902,9 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -3264,6 +3276,12 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da2d6f23ffea9d7e76c53eee25dfb67bcd8fde7f1198b0855350698c9f07c780" +[[package]] +name = "indoc" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" + [[package]] name = "infer" version = "0.7.0" @@ -4908,6 +4926,17 @@ dependencies = [ "windows-sys 0.36.1", ] +[[package]] +name = "opener" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c62dcb6174f9cb326eac248f07e955d5d559c272730b6c03e396b443b562788" +dependencies = [ + "bstr 1.4.0", + "normpath", + "winapi", +] + [[package]] name = "openssl" version = "0.10.42" @@ -5757,7 +5786,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12" dependencies = [ "bytes", - "heck 0.4.0", + "heck 0.4.1", "itertools", "lazy_static", "log", @@ -5826,7 +5855,7 @@ dependencies = [ "chrono", "diagnostics", "enumflags2 0.7.5", - "indoc", + "indoc 1.0.8", "itertools", "lsp-types", "once_cell", @@ -7395,16 +7424,20 @@ dependencies = [ "axum", "http", "httpz 0.0.3", + "opener", "percent-encoding", "rand 0.8.5", "rspc", "sd-core", "sd-desktop-macos", "serde", + "specta", "tauri", "tauri-build", + "tauri-specta", "tokio", "tracing", + "uuid 1.2.1", "window-shadows", ] @@ -7417,12 +7450,13 @@ dependencies = [ "chrono", "document-features", "indexmap", - "indoc", + "indoc 1.0.8", "once_cell", "paste", "serde", "serde_json", "specta-macros", + "tauri", "thiserror", "tokio", "uhlc", @@ -7506,7 +7540,7 @@ dependencies = [ "connection-string", "either", "enumflags2 0.7.5", - "indoc", + "indoc 1.0.8", "migration-connector", "once_cell", "psl", @@ -7564,7 +7598,7 @@ dependencies = [ "bigdecimal", "enumflags2 0.7.5", "indexmap", - "indoc", + "indoc 1.0.8", "once_cell", "psl", "quaint", @@ -7675,7 +7709,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ - "heck 0.4.0", + "heck 0.4.1", "proc-macro2", "quote", "rustversion", @@ -7823,7 +7857,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" dependencies = [ "cfg-expr 0.10.3", - "heck 0.4.0", + "heck 0.4.1", "pkg-config", "toml", "version-compare 0.1.0", @@ -7910,7 +7944,7 @@ dependencies = [ "glib", "glob", "gtk", - "heck 0.4.0", + "heck 0.4.1", "http", "ignore", "minisign-verify", @@ -7957,7 +7991,7 @@ checksum = "0991fb306849897439dbd4a72e4cbed2413e2eb26cb4b3ba220b94edba8b4b88" dependencies = [ "anyhow", "cargo_toml", - "heck 0.4.0", + "heck 0.4.1", "json-patch", "semver 1.0.14", "serde_json", @@ -7997,7 +8031,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069319e5ecbe653a799b94b0690d9f9bf5d00f7b1d3989aa331c524d4e354075" dependencies = [ - "heck 0.4.0", + "heck 0.4.1", "proc-macro2", "quote", "syn 1.0.107", @@ -8045,6 +8079,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.2.1" @@ -8054,7 +8103,7 @@ dependencies = [ "brotli", "ctor", "glob", - "heck 0.4.0", + "heck 0.4.1", "html5ever", "infer", "json-patch", @@ -8739,7 +8788,7 @@ version = "0.1.0" source = "git+https://github.com/Brendonovich/prisma-engines?tag=pcr-0.6.5#7cc20cc54a7ab0b5e38c81901826939a91a17ba0" dependencies = [ "backtrace", - "indoc", + "indoc 1.0.8", "quaint", "serde", "serde_json", diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml index 4add6fde2..53c215037 100644 --- a/apps/desktop/src-tauri/Cargo.toml +++ b/apps/desktop/src-tauri/Cargo.toml @@ -19,6 +19,10 @@ tracing = "0.1.36" serde = "1.0.145" percent-encoding = "2.2.0" http = "0.2.8" +opener = "0.6.1" +specta.workspace = true +tauri-specta = { version = "1.0.0", features = ["typescript"] } +uuid = { version = "1.1.2", features = ["serde"] } [target.'cfg(target_os = "linux")'.dependencies] axum = { version = "0.6.4", features = ["headers", "query"] } diff --git a/apps/desktop/src-tauri/src/file.rs b/apps/desktop/src-tauri/src/file.rs new file mode 100644 index 000000000..216157ddd --- /dev/null +++ b/apps/desktop/src-tauri/src/file.rs @@ -0,0 +1,39 @@ +use std::sync::Arc; + +use sd_core::Node; +use serde::Serialize; +use specta::Type; + +#[derive(Serialize, Type)] +#[serde(tag = "t", content = "c")] +pub enum OpenFilePathResult { + NoLibrary, + NoFile, + OpenError(String), + AllGood, +} + +#[tauri::command(async)] +#[specta::specta] +pub async fn open_file_path( + library: uuid::Uuid, + id: i32, + node: tauri::State<'_, Arc>, +) -> Result { + let res = if let Some(library) = node.library_manager.get_library(library).await { + let Ok(Some(path)) = library + .get_file_path(id) + .await + else { + return Ok(OpenFilePathResult::NoFile) + }; + + opener::open(path) + .map(|_| OpenFilePathResult::AllGood) + .unwrap_or_else(|e| OpenFilePathResult::OpenError(e.to_string())) + } else { + OpenFilePathResult::NoLibrary + }; + + Ok(res) +} diff --git a/apps/desktop/src-tauri/src/main.rs b/apps/desktop/src-tauri/src/main.rs index 8cc97264d..236599350 100644 --- a/apps/desktop/src-tauri/src/main.rs +++ b/apps/desktop/src-tauri/src/main.rs @@ -14,9 +14,11 @@ use tracing::{debug, error}; #[cfg(target_os = "linux")] mod app_linux; +mod file; mod menu; #[tauri::command(async)] +#[specta::specta] async fn app_ready(app_handle: tauri::AppHandle) { let window = app_handle.get_window("main").unwrap(); @@ -29,6 +31,15 @@ pub fn tauri_error_plugin(err: NodeError) -> TauriPlugin { .build() } +macro_rules! tauri_handlers { + ($($name:path),+) => {{ + #[cfg(debug_assertions)] + tauri_specta::ts::export(specta::collect_types![$($name),+], "../src/commands.ts").unwrap(); + + tauri::generate_handler![$($name),+] + }}; +} + #[tokio::main] async fn main() -> tauri::Result<()> { #[cfg(target_os = "linux")] @@ -58,10 +69,12 @@ async fn main() -> tauri::Result<()> { endpoint.tauri_uri_scheme("spacedrive"), ); - let app = app.plugin(rspc::integrations::tauri::plugin(router, { - let node = node.clone(); - move || node.clone() - })); + let app = app + .plugin(rspc::integrations::tauri::plugin(router, { + let node = node.clone(); + move || node.clone() + })) + .manage(node.clone()); (Some(node), app) } @@ -107,8 +120,8 @@ async fn main() -> tauri::Result<()> { Ok(()) }) .on_menu_event(menu::handle_menu_event) - .invoke_handler(tauri::generate_handler![app_ready]) .menu(menu::get_menu()) + .invoke_handler(tauri_handlers![app_ready, file::open_file_path]) .build(tauri::generate_context!())?; app.run(move |app_handler, event| { diff --git a/apps/desktop/src/App.tsx b/apps/desktop/src/App.tsx index b7f51bfd4..a03ed1707 100644 --- a/apps/desktop/src/App.tsx +++ b/apps/desktop/src/App.tsx @@ -19,6 +19,7 @@ import { } from '@sd/interface'; import { getSpacedropState } from '@sd/interface/hooks/useSpacedropState'; import '@sd/ui/style'; +import { appReady, openFilePath } from './commands'; const client = hooks.createClient({ links: [ @@ -72,7 +73,8 @@ const platform: Platform = { openFilePickerDialog: () => dialog.open(), saveFilePickerDialog: () => dialog.save(), showDevtools: () => invoke('show_devtools'), - openPath: (path) => shell.open(path) + openPath: (path) => shell.open(path), + openFilePath }; const queryClient = new QueryClient(); @@ -82,7 +84,7 @@ const router = createMemoryRouter(routes); export default function App() { useEffect(() => { // This tells Tauri to show the current window because it's finished loading - invoke('app_ready'); + appReady(); }, []); useEffect(() => { diff --git a/apps/desktop/src/commands.ts b/apps/desktop/src/commands.ts new file mode 100644 index 000000000..c39f6c1b6 --- /dev/null +++ b/apps/desktop/src/commands.ts @@ -0,0 +1,23 @@ +// 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 appReady() { + return invoke('app_ready'); +} + +export function openFilePath(library: string, id: number) { + return invoke('open_file_path', { library, id }); +} + +export type OpenFilePathResult = + | { t: 'NoLibrary' } + | { t: 'NoFile' } + | { t: 'OpenError'; c: string } + | { t: 'AllGood' }; diff --git a/core/Cargo.toml b/core/Cargo.toml index b8fc302a3..dbaf48b67 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -10,12 +10,8 @@ rust-version = "1.68.1" [features] default = [] -mobile = [ -] # This feature allows features to be disabled when the Core is running on mobile. -ffmpeg = [ - "dep:ffmpeg-next", - "dep:sd-ffmpeg", -] # This feature controls whether the Spacedrive Core contains functionality which requires FFmpeg. +mobile = [] # This feature allows features to be disabled when the Core is running on mobile. +ffmpeg = ["dep:ffmpeg-next", "dep:sd-ffmpeg"] # This feature controls whether the Spacedrive Core contains functionality which requires FFmpeg. location-watcher = ["dep:notify"] sync-messages = [] diff --git a/core/src/api/libraries.rs b/core/src/api/libraries.rs index beec767d4..9f24c92ca 100644 --- a/core/src/api/libraries.rs +++ b/core/src/api/libraries.rs @@ -105,7 +105,10 @@ pub(crate) fn mount() -> AlphaRouter { invalidate_query!( // SAFETY: This unwrap is alright as we just created the library - ctx.library_manager.get_ctx(new_library.uuid).await.unwrap(), + ctx.library_manager + .get_library(new_library.uuid) + .await + .unwrap(), "library.getStatistics" ); diff --git a/core/src/api/utils/invalidate.rs b/core/src/api/utils/invalidate.rs index e50fb493f..ff92db63c 100644 --- a/core/src/api/utils/invalidate.rs +++ b/core/src/api/utils/invalidate.rs @@ -249,9 +249,9 @@ pub(crate) fn mount_invalidate() -> AlphaRouter { }, // Given human reaction time of ~250 milli this should be a good ballance. _ = tokio::time::sleep(Duration::from_millis(200)) => { - let x = buf.drain().map(|(_k, v)| v).collect::>(); - if !x.is_empty() { - match tx.send(x) { + let events = buf.drain().map(|(_k, v)| v).collect::>(); + if !events.is_empty() { + match tx.send(events) { Ok(_) => {}, // All receivers are shutdown means that all clients are disconnected. Err(_) => { diff --git a/core/src/api/utils/library.rs b/core/src/api/utils/library.rs index a8f570ffe..fa11ff059 100644 --- a/core/src/api/utils/library.rs +++ b/core/src/api/utils/library.rs @@ -34,7 +34,7 @@ pub(crate) fn library() -> impl MwV3 { MwArgMapperMiddleware::::new().mount(|mw, ctx: Ctx, library_id| async move { let library = ctx .library_manager - .get_ctx(library_id) + .get_library(library_id) .await .ok_or_else(|| { rspc::Error::new( diff --git a/core/src/custom_uri.rs b/core/src/custom_uri.rs index ac2dee314..fb29f03e1 100644 --- a/core/src/custom_uri.rs +++ b/core/src/custom_uri.rs @@ -167,7 +167,7 @@ async fn handle_file( } else { let library = node .library_manager - .get_ctx(library_id) + .get_library(library_id) .await .ok_or_else(|| HandleCustomUriError::NotFound("library"))?; diff --git a/core/src/lib.rs b/core/src/lib.rs index 94fbba049..61e3b3f1f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -16,7 +16,7 @@ use tracing_subscriber::{prelude::*, EnvFilter}; pub mod api; pub mod custom_uri; pub(crate) mod job; -pub(crate) mod library; +pub mod library; pub(crate) mod location; pub(crate) mod migrations; pub(crate) mod node; @@ -27,7 +27,7 @@ pub(crate) mod util; pub(crate) mod volume; #[allow(warnings, unused)] -pub(crate) mod prisma; +mod prisma; pub(crate) mod prisma_sync; #[derive(Clone)] @@ -41,7 +41,7 @@ pub struct NodeContext { pub struct Node { config: Arc, - library_manager: Arc, + pub library_manager: Arc, location_manager: Arc, jobs: Arc, p2p: Arc, @@ -109,11 +109,12 @@ impl Node { "desktop=debug" .parse() .expect("Error invalid tracing directive!"), - ), // .add_directive( - // "rspc=debug" - // .parse() - // .expect("Error invalid tracing directive!"), - // ), + ), + // .add_directive( + // "rspc=debug" + // .parse() + // .expect("Error invalid tracing directive!"), + // ), ); #[cfg(not(target_os = "android"))] let subscriber = subscriber.with(tracing_subscriber::fmt::layer().with_filter(CONSOLE_LOG_FILTER)); @@ -161,7 +162,7 @@ impl Node { while let Ok((library_id, operations)) = p2p_rx.recv().await { debug!("going to ingest {} operations", operations.len()); - let Some(library) = library_manager.get_ctx(library_id).await else { + let Some(library) = library_manager.get_library(library_id).await else { warn!("no library found!"); continue; }; diff --git a/core/src/library/library.rs b/core/src/library/library.rs index 1a000b4bb..de2575541 100644 --- a/core/src/library/library.rs +++ b/core/src/library/library.rs @@ -1,16 +1,17 @@ use crate::{ api::CoreEvent, job::{IntoJob, JobInitData, JobManagerError, StatefulJob}, - location::LocationManager, + location::{file_path_helper::MaterializedPath, LocationManager}, node::NodeConfigManager, object::preview::THUMBNAIL_CACHE_DIR_NAME, - prisma::PrismaClient, + prisma::{file_path, location, PrismaClient}, sync::SyncManager, NodeContext, }; use std::{ fmt::{Debug, Formatter}, + path::{Path, PathBuf}, sync::Arc, }; @@ -18,7 +19,7 @@ use sd_crypto::keys::keymanager::KeyManager; use tracing::warn; use uuid::Uuid; -use super::LibraryConfig; +use super::{LibraryConfig, LibraryManagerError}; /// LibraryContext holds context for a library which can be passed around the application. #[derive(Clone)] @@ -97,4 +98,30 @@ impl Library { Err(e) => Err(e), } } + + /// Returns the full path of a file + pub async fn get_file_path(&self, id: i32) -> Result, LibraryManagerError> { + Ok(self + .db + .file_path() + .find_first(vec![ + file_path::location::is(vec![location::node_id::equals(self.node_local_id)]), + file_path::id::equals(id), + ]) + .select(file_path::select!({ + materialized_path + location: select { + id + path + } + })) + .exec() + .await? + .map(|record| { + Path::new(&record.location.path).join(&MaterializedPath::from(( + record.location.id, + &record.materialized_path, + ))) + })) + } } diff --git a/core/src/library/manager.rs b/core/src/library/manager.rs index c4c05e44a..0731b2811 100644 --- a/core/src/library/manager.rs +++ b/core/src/library/manager.rs @@ -304,7 +304,7 @@ impl LibraryManager { } // get_ctx will return the library context for the given library id. - pub(crate) async fn get_ctx(&self, library_id: Uuid) -> Option { + pub async fn get_library(&self, library_id: Uuid) -> Option { self.libraries .read() .await diff --git a/core/src/util/debug_initializer.rs b/core/src/util/debug_initializer.rs index 69419089a..3ab93c964 100644 --- a/core/src/util/debug_initializer.rs +++ b/core/src/util/debug_initializer.rs @@ -81,7 +81,7 @@ impl InitConfig { } }); - let library = match library_manager.get_ctx(lib.id).await { + let library = match library_manager.get_library(lib.id).await { Some(lib) => lib, None => { let library = library_manager @@ -95,7 +95,7 @@ impl InitConfig { .await .unwrap(); - library_manager.get_ctx(library.uuid).await.unwrap() + library_manager.get_library(library.uuid).await.unwrap() } }; diff --git a/interface/app/$libraryId/Explorer/File/ContextMenu.tsx b/interface/app/$libraryId/Explorer/File/ContextMenu.tsx index 2faeae18c..6e92806c6 100644 --- a/interface/app/$libraryId/Explorer/File/ContextMenu.tsx +++ b/interface/app/$libraryId/Explorer/File/ContextMenu.tsx @@ -14,13 +14,22 @@ import { TrashSimple } from 'phosphor-react'; import { PropsWithChildren } from 'react'; -import { ExplorerItem, isObject, useLibraryMutation, useLibraryQuery } from '@sd/client'; +import { + ExplorerItem, + isObject, + useLibraryContext, + useLibraryMutation, + useLibraryQuery +} from '@sd/client'; import { ContextMenu, dialogManager } from '@sd/ui'; import { useExplorerParams } from '~/app/$libraryId/location/$id'; import { showAlertDialog } from '~/components/AlertDialog'; import { getExplorerStore, useExplorerStore } from '~/hooks/useExplorerStore'; +import { useOperatingSystem } from '~/hooks/useOperatingSystem'; +import { usePlatform } from '~/util/Platform'; import AssignTagMenuItems from '../AssignTagMenuItems'; import { OpenInNativeExplorer } from '../ContextMenu'; +import { getItemFilePath } from '../util'; import DecryptDialog from './DecryptDialog'; import DeleteDialog from './DeleteDialog'; import EncryptDialog from './EncryptDialog'; @@ -45,13 +54,7 @@ export default ({ data, className, ...props }: Props) => { return (
e.stopPropagation()} className={clsx('flex', className)}> - - (getExplorerStore().quickViewObject = data)} - /> - + @@ -248,3 +251,33 @@ export default ({ data, className, ...props }: Props) => {
); }; + +const OpenOrDownloadOptions = (props: { data: ExplorerItem }) => { + const os = useOperatingSystem(); + const platform = usePlatform(); + + const filePath = getItemFilePath(props.data); + const openFilePath = platform.openFilePath; + + const { library } = useLibraryContext(); + + if (os === 'browser') return ; + else + return ( + <> + {filePath && openFilePath && ( + openFilePath(library.uuid, filePath.id)} + /> + )} + (getExplorerStore().quickViewObject = props.data)} + /> + + + ); +}; diff --git a/interface/util/Platform.tsx b/interface/util/Platform.tsx index eab764a5d..f98f4fa94 100644 --- a/interface/util/Platform.tsx +++ b/interface/util/Platform.tsx @@ -17,6 +17,8 @@ export type Platform = { saveFilePickerDialog?(): Promise; showDevtools?(): void; openPath?(path: string): void; + // Opens a file path with a given ID + openFilePath?(library: string, id: number): any; }; // Keep this private and use through helpers below diff --git a/packages/client/src/core.ts b/packages/client/src/core.ts index 5f7f943bc..b80079e0b 100644 --- a/packages/client/src/core.ts +++ b/packages/client/src/core.ts @@ -107,8 +107,6 @@ export type Ordering = { name: boolean } */ export type StoredKeyVersion = "V1" -export type Tag = { id: number; pub_id: number[]; name: string | null; color: string | null; total_objects: number | null; redundancy_goal: number | null; date_created: string; date_modified: string } - /** * This should be used for passing an encrypted key around. * @@ -135,12 +133,16 @@ export type ExplorerData = { context: ExplorerContext; items: ExplorerItem[] } export type RenameFileArgs = { location_id: number; file_name: string; new_file_name: string } +export type IndexerRule = { id: number; kind: number; name: string; default: boolean; parameters: number[]; date_created: string; date_modified: string } + /** * Represents the operating system which the remote peer is running. * This is not used internally and predominantly is designed to be used for display purposes by the embedding application. */ export type OperatingSystem = "Windows" | "Linux" | "MacOS" | "Ios" | "Android" | { Other: string } +export type MediaData = { id: number; pixel_width: number | null; pixel_height: number | null; longitude: number | null; latitude: number | null; fps: number | null; capture_device_make: string | null; capture_device_model: string | null; capture_device_software: string | null; duration_seconds: number | null; codecs: string | null; streams: number | null } + /** * This is a stored key, and can be freely written to the database. * @@ -196,13 +198,17 @@ export type LocationUpdateArgs = { id: number; name: string | null; generate_pre export type FileCutterJobInit = { source_location_id: number; source_path_id: number; target_location_id: number; target_path: string } +export type FilePath = { id: number; pub_id: number[]; is_dir: boolean; cas_id: string | null; integrity_checksum: string | null; location_id: number; materialized_path: string; name: string; extension: string; size_in_bytes: string; inode: number[]; device: number[]; object_id: number | null; parent_id: number[] | null; key_id: number | null; date_created: string; date_modified: string; date_indexed: string } + export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused" export type ObjectValidatorArgs = { id: number; path: string } export type FileEraserJobInit = { location_id: number; path_id: number; passes: string } -export type MediaData = { id: number; pixel_width: number | null; pixel_height: number | null; longitude: number | null; latitude: number | null; fps: number | null; capture_device_make: string | null; capture_device_model: string | null; capture_device_software: string | null; duration_seconds: number | null; codecs: string | null; streams: number | null } +export type Node = { id: number; pub_id: number[]; name: string; platform: number; version: string | null; last_seen: string; timezone: string | null; date_created: string } + +export type Tag = { id: number; pub_id: number[]; name: string | null; color: string | null; total_objects: number | null; redundancy_goal: number | null; date_created: string; date_modified: string } export type Volume = { name: string; mount_point: string; total_capacity: string; available_capacity: string; is_removable: boolean; disk_type: string | null; file_system: string | null; is_root_filesystem: boolean } @@ -215,6 +221,8 @@ export type Algorithm = "XChaCha20Poly1305" | "Aes256Gcm" export type ExplorerItem = { type: "Path"; has_thumbnail: boolean; item: FilePathWithObject } | { type: "Object"; has_thumbnail: boolean; item: ObjectWithFilePaths } +export type Statistics = { id: number; date_captured: string; total_object_count: number; library_db_size: string; total_bytes_used: string; total_bytes_capacity: string; total_unique_bytes: string; total_bytes_free: string; preview_media_bytes: string } + export type JobReport = { id: string; name: string; action: string | null; data: number[] | null; metadata: any | null; is_background: boolean; created_at: string | null; started_at: string | null; completed_at: string | null; parent_id: string | null; status: JobStatus; task_count: number; completed_task_count: number; message: string } export type OwnedOperationItem = { id: any; data: OwnedOperationData } @@ -223,8 +231,6 @@ export type SetFavoriteArgs = { id: number; favorite: boolean } export type CRDTOperationType = SharedOperation | RelationOperation | OwnedOperation -export type Statistics = { id: number; date_captured: string; total_object_count: number; library_db_size: string; total_bytes_used: string; total_bytes_capacity: string; total_unique_bytes: string; total_bytes_free: string; preview_media_bytes: string } - /** * TODO: P2P event for the frontend */ @@ -232,8 +238,6 @@ export type P2PEvent = { type: "DiscoveredPeer"; peer_id: PeerId; metadata: Peer export type SpacedropArgs = { peer_id: PeerId; file_path: string[] } -export type Object = { id: number; pub_id: number[]; kind: number; key_id: number | null; hidden: boolean; favorite: boolean; important: boolean; has_thumbnail: boolean; has_thumbstrip: boolean; has_video_preview: boolean; ipfs_id: string | null; note: string | null; date_created: string } - export type LocationWithIndexerRules = { id: number; pub_id: number[]; node_id: number; name: string; path: string; total_capacity: number | null; available_capacity: number | null; is_archived: boolean; generate_preview_media: boolean; sync_preview_media: boolean; hidden: boolean; date_created: string; indexer_rules: ({ indexer_rule: IndexerRule })[] } export type NodeState = ({ id: string; name: string; p2p_port: number | null; p2p_email: string | null; p2p_img_url: string | null }) & { data_path: string } @@ -250,15 +254,11 @@ export type SharedOperationCreateData = { u: { [key: string]: any } } | "a" export type KeyAddArgs = { algorithm: Algorithm; hashing_algorithm: HashingAlgorithm; key: Protected; library_sync: boolean; automount: boolean } -export type Location = { id: number; pub_id: number[]; node_id: number; name: string; path: string; total_capacity: number | null; available_capacity: number | null; is_archived: boolean; generate_preview_media: boolean; sync_preview_media: boolean; hidden: boolean; date_created: string } - /** * Can wrap a query argument to require it to contain a `library_id` and provide helpers for working with libraries. */ export type LibraryArgs = { library_id: string; arg: T } -export type Node = { id: number; pub_id: number[]; name: string; platform: number; version: string | null; last_seen: string; timezone: string | null; date_created: string } - /** * `LocationCreateArgs` is the argument received from the client using `rspc` to create a new location. * It has the actual path and a vector of indexer rules ids, to create many-to-many relationships @@ -272,6 +272,8 @@ export type OwnedOperationData = { Create: { [key: string]: any } } | { CreateMa export type SharedOperationData = SharedOperationCreateData | { field: string; value: any } | null +export type Object = { id: number; pub_id: number[]; kind: number; key_id: number | null; hidden: boolean; favorite: boolean; important: boolean; has_thumbnail: boolean; has_thumbstrip: boolean; has_video_preview: boolean; ipfs_id: string | null; note: string | null; date_created: string } + export type TagAssignArgs = { object_id: number; tag_id: number; unassign: boolean } export type FileCopierJobInit = { source_location_id: number; source_path_id: number; target_location_id: number; target_path: string; target_file_name_suffix: string | null } @@ -287,8 +289,6 @@ export type ExplorerContext = ({ type: "Location" } & Location) | ({ type: "Tag" export type SetNoteArgs = { id: number; note: string | null } -export type FilePath = { id: number; pub_id: number[]; is_dir: boolean; cas_id: string | null; integrity_checksum: string | null; location_id: number; materialized_path: string; name: string; extension: string; size_in_bytes: string; inode: number[]; device: number[]; object_id: number | null; parent_id: number[] | null; key_id: number | null; date_created: string; date_modified: string; date_indexed: string } - /** * LibraryConfig holds the configuration for a specific library. This is stored as a '{uuid}.sdlibrary' file. */ @@ -300,6 +300,8 @@ export type FileDecryptorJobInit = { location_id: number; path_id: number; mount export type AutomountUpdateArgs = { uuid: string; status: boolean } +export type Location = { id: number; pub_id: number[]; node_id: number; name: string; path: string; total_capacity: number | null; available_capacity: number | null; is_archived: boolean; generate_preview_media: boolean; sync_preview_media: boolean; hidden: boolean; date_created: string } + export type Protected = T /** @@ -314,8 +316,6 @@ export type Protected = T */ export type IndexerRuleCreateArgs = { kind: RuleKind; name: string; parameters: string[] } -export type IndexerRule = { id: number; kind: number; name: string; default: boolean; parameters: number[]; date_created: string; date_modified: string } - export type LightScanArgs = { location_id: number; sub_path: string } export type RestoreBackupArgs = { password: Protected; secret_key: Protected; path: string }