mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-14 04:14:04 +00:00
[ENG-635] Job time estimation (#842)
* fix extension case sensitivity * job time estimation wip * update schema * use `DateTime` to handle estimated completion time * use a date with `dayjs` * remove old migrations * update migrations * remove dead code * Quick tweaks * unused import --------- Co-authored-by: brxken128 <77554505+brxken128@users.noreply.github.com> Co-authored-by: ameer2468 <33054370+ameer2468@users.noreply.github.com>
This commit is contained in:
parent
da2e78dc61
commit
ea46e7736a
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `parent_id` on the `file_path` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "job" ADD COLUMN "date_estimated_completion" DATETIME;
|
||||
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_file_path" (
|
||||
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
"pub_id" BLOB NOT NULL,
|
||||
"is_dir" BOOLEAN NOT NULL DEFAULT false,
|
||||
"cas_id" TEXT,
|
||||
"integrity_checksum" TEXT,
|
||||
"location_id" INTEGER NOT NULL,
|
||||
"materialized_path" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"extension" TEXT NOT NULL,
|
||||
"size_in_bytes" TEXT NOT NULL DEFAULT '0',
|
||||
"inode" BLOB NOT NULL,
|
||||
"device" BLOB NOT NULL,
|
||||
"object_id" INTEGER,
|
||||
"key_id" INTEGER,
|
||||
"date_created" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"date_modified" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"date_indexed" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "file_path_location_id_fkey" FOREIGN KEY ("location_id") REFERENCES "location" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "file_path_object_id_fkey" FOREIGN KEY ("object_id") REFERENCES "object" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "file_path_key_id_fkey" FOREIGN KEY ("key_id") REFERENCES "key" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_file_path" ("cas_id", "date_created", "date_indexed", "date_modified", "device", "extension", "id", "inode", "integrity_checksum", "is_dir", "key_id", "location_id", "materialized_path", "name", "object_id", "pub_id", "size_in_bytes") SELECT "cas_id", "date_created", "date_indexed", "date_modified", "device", "extension", "id", "inode", "integrity_checksum", "is_dir", "key_id", "location_id", "materialized_path", "name", "object_id", "pub_id", "size_in_bytes" FROM "file_path";
|
||||
DROP TABLE "file_path";
|
||||
ALTER TABLE "new_file_path" RENAME TO "file_path";
|
||||
CREATE UNIQUE INDEX "file_path_pub_id_key" ON "file_path"("pub_id");
|
||||
CREATE UNIQUE INDEX "file_path_integrity_checksum_key" ON "file_path"("integrity_checksum");
|
||||
CREATE INDEX "file_path_location_id_idx" ON "file_path"("location_id");
|
||||
CREATE INDEX "file_path_location_id_materialized_path_idx" ON "file_path"("location_id", "materialized_path");
|
||||
CREATE UNIQUE INDEX "file_path_location_id_materialized_path_name_extension_key" ON "file_path"("location_id", "materialized_path", "name", "extension");
|
||||
CREATE UNIQUE INDEX "file_path_location_id_inode_device_key" ON "file_path"("location_id", "inode", "device");
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
|
@ -385,11 +385,13 @@ model Job {
|
|||
|
||||
parent_id Bytes?
|
||||
|
||||
task_count Int @default(1)
|
||||
completed_task_count Int @default(0)
|
||||
date_created DateTime @default(now())
|
||||
date_started DateTime? @default(now()) // Started execution
|
||||
date_completed DateTime? @default(now()) // Finished execution
|
||||
task_count Int @default(1)
|
||||
completed_task_count Int @default(0)
|
||||
date_estimated_completion DateTime? // Estimated timestamp that the job will be complete at
|
||||
|
||||
date_created DateTime @default(now())
|
||||
date_started DateTime? @default(now()) // Started execution
|
||||
date_completed DateTime? @default(now()) // Finished execution
|
||||
|
||||
nodes Node @relation(fields: [node_id], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||
|
||||
|
|
|
@ -331,6 +331,7 @@ pub struct JobReport {
|
|||
pub completed_task_count: i32,
|
||||
|
||||
pub message: String,
|
||||
pub estimated_completion: DateTime<Utc>,
|
||||
// pub percentage_complete: f64,
|
||||
}
|
||||
|
||||
|
@ -364,8 +365,8 @@ impl From<job::Data> for JobReport {
|
|||
.map(|errors_str| errors_str.split("\n\n").map(str::to_string).collect())
|
||||
.unwrap_or_default(),
|
||||
created_at: Some(data.date_created.into()),
|
||||
started_at: data.date_started.map(|d| d.into()),
|
||||
completed_at: data.date_completed.map(|d| d.into()),
|
||||
started_at: data.date_started.map(DateTime::into),
|
||||
completed_at: data.date_completed.map(DateTime::into),
|
||||
parent_id: data
|
||||
.parent_id
|
||||
.map(|id| Uuid::from_slice(&id).expect("corrupted database")),
|
||||
|
@ -373,6 +374,9 @@ impl From<job::Data> for JobReport {
|
|||
task_count: data.task_count,
|
||||
completed_task_count: data.completed_task_count,
|
||||
message: String::new(),
|
||||
estimated_completion: data
|
||||
.date_estimated_completion
|
||||
.map_or(Utc::now(), DateTime::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -395,6 +399,7 @@ impl JobReport {
|
|||
parent_id: None,
|
||||
completed_task_count: 0,
|
||||
message: String::new(),
|
||||
estimated_completion: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::invalidate_query;
|
||||
use crate::job::{DynJob, JobError, JobManager, JobReportUpdate, JobStatus};
|
||||
use crate::library::Library;
|
||||
use chrono::Utc;
|
||||
use chrono::{DateTime, Utc};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::{
|
||||
|
@ -67,6 +67,7 @@ pub struct Worker {
|
|||
report: JobReport,
|
||||
worker_events_tx: UnboundedSender<WorkerEvent>,
|
||||
worker_events_rx: Option<UnboundedReceiver<WorkerEvent>>,
|
||||
start_time: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
|
@ -78,6 +79,7 @@ impl Worker {
|
|||
report,
|
||||
worker_events_tx,
|
||||
worker_events_rx: Some(worker_events_rx),
|
||||
start_time: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,6 +113,8 @@ impl Worker {
|
|||
worker.report.started_at = Some(Utc::now());
|
||||
}
|
||||
|
||||
worker.start_time = Some(Utc::now());
|
||||
|
||||
// If the report doesn't have a created_at date, it's a new report
|
||||
if worker.report.created_at.is_none() {
|
||||
worker.report.create(&library).await?;
|
||||
|
@ -217,6 +221,22 @@ impl Worker {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Calculate elapsed time
|
||||
if let Some(start_time) = worker.start_time {
|
||||
let elapsed = Utc::now() - start_time;
|
||||
|
||||
// Calculate remaining time
|
||||
let task_count = worker.report.task_count as usize;
|
||||
let completed_task_count = worker.report.completed_task_count as usize;
|
||||
let remaining_task_count = task_count.saturating_sub(completed_task_count);
|
||||
let remaining_time_per_task = elapsed / (completed_task_count + 1) as i32; // Adding 1 to avoid division by zero
|
||||
let remaining_time = remaining_time_per_task * remaining_task_count as i32;
|
||||
|
||||
// Update the report with estimated remaining time
|
||||
worker.report.estimated_completion = Utc::now()
|
||||
.checked_add_signed(remaining_time)
|
||||
.unwrap_or(Utc::now());
|
||||
}
|
||||
|
||||
invalidate_query!(library, "jobs.getRunning");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import clsx from 'clsx';
|
||||
import dayjs from 'dayjs';
|
||||
import {
|
||||
Camera,
|
||||
Copy,
|
||||
|
@ -16,12 +17,11 @@ import { memo } from 'react';
|
|||
import { JobReport } from '@sd/client';
|
||||
import { ProgressBar } from '@sd/ui';
|
||||
import './Job.scss';
|
||||
import { useJobTimeText } from './useJobTimeText';
|
||||
|
||||
interface JobNiceData {
|
||||
name: string;
|
||||
icon: React.ForwardRefExoticComponent<any>;
|
||||
filesDiscovered: string;
|
||||
subtext: string;
|
||||
}
|
||||
|
||||
const getNiceData = (
|
||||
|
@ -35,9 +35,7 @@ const getNiceData = (
|
|||
? `Indexed paths at ${job.metadata?.location_path} `
|
||||
: `Processing added location...`,
|
||||
icon: Folder,
|
||||
filesDiscovered: `${numberWithCommas(
|
||||
job.metadata?.total_paths || 0
|
||||
)} ${JobCountTextCondition(job, 'path')}`
|
||||
subtext: `${numberWithCommas(job.metadata?.total_paths || 0)} ${appendPlural(job, 'path')}`
|
||||
},
|
||||
thumbnailer: {
|
||||
name: `${
|
||||
|
@ -46,12 +44,14 @@ const getNiceData = (
|
|||
: 'Generated thumbnails'
|
||||
}`,
|
||||
icon: Camera,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)} ${JobCountTextCondition(job, 'item')}`
|
||||
subtext: `${numberWithCommas(job.completed_task_count)} of ${numberWithCommas(
|
||||
job.task_count
|
||||
)} ${appendPlural(job, 'thumbnail')}`
|
||||
},
|
||||
shallow_thumbnailer: {
|
||||
name: `Generating thumbnails for current directory`,
|
||||
icon: Camera,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)} ${JobCountTextCondition(job, 'item')}`
|
||||
subtext: `${numberWithCommas(job.task_count)} ${appendPlural(job, 'item')}`
|
||||
},
|
||||
file_identifier: {
|
||||
name: `${
|
||||
|
@ -60,60 +60,51 @@ const getNiceData = (
|
|||
: 'Extracted metadata'
|
||||
}`,
|
||||
icon: Eye,
|
||||
filesDiscovered:
|
||||
subtext:
|
||||
job.message ||
|
||||
`${numberWithCommas(job.task_count)} ${JobCountTextCondition(job, 'item')}`
|
||||
`${numberWithCommas(job.metadata.total_orphan_paths)} ${appendPlural(
|
||||
job,
|
||||
'file',
|
||||
'file_identifier'
|
||||
)}`
|
||||
},
|
||||
object_validator: {
|
||||
name: `Generated full object hashes`,
|
||||
icon: Fingerprint,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)} ${JobCountTextCondition(
|
||||
job,
|
||||
'object'
|
||||
)}`
|
||||
subtext: `${numberWithCommas(job.task_count)} ${appendPlural(job, 'object')}`
|
||||
},
|
||||
file_encryptor: {
|
||||
name: `Encrypted`,
|
||||
icon: LockSimple,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)} ${JobCountTextCondition(job, 'file')}`
|
||||
subtext: `${numberWithCommas(job.task_count)} ${appendPlural(job, 'file')}`
|
||||
},
|
||||
file_decryptor: {
|
||||
name: `Decrypted`,
|
||||
icon: LockSimpleOpen,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)}${JobCountTextCondition(job, 'file')}`
|
||||
subtext: `${numberWithCommas(job.task_count)}${appendPlural(job, 'file')}`
|
||||
},
|
||||
file_eraser: {
|
||||
name: `Securely erased`,
|
||||
icon: TrashSimple,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)} ${JobCountTextCondition(job, 'file')}`
|
||||
subtext: `${numberWithCommas(job.task_count)} ${appendPlural(job, 'file')}`
|
||||
},
|
||||
file_deleter: {
|
||||
name: `Deleted`,
|
||||
icon: Trash,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)} ${JobCountTextCondition(job, 'file')}`
|
||||
subtext: `${numberWithCommas(job.task_count)} ${appendPlural(job, 'file')}`
|
||||
},
|
||||
file_copier: {
|
||||
name: `Copied`,
|
||||
icon: Copy,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)} ${JobCountTextCondition(job, 'file')}`
|
||||
subtext: `${numberWithCommas(job.task_count)} ${appendPlural(job, 'file')}`
|
||||
},
|
||||
file_cutter: {
|
||||
name: `Moved`,
|
||||
icon: Scissors,
|
||||
filesDiscovered: `${numberWithCommas(job.task_count)} ${JobCountTextCondition(job, 'file')}`
|
||||
subtext: `${numberWithCommas(job.task_count)} ${appendPlural(job, 'file')}`
|
||||
}
|
||||
});
|
||||
|
||||
const StatusColors: Record<JobReport['status'], string> = {
|
||||
Running: 'text-blue-500',
|
||||
Failed: 'text-red-500',
|
||||
Completed: 'text-green-500',
|
||||
CompletedWithErrors: 'text-orange-500',
|
||||
Queued: 'text-yellow-500',
|
||||
Canceled: 'text-gray-500',
|
||||
Paused: 'text-gray-500'
|
||||
};
|
||||
|
||||
interface JobProps {
|
||||
job: JobReport;
|
||||
clearJob?: (arg: string) => void;
|
||||
|
@ -121,15 +112,28 @@ interface JobProps {
|
|||
isGroup?: boolean;
|
||||
}
|
||||
|
||||
function formatEstimatedRemainingTime(end_date: string) {
|
||||
const duration = dayjs.duration(new Date(end_date).getTime() - Date.now());
|
||||
|
||||
if (duration.hours() > 0) {
|
||||
return `${duration.hours()} hour${duration.hours() > 1 ? 's' : ''} remaining`;
|
||||
} else if (duration.minutes() > 0) {
|
||||
return `${duration.minutes()} minute${duration.minutes() > 1 ? 's' : ''} remaining`;
|
||||
} else {
|
||||
return `${duration.seconds()} second${duration.seconds() > 1 ? 's' : ''} remaining`;
|
||||
}
|
||||
}
|
||||
|
||||
function Job({ job, clearJob, className, isGroup }: JobProps) {
|
||||
const niceData = getNiceData(job, isGroup)[job.name] || {
|
||||
name: job.name,
|
||||
icon: Question,
|
||||
filesDiscovered: job.name
|
||||
subtext: job.name
|
||||
};
|
||||
const isRunning = job.status === 'Running';
|
||||
|
||||
const time = useJobTimeText(job);
|
||||
// dayjs from seconds to time
|
||||
const time = isRunning ? formatEstimatedRemainingTime(job.estimated_completion) : '';
|
||||
|
||||
return (
|
||||
<li
|
||||
|
@ -148,20 +152,20 @@ function Job({ job, clearJob, className, isGroup }: JobProps) {
|
|||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex w-full flex-col">
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="flex items-center">
|
||||
<div className="truncate">
|
||||
<span className="truncate font-semibold">{niceData.name}</span>
|
||||
<span className="font-semibold truncate">{niceData.name}</span>
|
||||
<p className="mb-[5px] mt-[2px] flex gap-1 truncate text-ink-faint">
|
||||
{job.status === 'Queued' && <p>{job.status}:</p>}
|
||||
{niceData.filesDiscovered}
|
||||
{niceData.subtext}
|
||||
{time && ' • '}
|
||||
<span className="truncate">{time}</span>
|
||||
</p>
|
||||
<div className="flex gap-1 truncate text-ink-faint"></div>
|
||||
</div>
|
||||
<div className="grow" />
|
||||
<div className="ml-7 flex flex-row space-x-2">
|
||||
<div className="flex flex-row space-x-2 ml-7">
|
||||
{/* {job.status === 'Running' && (
|
||||
<Button size="icon">
|
||||
<Tooltip label="Coming Soon">
|
||||
|
@ -189,12 +193,18 @@ function Job({ job, clearJob, className, isGroup }: JobProps) {
|
|||
);
|
||||
}
|
||||
|
||||
function JobCountTextCondition(job: JobReport, word: string) {
|
||||
const addStoEnd = job.task_count > 1 || job?.task_count === 0 ? `${word}s` : `${word}`;
|
||||
return addStoEnd;
|
||||
function appendPlural(job: JobReport, word: string, niceDataKey?: string) {
|
||||
const condition = (condition: boolean) => (condition ? `${word}s` : `${word}`);
|
||||
switch (niceDataKey) {
|
||||
case 'file_identifier':
|
||||
return condition(job.metadata?.total_orphan_paths > 1);
|
||||
default:
|
||||
return condition(job.task_count > 1);
|
||||
}
|
||||
}
|
||||
|
||||
function numberWithCommas(x: number) {
|
||||
if (!x) return 0;
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Folder } from '@sd/assets/icons';
|
|||
import clsx from 'clsx';
|
||||
import dayjs from 'dayjs';
|
||||
import { X } from 'phosphor-react';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { JobReport } from '@sd/client';
|
||||
import { Button, ProgressBar, Tooltip } from '@sd/ui';
|
||||
import Job from './Job';
|
||||
|
@ -51,7 +51,7 @@ function JobGroup({ data, clearJob }: JobGroupProps) {
|
|||
size="icon"
|
||||
>
|
||||
<Tooltip label="Remove">
|
||||
<X className="h-4 w-4 cursor-pointer" />
|
||||
<X className="w-4 h-4 cursor-pointer" />
|
||||
</Tooltip>
|
||||
</Button>
|
||||
)}
|
||||
|
@ -67,17 +67,19 @@ function JobGroup({ data, clearJob }: JobGroupProps) {
|
|||
src={Folder}
|
||||
className={clsx('relative left-[-2px] top-2 z-10 mr-3 h-6 w-6')}
|
||||
/>
|
||||
<div className="flex w-full flex-col">
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="flex items-center">
|
||||
<div className="truncate">
|
||||
<p className="truncate font-semibold">
|
||||
<p className="font-semibold truncate">
|
||||
{allJobsCompleted
|
||||
? `Added location "${data.metadata.init.location.name || ''}"`
|
||||
? `Added location "${
|
||||
data.metadata.init.location.name || ''
|
||||
}"`
|
||||
: `Indexing "${data.metadata.init.location.name || ''}"`}
|
||||
</p>
|
||||
<p className="my-[2px] text-ink-faint">
|
||||
<b>{tasks.total} </b>
|
||||
{tasks.total <= 1 ? 'item' : 'items'}
|
||||
{tasks.total <= 1 ? 'task' : 'tasks'}
|
||||
{' • '}
|
||||
{date_started}
|
||||
{!allJobsCompleted && totalGroupTime && ' • '}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
import dayjs from 'dayjs';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { JobReport } from '@sd/client';
|
||||
import { useForceUpdate } from '~/util';
|
||||
|
||||
export function useJobTimeText(job: JobReport): string | null {
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
const elapsedTimeText = useMemo(() => {
|
||||
let newText: string;
|
||||
if (job.status === 'Running') {
|
||||
newText = `Elapsed ${dayjs(job.started_at).fromNow(true)}`;
|
||||
} else if (job.completed_at) {
|
||||
newText = `Took ${dayjs(job.started_at).from(job.completed_at, true)}`;
|
||||
} else {
|
||||
newText = `Took ${dayjs(job.started_at).fromNow(true)}`;
|
||||
}
|
||||
return newText;
|
||||
}, [job]);
|
||||
|
||||
useEffect(() => {
|
||||
if (job.status === 'Running') {
|
||||
const interval = setInterval(forceUpdate, 1000);
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [job.status, forceUpdate]);
|
||||
|
||||
return elapsedTimeText === 'Took NaN years' ? null : elapsedTimeText;
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
import { getIcon, iconNames } from '@sd/assets/util';
|
||||
import { useInfiniteQuery } from '@tanstack/react-query';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import 'react-loading-skeleton/dist/skeleton.css';
|
||||
import { z } from '@sd/ui/src/forms';
|
||||
import { Category } from '~/../packages/client/src';
|
||||
import { useExplorerTopBarOptions } from '~/hooks';
|
||||
import Explorer from '../Explorer';
|
||||
import { SEARCH_PARAMS } from '../Explorer/util';
|
||||
|
@ -11,8 +10,7 @@ import { TopBarPortal } from '../TopBar/Portal';
|
|||
import TopBarOptions from '../TopBar/TopBarOptions';
|
||||
import Statistics from '../overview/Statistics';
|
||||
import { Categories } from './Categories';
|
||||
import { useItems } from "./data"
|
||||
import { Category } from '~/../packages/client/src';
|
||||
import { useItems } from './data';
|
||||
|
||||
export type SearchArgs = z.infer<typeof SEARCH_PARAMS>;
|
||||
|
||||
|
@ -46,8 +44,7 @@ export const Component = () => {
|
|||
isFetchingNextPage={query.isFetchingNextPage}
|
||||
scrollRef={page?.ref}
|
||||
>
|
||||
<Statistics />
|
||||
<Categories selected={selectedCategory} onSelectedChanged={setSelectedCategory}/>
|
||||
<Categories selected={selectedCategory} onSelectedChanged={setSelectedCategory} />
|
||||
</Explorer>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -103,6 +103,8 @@ export type MasterPasswordChangeArgs = { password: Protected<string>; algorithm:
|
|||
*/
|
||||
export type NodeConfig = { id: string; name: string; p2p_port: number | null; p2p_email: string | null; p2p_img_url: string | null }
|
||||
|
||||
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 }
|
||||
|
||||
/**
|
||||
* This denotes the `StoredKey` version.
|
||||
*/
|
||||
|
@ -117,12 +119,12 @@ export type EncryptedKey = number[]
|
|||
|
||||
export type PeerId = 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 GenerateThumbsForLocationArgs = { id: number; path: string }
|
||||
|
||||
export type LibraryConfigWrapped = { uuid: string; config: LibraryConfig }
|
||||
|
||||
export type Node = { id: number; pub_id: number[]; name: string; platform: number; version: string | null; last_seen: string; timezone: string | null; date_created: string }
|
||||
|
||||
/**
|
||||
* These parameters define the password-hashing level.
|
||||
*
|
||||
|
@ -204,19 +206,17 @@ export type Salt = number[]
|
|||
*/
|
||||
export type Category = "Recents" | "Favorites" | "Photos" | "Videos" | "Movies" | "Music" | "Documents" | "Downloads" | "Encrypted" | "Projects" | "Applications" | "Archives" | "Databases" | "Games" | "Books" | "Contacts" | "Trash"
|
||||
|
||||
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 Node = { id: number; pub_id: number[]; name: string; platform: number; version: string | null; last_seen: string; timezone: string | null; date_created: string }
|
||||
|
||||
export type FileCopierJobInit = { source_location_id: number; source_path_id: number; target_location_id: number; target_path: string; target_file_name_suffix: string | null }
|
||||
|
||||
export type SetFavoriteArgs = { id: number; favorite: 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 FilePathFilterArgs = { locationId?: number | null; search?: string; extension?: string | null; createdAt?: OptionalRange<string>; path?: string | null; object?: ObjectFilterArgs | 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; date_accessed: string | null }
|
||||
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 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; key_id: number | null; date_created: string; date_modified: string; date_indexed: string }
|
||||
|
||||
export type IndexerRule = { id: number; kind: number; name: string; default: boolean; parameters: number[]; date_created: string; date_modified: string }
|
||||
|
||||
export type FilePathSearchOrdering = { name: SortOrder } | { sizeInBytes: SortOrder } | { dateCreated: SortOrder } | { dateModified: SortOrder } | { dateIndexed: SortOrder } | { object: ObjectSearchOrdering }
|
||||
|
||||
|
@ -229,10 +229,10 @@ export type IdentifyUniqueFilesArgs = { id: number; path: string }
|
|||
*/
|
||||
export type Algorithm = "XChaCha20Poly1305" | "Aes256Gcm"
|
||||
|
||||
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 OwnedOperationItem = { id: any; data: OwnedOperationData }
|
||||
|
||||
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 ObjectSearchOrdering = { dateAccessed: SortOrder }
|
||||
|
||||
export type CRDTOperationType = SharedOperation | RelationOperation | OwnedOperation
|
||||
|
@ -248,7 +248,7 @@ export type MaybeNot<T> = T | { not: T }
|
|||
|
||||
export type SpacedropArgs = { peer_id: PeerId; file_path: string[] }
|
||||
|
||||
export type JobReport = { id: string; name: string; action: string | null; data: number[] | null; metadata: any | null; is_background: boolean; errors_text: string[]; 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 JobReport = { id: string; name: string; action: string | null; data: number[] | null; metadata: any | null; is_background: boolean; errors_text: string[]; 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; estimated_completion: string }
|
||||
|
||||
export type ObjectFilterArgs = { favorite?: boolean | null; hidden?: boolean | null; dateAccessed?: MaybeNot<string | null> | null; kind?: number[]; tags?: number[] }
|
||||
|
||||
|
@ -302,6 +302,8 @@ export type OwnedOperationData = { Create: { [key: string]: any } } | { CreateMa
|
|||
|
||||
export type SharedOperationData = SharedOperationCreateData | { field: string; value: any } | null
|
||||
|
||||
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 TagUpdateArgs = { id: number; name: string | null; color: string | null }
|
||||
|
||||
export type ObjectValidatorArgs = { id: number; path: string }
|
||||
|
@ -310,11 +312,15 @@ export type TagAssignArgs = { object_id: number; tag_id: number; unassign: boole
|
|||
|
||||
export type ChangeNodeNameArgs = { name: 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; date_accessed: string | null }
|
||||
|
||||
/**
|
||||
* This defines all available password hashing algorithms.
|
||||
*/
|
||||
export type HashingAlgorithm = { name: "Argon2id"; params: Params } | { name: "BalloonBlake3"; params: Params }
|
||||
|
||||
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused" | "CompletedWithErrors"
|
||||
|
||||
export type FilePathWithObject = { 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; key_id: number | null; date_created: string; date_modified: string; date_indexed: string; object: Object | null }
|
||||
|
||||
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 }[] }
|
||||
|
@ -332,14 +338,8 @@ export type AutomountUpdateArgs = { uuid: string; status: boolean }
|
|||
|
||||
export type Protected<T> = T
|
||||
|
||||
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; key_id: number | null; date_created: string; date_modified: string; date_indexed: string }
|
||||
|
||||
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused" | "CompletedWithErrors"
|
||||
|
||||
export type RestoreBackupArgs = { password: Protected<string>; secret_key: Protected<string>; path: string }
|
||||
|
||||
export type IndexerRule = { id: number; kind: number; name: string; default: boolean; parameters: number[]; date_created: string; date_modified: string }
|
||||
|
||||
export type RelationOperation = { relation_item: string; relation_group: string; relation: string; data: RelationOperationData }
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue