File Opening (#762)

* file opening

* eslint disable in gererated commands

* bruh?

* Fixing materialized_path joining and some warnings

* no unwraps

* formatting

---------

Co-authored-by: Ericson Soares <ericson.ds999@gmail.com>
This commit is contained in:
Brendan Allan 2023-04-28 21:55:00 +08:00 committed by GitHub
parent c7d182e12b
commit 3570c5f3d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 271 additions and 79 deletions

93
Cargo.lock generated
View file

@ -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",

View file

@ -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"] }

View file

@ -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<Node>>,
) -> Result<OpenFilePathResult, ()> {
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)
}

View file

@ -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<R: Runtime>(err: NodeError) -> TauriPlugin<R> {
.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| {

View file

@ -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(() => {

View file

@ -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__<T>(cmd: string, args?: Record<string, unknown>): Promise<T>;
}
}
const invoke = window.__TAURI_INVOKE__;
export function appReady() {
return invoke<null>('app_ready');
}
export function openFilePath(library: string, id: number) {
return invoke<OpenFilePathResult>('open_file_path', { library, id });
}
export type OpenFilePathResult =
| { t: 'NoLibrary' }
| { t: 'NoFile' }
| { t: 'OpenError'; c: string }
| { t: 'AllGood' };

View file

@ -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 = []

View file

@ -105,7 +105,10 @@ pub(crate) fn mount() -> AlphaRouter<Ctx> {
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"
);

View file

@ -249,9 +249,9 @@ pub(crate) fn mount_invalidate() -> AlphaRouter<Ctx> {
},
// 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::<Vec<_>>();
if !x.is_empty() {
match tx.send(x) {
let events = buf.drain().map(|(_k, v)| v).collect::<Vec<_>>();
if !events.is_empty() {
match tx.send(events) {
Ok(_) => {},
// All receivers are shutdown means that all clients are disconnected.
Err(_) => {

View file

@ -34,7 +34,7 @@ pub(crate) fn library() -> impl MwV3<Ctx, NewCtx = (Ctx, Library)> {
MwArgMapperMiddleware::<LibraryArgsLike>::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(

View file

@ -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"))?;

View file

@ -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<NodeConfigManager>,
library_manager: Arc<LibraryManager>,
pub library_manager: Arc<LibraryManager>,
location_manager: Arc<LocationManager>,
jobs: Arc<JobManager>,
p2p: Arc<P2PManager>,
@ -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;
};

View file

@ -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<Option<PathBuf>, 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,
)))
}))
}
}

View file

@ -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<Library> {
pub async fn get_library(&self, library_id: Uuid) -> Option<Library> {
self.libraries
.read()
.await

View file

@ -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()
}
};

View file

@ -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 (
<div onClick={(e) => e.stopPropagation()} className={clsx('flex', className)}>
<ContextMenu.Root trigger={props.children}>
<ContextMenu.Item label="Open" keybind="⌘O" />
<ContextMenu.Item
label="Quick view"
keybind="␣"
onClick={() => (getExplorerStore().quickViewObject = data)}
/>
<ContextMenu.Item label="Open with..." keybind="⌘^O" />
<OpenOrDownloadOptions data={data} />
<ContextMenu.Separator />
@ -248,3 +251,33 @@ export default ({ data, className, ...props }: Props) => {
</div>
);
};
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 <ContextMenu.Item label="Download" />;
else
return (
<>
{filePath && openFilePath && (
<ContextMenu.Item
label="Open"
keybind="⌘O"
onClick={() => openFilePath(library.uuid, filePath.id)}
/>
)}
<ContextMenu.Item
label="Quick view"
keybind="␣"
onClick={() => (getExplorerStore().quickViewObject = props.data)}
/>
<ContextMenu.Item label="Open with..." keybind="⌘^O" />
</>
);
};

View file

@ -17,6 +17,8 @@ export type Platform = {
saveFilePickerDialog?(): Promise<string | null>;
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

View file

@ -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<string>; 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<T> = { 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> = T
/**
@ -314,8 +316,6 @@ export type Protected<T> = 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<string>; secret_key: Protected<string>; path: string }