format using tabs

This commit is contained in:
maxichrome 2022-05-22 23:07:35 -05:00
parent 198f52af20
commit a0d0938001
No known key found for this signature in database
GPG key ID: DDC459310E98B6AB
150 changed files with 5021 additions and 4855 deletions

View file

@ -43,8 +43,8 @@ body:
id: info
attributes:
label: Platform and versions
description: "Please include the output of `pnpm --version && cargo --version && rustc --version` along with information about your Operating System such as version and/or specific distribution if revelant."
render: shell
description: 'Please include the output of `pnpm --version && cargo --version && rustc --version` along with information about your Operating System such as version and/or specific distribution if revelant.'
render: Shell
validations:
required: true
@ -52,7 +52,7 @@ body:
id: logs
attributes:
label: Stack trace
render: shell
render: Shell
- type: textarea
id: context

View file

@ -1,3 +1,5 @@
# tell yaml plugin that this is the config file and not a template of its own:
# yaml-language-server: $schema=https://json.schemastore.org/github-issue-config.json
blank_issues_enabled: false
contact_links:
- name: 📝 Report Typo

View file

@ -1,10 +1,9 @@
<!-- Put any information about this PR up here -->
<!-- Which issue does this PR close? -->
<!-- If this PR does not have a corresponding issue,
make sure one gets created before you create this PR.
You can create a bug report or feature request at
https://github.com/spacedriveapp/spacedrive/issues/new/choose -->
Closes #(issue)

View file

@ -1,5 +1,4 @@
hard_tabs = true
tab_spaces = 4
match_block_trailing_comma = true
max_width = 90
newline_style = "Unix"

View file

@ -22,5 +22,7 @@
"editor.defaultFormatter": "matklad.rust-analyzer"
},
"rust-analyzer.procMacro.enable": true,
"rust-analyzer.diagnostics.experimental.enable": false
"rust-analyzer.diagnostics.experimental.enable": false,
"rust-analyzer.inlayHints.parameterHints.enable": false,
"rust-analyzer.inlayHints.typeHints.enable": false
}

View file

@ -1,4 +1,3 @@
# Contributor Covenant Code of Conduct
## Our Pledge
@ -18,23 +17,23 @@ diverse, inclusive, and healthy community.
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
@ -120,14 +119,14 @@ version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
[Mozilla's code of conduct enforcement ladder][mozilla coc].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
[https://www.contributor-covenant.org/faq][faq]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[mozilla coc]: https://github.com/mozilla/diversity
[faq]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View file

@ -61,6 +61,7 @@ If you are having issues ensure you are using the following versions of Rust and
### Pull Request
When you're finished with the changes, create a pull request, also known as a PR.
- Fill the "Ready for review" template so that we can review your PR. This template helps reviewers understand your changes as well as the purpose of your pull request.
- Don't forget to [link PR to issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) if you are solving one.
- Enable the checkbox to [allow maintainer edits](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so the branch can be updated for a merge.

View file

@ -38,7 +38,6 @@ Organize files across many devices in one place. From cloud services to offline
For independent creatives, hoarders and those that want to own their digital footprint. Spacedrive provides a file management experience like no other, and it's completely free.
<p align="center">
<img src="https://raw.githubusercontent.com/spacedriveapp/.github/main/profile/app.png" alt="Logo">
<br />

View file

@ -1,6 +1,5 @@
max_width = 100
hard_tabs = false
tab_spaces = 2
hard_tabs = true
newline_style = "Auto"
use_small_heuristics = "Default"
reorder_imports = true

View file

@ -1,7 +1,7 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { name, version } from './package.json';
import svg from "vite-plugin-svgr"
import svg from 'vite-plugin-svgr';
// https://vitejs.dev/config/
export default defineConfig({

View file

@ -28,12 +28,12 @@
* --syntax-cursor-line: hsla(220, 100%, 80%, 0.04);
*/
code[class*="language-"],
pre[class*="language-"] {
code[class*='language-'],
pre[class*='language-'] {
background: hsl(220, 9%, 6%);
color: hsl(220, 14%, 71%);
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: "Fira Code", "Fira Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace;
font-family: 'Fira Code', 'Fira Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
direction: ltr;
text-align: left;
white-space: pre;
@ -50,24 +50,24 @@
}
/* Selection */
code[class*="language-"]::-moz-selection,
code[class*="language-"] *::-moz-selection,
pre[class*="language-"] *::-moz-selection {
code[class*='language-']::-moz-selection,
code[class*='language-'] *::-moz-selection,
pre[class*='language-'] *::-moz-selection {
background: hsl(220, 13%, 28%);
color: inherit;
text-shadow: none;
}
code[class*="language-"]::selection,
code[class*="language-"] *::selection,
pre[class*="language-"] *::selection {
code[class*='language-']::selection,
code[class*='language-'] *::selection,
pre[class*='language-'] *::selection {
background: hsl(220, 13%, 28%);
color: inherit;
text-shadow: none;
}
/* Code blocks */
pre[class*="language-"] {
pre[class*='language-'] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
@ -75,7 +75,7 @@
}
/* Inline code */
:not(pre) > code[class*="language-"] {
:not(pre) > code[class*='language-'] {
padding: 0.2em 0.3em;
border-radius: 0.3em;
white-space: normal;
@ -83,8 +83,8 @@
/* Print */
@media print {
code[class*="language-"],
pre[class*="language-"] {
code[class*='language-'],
pre[class*='language-'] {
text-shadow: none;
}
}
@ -177,7 +177,10 @@
color: hsl(286, 60%, 67%);
}
.language-javascript .token.template-string > .token.interpolation > .token.interpolation-punctuation.punctuation {
.language-javascript
.token.template-string
> .token.interpolation
> .token.interpolation-punctuation.punctuation {
color: hsl(5, 48%, 51%);
}

View file

@ -7,7 +7,6 @@ html {
}
}
.landing-img {
background-image: url('/app.png');
background-size: contain;
@ -23,8 +22,6 @@ html {
-ms-animation: fadeInUp 3s;
}
.fade-in-heading {
animation: fadeInUp 1s;
}
@ -41,7 +38,6 @@ html {
}
}
.bloom {
@apply absolute w-96 h-96;
will-change: opacity;
@ -60,11 +56,11 @@ html {
animation-delay: 500ms;
}
&.bloom-two {
background: conic-gradient(from 90deg at 50% 50%, #c62dbb, #1D054B);
background: conic-gradient(from 90deg at 50% 50%, #c62dbb, #1d054b);
animation-delay: 300ms;
}
&.bloom-three {
background: conic-gradient(from 90deg at 50% 50%, #2d53c6, #1D054B);
background: conic-gradient(from 90deg at 50% 50%, #2d53c6, #1d054b);
animation-delay: 1100ms;
}
}

View file

@ -1,6 +1,5 @@
max_width = 100
hard_tabs = false
tab_spaces = 2
hard_tabs = true
newline_style = "Unix"
use_small_heuristics = "Default"
reorder_imports = true

View file

@ -1,3 +1,10 @@
import type { Platform } from "./Platform";
import type { Platform } from './Platform';
export interface Client { uuid: string, name: string, platform: Platform, tcp_address: string, last_seen: string, last_synchronized: string, }
export interface Client {
uuid: string;
name: string;
platform: Platform;
tcp_address: string;
last_seen: string;
last_synchronized: string;
}

View file

@ -1,2 +1,14 @@
export type ClientCommand = { key: "FileRead", params: { id: number, } } | { key: "FileDelete", params: { id: number, } } | { key: "LibDelete", params: { id: number, } } | { key: "TagCreate", params: { name: string, color: string, } } | { key: "TagUpdate", params: { name: string, color: string, } } | { key: "TagAssign", params: { file_id: number, tag_id: number, } } | { key: "TagDelete", params: { id: number, } } | { key: "LocCreate", params: { path: string, } } | { key: "LocUpdate", params: { id: number, name: string | null, } } | { key: "LocDelete", params: { id: number, } } | { key: "SysVolumeUnmount", params: { id: number, } } | { key: "GenerateThumbsForLocation", params: { id: number, path: string, } } | { key: "IdentifyUniqueFiles" };
export type ClientCommand =
| { key: 'FileRead'; params: { id: number } }
| { key: 'FileDelete'; params: { id: number } }
| { key: 'LibDelete'; params: { id: number } }
| { key: 'TagCreate'; params: { name: string; color: string } }
| { key: 'TagUpdate'; params: { name: string; color: string } }
| { key: 'TagAssign'; params: { file_id: number; tag_id: number } }
| { key: 'TagDelete'; params: { id: number } }
| { key: 'LocCreate'; params: { path: string } }
| { key: 'LocUpdate'; params: { id: number; name: string | null } }
| { key: 'LocDelete'; params: { id: number } }
| { key: 'SysVolumeUnmount'; params: { id: number } }
| { key: 'GenerateThumbsForLocation'; params: { id: number; path: string } }
| { key: 'IdentifyUniqueFiles' };

View file

@ -1,2 +1,10 @@
export type ClientQuery = { key: "ClientGetState" } | { key: "SysGetVolumes" } | { key: "LibGetTags" } | { key: "JobGetRunning" } | { key: "JobGetHistory" } | { key: "SysGetLocations" } | { key: "SysGetLocation", params: { id: number, } } | { key: "LibGetExplorerDir", params: { location_id: number, path: string, limit: number, } } | { key: "GetLibraryStatistics" };
export type ClientQuery =
| { key: 'ClientGetState' }
| { key: 'SysGetVolumes' }
| { key: 'LibGetTags' }
| { key: 'JobGetRunning' }
| { key: 'JobGetHistory' }
| { key: 'SysGetLocations' }
| { key: 'SysGetLocation'; params: { id: number } }
| { key: 'LibGetExplorerDir'; params: { location_id: number; path: string; limit: number } }
| { key: 'GetLibraryStatistics' };

View file

@ -1,3 +1,11 @@
import type { LibraryState } from "./LibraryState";
import type { LibraryState } from './LibraryState';
export interface ClientState { client_uuid: string, client_id: number, client_name: string, data_path: string, tcp_port: number, libraries: Array<LibraryState>, current_library_uuid: string, }
export interface ClientState {
client_uuid: string;
client_id: number;
client_name: string;
data_path: string;
tcp_port: number;
libraries: Array<LibraryState>;
current_library_uuid: string;
}

View file

@ -1,4 +1,10 @@
import type { ClientQuery } from "./ClientQuery";
import type { CoreResource } from "./CoreResource";
import type { ClientQuery } from './ClientQuery';
import type { CoreResource } from './CoreResource';
export type CoreEvent = { key: "InvalidateQuery", data: ClientQuery } | { key: "InvalidateQueryDebounced", data: ClientQuery } | { key: "InvalidateResource", data: CoreResource } | { key: "NewThumbnail", data: { cas_id: string, } } | { key: "Log", data: { message: string, } } | { key: "DatabaseDisconnected", data: { reason: string | null, } };
export type CoreEvent =
| { key: 'InvalidateQuery'; data: ClientQuery }
| { key: 'InvalidateQueryDebounced'; data: ClientQuery }
| { key: 'InvalidateResource'; data: CoreResource }
| { key: 'NewThumbnail'; data: { cas_id: string } }
| { key: 'Log'; data: { message: string } }
| { key: 'DatabaseDisconnected'; data: { reason: string | null } };

View file

@ -1,5 +1,11 @@
import type { File } from "./File";
import type { JobReport } from "./JobReport";
import type { LocationResource } from "./LocationResource";
import type { File } from './File';
import type { JobReport } from './JobReport';
import type { LocationResource } from './LocationResource';
export type CoreResource = "Client" | "Library" | { Location: LocationResource } | { File: File } | { Job: JobReport } | "Tag";
export type CoreResource =
| 'Client'
| 'Library'
| { Location: LocationResource }
| { File: File }
| { Job: JobReport }
| 'Tag';

View file

@ -1,8 +1,18 @@
import type { ClientState } from "./ClientState";
import type { DirectoryWithContents } from "./DirectoryWithContents";
import type { JobReport } from "./JobReport";
import type { LocationResource } from "./LocationResource";
import type { Statistics } from "./Statistics";
import type { Volume } from "./Volume";
import type { ClientState } from './ClientState';
import type { DirectoryWithContents } from './DirectoryWithContents';
import type { JobReport } from './JobReport';
import type { LocationResource } from './LocationResource';
import type { Statistics } from './Statistics';
import type { Volume } from './Volume';
export type CoreResponse = { key: "Success", data: null } | { key: "SysGetVolumes", data: Array<Volume> } | { key: "SysGetLocation", data: LocationResource } | { key: "SysGetLocations", data: Array<LocationResource> } | { key: "LibGetExplorerDir", data: DirectoryWithContents } | { key: "ClientGetState", data: ClientState } | { key: "LocCreate", data: LocationResource } | { key: "JobGetRunning", data: Array<JobReport> } | { key: "JobGetHistory", data: Array<JobReport> } | { key: "GetLibraryStatistics", data: Statistics };
export type CoreResponse =
| { key: 'Success'; data: null }
| { key: 'SysGetVolumes'; data: Array<Volume> }
| { key: 'SysGetLocation'; data: LocationResource }
| { key: 'SysGetLocations'; data: Array<LocationResource> }
| { key: 'LibGetExplorerDir'; data: DirectoryWithContents }
| { key: 'ClientGetState'; data: ClientState }
| { key: 'LocCreate'; data: LocationResource }
| { key: 'JobGetRunning'; data: Array<JobReport> }
| { key: 'JobGetHistory'; data: Array<JobReport> }
| { key: 'GetLibraryStatistics'; data: Statistics };

View file

@ -1,3 +1,6 @@
import type { FilePath } from "./FilePath";
import type { FilePath } from './FilePath';
export interface DirectoryWithContents { directory: FilePath, contents: Array<FilePath>, }
export interface DirectoryWithContents {
directory: FilePath;
contents: Array<FilePath>;
}

View file

@ -1,2 +1 @@
export type EncryptionAlgorithm = "None" | "AES128" | "AES192" | "AES256";
export type EncryptionAlgorithm = 'None' | 'AES128' | 'AES192' | 'AES256';

View file

@ -1,5 +1,24 @@
import type { EncryptionAlgorithm } from "./EncryptionAlgorithm";
import type { FileKind } from "./FileKind";
import type { FilePath } from "./FilePath";
import type { EncryptionAlgorithm } from './EncryptionAlgorithm';
import type { FileKind } from './FileKind';
import type { FilePath } from './FilePath';
export interface File { id: number, cas_id: string, integrity_checksum: string | null, size_in_bytes: string, kind: FileKind, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, encryption: EncryptionAlgorithm, ipfs_id: string | null, comment: string | null, date_created: string, date_modified: string, date_indexed: string, paths: Array<FilePath>, }
export interface File {
id: number;
cas_id: string;
integrity_checksum: string | null;
size_in_bytes: string;
kind: FileKind;
hidden: boolean;
favorite: boolean;
important: boolean;
has_thumbnail: boolean;
has_thumbstrip: boolean;
has_video_preview: boolean;
encryption: EncryptionAlgorithm;
ipfs_id: string | null;
comment: string | null;
date_created: string;
date_modified: string;
date_indexed: string;
paths: Array<FilePath>;
}

View file

@ -1,2 +1,10 @@
export type FileKind = "Unknown" | "Directory" | "Package" | "Archive" | "Image" | "Video" | "Audio" | "Plaintext" | "Alias";
export type FileKind =
| 'Unknown'
| 'Directory'
| 'Package'
| 'Archive'
| 'Image'
| 'Video'
| 'Audio'
| 'Plaintext'
| 'Alias';

View file

@ -1,2 +1,16 @@
export interface FilePath { id: number, is_dir: boolean, location_id: number, materialized_path: string, name: string, extension: string | null, file_id: number | null, parent_id: number | null, temp_cas_id: string | null, has_local_thumbnail: boolean, date_created: string, date_modified: string, date_indexed: string, permissions: string | null, }
export interface FilePath {
id: number;
is_dir: boolean;
location_id: number;
materialized_path: string;
name: string;
extension: string | null;
file_id: number | null;
parent_id: number | null;
temp_cas_id: string | null;
has_local_thumbnail: boolean;
date_created: string;
date_modified: string;
date_indexed: string;
permissions: string | null;
}

View file

@ -1,3 +1,12 @@
import type { JobStatus } from "./JobStatus";
import type { JobStatus } from './JobStatus';
export interface JobReport { id: string, date_created: string, date_modified: string, status: JobStatus, task_count: number, completed_task_count: number, message: string, seconds_elapsed: string, }
export interface JobReport {
id: string;
date_created: string;
date_modified: string;
status: JobStatus;
task_count: number;
completed_task_count: number;
message: string;
seconds_elapsed: string;
}

View file

@ -1,2 +1 @@
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed";
export type JobStatus = 'Queued' | 'Running' | 'Completed' | 'Canceled' | 'Failed';

View file

@ -1,2 +1,6 @@
export interface LibraryState { library_uuid: string, library_id: number, library_path: string, offline: boolean, }
export interface LibraryState {
library_uuid: string;
library_id: number;
library_path: string;
offline: boolean;
}

View file

@ -1,2 +1,10 @@
export interface LocationResource { id: number, name: string | null, path: string | null, total_capacity: number | null, available_capacity: number | null, is_removable: boolean | null, is_online: boolean, date_created: string, }
export interface LocationResource {
id: number;
name: string | null;
path: string | null;
total_capacity: number | null;
available_capacity: number | null;
is_removable: boolean | null;
is_online: boolean;
date_created: string;
}

View file

@ -1,2 +1 @@
export type Platform = "Unknown" | "Windows" | "MacOS" | "Linux" | "IOS" | "Android";
export type Platform = 'Unknown' | 'Windows' | 'MacOS' | 'Linux' | 'IOS' | 'Android';

View file

@ -1,2 +1,9 @@
export interface Statistics { total_file_count: number, total_bytes_used: string, total_bytes_capacity: string, total_bytes_free: string, total_unique_bytes: string, preview_media_bytes: string, library_db_size: string, }
export interface Statistics {
total_file_count: number;
total_bytes_used: string;
total_bytes_capacity: string;
total_bytes_free: string;
total_unique_bytes: string;
preview_media_bytes: string;
library_db_size: string;
}

View file

@ -1,2 +1,10 @@
export interface Volume { name: string, mount_point: string, total_capacity: bigint, available_capacity: bigint, is_removable: boolean, disk_type: string | null, file_system: string | null, is_root_filesystem: boolean, }
export interface Volume {
name: string;
mount_point: string;
total_capacity: bigint;
available_capacity: bigint;
is_removable: boolean;
disk_type: string | null;
file_system: string | null;
is_root_filesystem: boolean;
}

View file

@ -45,7 +45,9 @@ pub async fn run_migrations(ctx: &CoreContext) -> Result<()> {
};
let value: Vec<serde_json::Value> = client
._query_raw("SELECT name FROM sqlite_master WHERE type='table' AND name='_migrations'")
._query_raw(
"SELECT name FROM sqlite_master WHERE type='table' AND name='_migrations'",
)
.await
.unwrap();

View file

@ -54,7 +54,10 @@ impl Job for ThumbnailJob {
tokio::task::spawn_blocking(move || {
ctx.progress(vec![
JobReportUpdate::TaskCount(image_files.len()),
JobReportUpdate::Message(format!("Preparing to process {} files", image_files.len())),
JobReportUpdate::Message(format!(
"Preparing to process {} files",
image_files.len()
)),
]);
for (i, image_file) in image_files.iter().enumerate() {

View file

@ -0,0 +1 @@

View file

@ -0,0 +1 @@

View file

@ -4,13 +4,13 @@ use crate::job::jobs::JobReportUpdate;
use crate::{
file::FileError,
job::{jobs::Job, worker::WorkerContext},
prisma::{file_path},
prisma::file_path,
CoreContext,
};
use anyhow::Result;
use futures::executor::block_on;
use serde::{Deserialize, Serialize};
use prisma_client_rust::Direction;
use serde::{Deserialize, Serialize};
use super::checksum::generate_cas_id;
@ -104,7 +104,10 @@ impl Job for FileIdentifierJob {
let remaining = count_orphan_file_paths(&ctx.core_ctx).await?;
println!("Finished with {} files remaining because your code is bad.", remaining);
println!(
"Finished with {} files remaining because your code is bad.",
remaining
);
// if remaining > 0 {
// ctx.core_ctx.spawn_job(Box::new(FileIdentifierJob));
@ -162,9 +165,5 @@ pub fn prepare_file_values(file_path: &file_path::Data) -> Result<String> {
}
};
// TODO: add all metadata
Ok(format!(
"(\"{}\",\"{}\")",
cas_id,
"0"
))
Ok(format!("(\"{}\",\"{}\")", cas_id, "0"))
}

View file

@ -149,8 +149,7 @@ impl JobReport {
}
pub async fn create(&self, ctx: &CoreContext) -> Result<(), JobError> {
let config = state::get();
ctx
.database
ctx.database
.job()
.create(
job::id::set(self.id.clone()),
@ -164,8 +163,7 @@ impl JobReport {
Ok(())
}
pub async fn update(&self, ctx: &CoreContext) -> Result<(), JobError> {
ctx
.database
ctx.database
.job()
.find_unique(job::id::equals(self.id.clone()))
.update(vec![

View file

@ -29,8 +29,7 @@ pub struct WorkerContext {
impl WorkerContext {
pub fn progress(&self, updates: Vec<JobReportUpdate>) {
self
.sender
self.sender
.send(WorkerEvent::Progressed(updates))
.unwrap_or(());
}
@ -148,7 +147,8 @@ impl Worker {
worker.job_report.task_count = task_count as i32;
}
JobReportUpdate::CompletedTaskCount(completed_task_count) => {
worker.job_report.completed_task_count = completed_task_count as i32;
worker.job_report.completed_task_count =
completed_task_count as i32;
}
JobReportUpdate::Message(message) => {
worker.job_report.message = message;
@ -158,8 +158,7 @@ impl Worker {
}
}
}
ctx
.emit(CoreEvent::InvalidateQueryDebounced(
ctx.emit(CoreEvent::InvalidateQueryDebounced(
ClientQuery::JobGetRunning,
))
.await;
@ -168,11 +167,9 @@ impl Worker {
worker.job_report.status = JobStatus::Completed;
worker.job_report.update(&ctx).await.unwrap_or(());
ctx
.emit(CoreEvent::InvalidateQuery(ClientQuery::JobGetRunning))
ctx.emit(CoreEvent::InvalidateQuery(ClientQuery::JobGetRunning))
.await;
ctx
.emit(CoreEvent::InvalidateQuery(ClientQuery::JobGetHistory))
ctx.emit(CoreEvent::InvalidateQuery(ClientQuery::JobGetHistory))
.await;
break;
}
@ -180,8 +177,7 @@ impl Worker {
worker.job_report.status = JobStatus::Failed;
worker.job_report.update(&ctx).await.unwrap_or(());
ctx
.emit(CoreEvent::InvalidateQuery(ClientQuery::JobGetHistory))
ctx.emit(CoreEvent::InvalidateQuery(ClientQuery::JobGetHistory))
.await;
break;
}

View file

@ -48,8 +48,7 @@ impl CoreController {
pub async fn query(&self, query: ClientQuery) -> Result<CoreResponse, CoreError> {
// a one time use channel to send and await a response
let (sender, recv) = oneshot::channel();
self
.query_sender
self.query_sender
.send(ReturnableMessage {
data: query,
return_sender: sender,
@ -61,8 +60,7 @@ impl CoreController {
pub async fn command(&self, command: ClientCommand) -> Result<CoreResponse, CoreError> {
let (sender, recv) = oneshot::channel();
self
.command_sender
self.command_sender
.send(ReturnableMessage {
data: command,
return_sender: sender,
@ -89,16 +87,14 @@ pub struct CoreContext {
impl CoreContext {
pub fn spawn_job(&self, job: Box<dyn Job>) {
self
.internal_sender
self.internal_sender
.send(InternalEvent::JobIngest(job))
.unwrap_or_else(|e| {
println!("Failed to spawn job. {:?}", e);
});
}
pub fn queue_job(&self, job: Box<dyn Job>) {
self
.internal_sender
self.internal_sender
.send(InternalEvent::JobIngest(job))
.unwrap_or_else(|e| {
println!("Failed to queue job. {:?}", e);
@ -240,7 +236,9 @@ impl Node {
} else {
for library in self.state.libraries.iter() {
// init database for library
match library::loader::load(&ctx, &library.library_path, &library.library_uuid).await {
match library::loader::load(&ctx, &library.library_path, &library.library_uuid)
.await
{
Ok(library) => println!("Loaded library: {:?}", library),
Err(e) => println!("Error loading library: {:?}", e),
}
@ -328,11 +326,15 @@ impl Node {
file::explorer::open::open_dir(&ctx, &location_id, &path).await?,
),
ClientQuery::LibGetTags => todo!(),
ClientQuery::JobGetRunning => CoreResponse::JobGetRunning(self.jobs.get_running().await),
ClientQuery::JobGetHistory => CoreResponse::JobGetHistory(Jobs::get_history(&ctx).await?),
ClientQuery::GetLibraryStatistics => {
CoreResponse::GetLibraryStatistics(library::statistics::Statistics::calculate(&ctx).await?)
ClientQuery::JobGetRunning => {
CoreResponse::JobGetRunning(self.jobs.get_running().await)
}
ClientQuery::JobGetHistory => {
CoreResponse::JobGetHistory(Jobs::get_history(&ctx).await?)
}
ClientQuery::GetLibraryStatistics => CoreResponse::GetLibraryStatistics(
library::statistics::Statistics::calculate(&ctx).await?,
),
ClientQuery::GetNodes => todo!(),
})
}

View file

@ -0,0 +1 @@

View file

@ -0,0 +1 @@

View file

@ -3,7 +3,8 @@ use futures::{channel::mpsc, SinkExt};
use serde::{Deserialize, Serialize};
use super::{
crdt::PoMethod, examples::tag::TagCreate, CrdtCtx, FakeCoreContext, PropertyOperation, SyncMethod,
crdt::PoMethod, examples::tag::TagCreate, CrdtCtx, FakeCoreContext, PropertyOperation,
SyncMethod,
};
pub struct SyncEngine {

View file

@ -50,7 +50,8 @@ static DOTFILE_NAME: &str = ".spacedrive";
// - accessible on from the local filesystem
// - already exists in the database
pub async fn check_location(path: &str) -> Result<DotSpacedrive, LocationError> {
let dotfile: DotSpacedrive = match fs::File::open(format!("{}/{}", path.clone(), DOTFILE_NAME)) {
let dotfile: DotSpacedrive = match fs::File::open(format!("{}/{}", path.clone(), DOTFILE_NAME))
{
Ok(file) => serde_json::from_reader(file).unwrap_or(DotSpacedrive::default()),
Err(e) => return Err(LocationError::DotfileReadFailure(e)),
};
@ -158,7 +159,9 @@ pub async fn create_location(ctx: &CoreContext, path: &str) -> Result<LocationRe
.create(
location::pub_id::set(uuid.to_string()),
vec![
location::name::set(Some(p.file_name().unwrap().to_string_lossy().to_string())),
location::name::set(Some(
p.file_name().unwrap().to_string_lossy().to_string(),
)),
location::is_online::set(true),
location::local_path::set(Some(path.to_string())),
],
@ -189,8 +192,7 @@ pub async fn create_location(ctx: &CoreContext, path: &str) -> Result<LocationRe
Err(e) => Err(LocationError::DotfileWriteFailure(e, path.to_string()))?,
}
ctx
.emit(CoreEvent::InvalidateQuery(ClientQuery::SysGetLocations))
ctx.emit(CoreEvent::InvalidateQuery(ClientQuery::SysGetLocations))
.await;
location

View file

@ -75,8 +75,8 @@ impl Volume {
let mut name = disk.name().to_str().unwrap_or("Volume").to_string();
let is_removable = disk.is_removable();
let file_system =
String::from_utf8(disk.file_system().to_vec()).unwrap_or_else(|_| "Err".to_string());
let file_system = String::from_utf8(disk.file_system().to_vec())
.unwrap_or_else(|_| "Err".to_string());
let disk_type = match disk.type_() {
sysinfo::DiskType::SSD => "SSD".to_string(),
@ -84,7 +84,8 @@ impl Volume {
_ => "Removable Disk".to_string(),
};
if cfg!(target_os = "macos") && mount_point == "/" || mount_point == "/System/Volumes/Data"
if cfg!(target_os = "macos") && mount_point == "/"
|| mount_point == "/System/Volumes/Data"
{
name = "Macintosh HD".to_string();
mount_point = "/".to_string();

View file

@ -1,5 +1,5 @@
# Core view
The primary screen in the Spacedrive app is of your entire virtual network, every "core" is a device under your full command. It is presented in a large panel list view, featuring bold visuals and quick interactions with your fleet.
Recent files, recent locations and settings are part of these panels, that can be customized at will.

View file

@ -1,22 +1,26 @@
# Roadmap
**Complete (Still Testing):**
- **File discovery** - Scan devices, drives and cloud accounts to build a directory of all files with metadata.
- **Preview generation** - Auto generate lower resolution stand-ins for image and video.
- **Statistics** - Total capacity, index size, preview media size, free space etc.
**In progress:**
- **File Explorer** - Browse online/offline storage locations, view files with metadata, perform basic CRUD.
- **Realtime synchronization** - Data index synchronized in realtime between devices, prioritizing peer-to-peer LAN connections (WiFi sync).
- **Self hosted** - Spacedrive can be deployed as a service, behaving as just another device powering your personal cloud.
**To be developed (MVP):**
- **Photos** - Photo and video albums similar to Apple/Google photos.
- **Search** - Deep search into your filesystem with a keybind, including offline locations.
- **Tags** - Define routines on custom tags to automate workflows, easily tag files individually, in bulk and automatically via rules.
- **Extensions** - Build tools on top of Spacedrive, extend functionality and integrate third party services. Extension directory on [spacedrive.com/extensions](/extensions).
**To be developed (Post-MVP):**
- **Spacedrive Cloud** - We'll host an always-on cloud device for you, with pay-as-you-go plans for storage.
- **Cloud integration** - Index & backup to Apple Photos, Google Drive, Dropbox, OneDrive & Mega + easy API for the community to add more.
- **Encrypted vault(s)** - Effortlessly manage & encrypt sensitive files, built on top of VeraCrypt. Encrypt individual files or create flexible-size vaults.

View file

@ -4,8 +4,11 @@ import ProgressBar from '../primitive/ProgressBar';
import { Transition } from '@headlessui/react';
import clsx from 'clsx';
const MiddleTruncatedText = ({ children, ...props }: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>) => {
const text = children?.toString() ?? "";
const MiddleTruncatedText = ({
children,
...props
}: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>) => {
const text = children?.toString() ?? '';
const first = text.substring(0, text.length / 2);
const last = text.substring(first.length);
@ -16,11 +19,29 @@ const MiddleTruncatedText = ({ children, ...props }: DetailedHTMLProps<HTMLAttri
return (
<div className="whitespace-nowrap overflow-hidden w-full">
<span {...props} style={{ maxWidth: `calc(100% - (1em * ${endWidth}))`, minWidth: startWidth }} className={clsx(props?.className, "text-ellipsis inline-block align-bottom whitespace-nowrap overflow-hidden")}>{first}</span>
<span {...props} style={{ maxWidth: `calc(100% - (1em * ${startWidth}))`, direction: "rtl" }} className={clsx(props?.className, "inline-block align-bottom whitespace-nowrap overflow-hidden")}>{last}</span>
<span
{...props}
style={{ maxWidth: `calc(100% - (1em * ${endWidth}))`, minWidth: startWidth }}
className={clsx(
props?.className,
'text-ellipsis inline-block align-bottom whitespace-nowrap overflow-hidden'
)}
>
{first}
</span>
<span
{...props}
style={{ maxWidth: `calc(100% - (1em * ${startWidth}))`, direction: 'rtl' }}
className={clsx(
props?.className,
'inline-block align-bottom whitespace-nowrap overflow-hidden'
)}
>
{last}
</span>
</div>
)
}
);
};
export default function RunningJobsWidget() {
const { data: jobs } = useBridgeQuery('JobGetRunning');
@ -39,7 +60,9 @@ export default function RunningJobsWidget() {
>
<div key={job.id} className="flex flex-col px-2 pt-1.5 pb-2 bg-gray-700 rounded">
{/* <span className="mb-0.5 text-tiny font-bold text-gray-400">{job.status} Job</span> */}
<MiddleTruncatedText className="mb-1.5 text-gray-450 text-tiny">{job.message}</MiddleTruncatedText>
<MiddleTruncatedText className="mb-1.5 text-gray-450 text-tiny">
{job.message}
</MiddleTruncatedText>
<ProgressBar value={job.completed_task_count} total={job.task_count} />
</div>
</Transition>

View file

@ -32,7 +32,6 @@ const Heading: React.FC<{ className?: string; children: string }> = ({ children,
export const SettingsScreen: React.FC<{}> = () => {
return (
<div className="flex flex-row w-full">
<div className="h-full border-r border-gray-100 w-60 dark:border-gray-550">
<div data-tauri-drag-region className="w-full h-7" />
<div className="p-5 pt-0">

View file

@ -3,7 +3,9 @@ button {
@apply cursor-default;
}
body { font-family: "InterVariable", sans-serif; }
body {
font-family: 'InterVariable', sans-serif;
}
.no-scrollbar {
-ms-overflow-style: none; /* for Internet Explorer, Edge */
@ -51,14 +53,13 @@ body { font-family: "InterVariable", sans-serif; }
width: 8px;
}
&::-webkit-scrollbar-track {
@apply bg-transparent rounded-[6px] my-[10px]
@apply bg-transparent rounded-[6px] my-[10px];
}
&::-webkit-scrollbar-thumb {
@apply rounded-[6px] bg-gray-300 dark:bg-gray-550;
}
}
@keyframes fadeIn {
from {
opacity: 0;
@ -98,7 +99,6 @@ body { font-family: "InterVariable", sans-serif; }
}
}
.dialog-overlay[data-state='open'] {
animation: fadeIn 200ms ease-out forwards;
}
@ -106,8 +106,8 @@ body { font-family: "InterVariable", sans-serif; }
animation: fadeIn 200ms ease-out forwards;
}
.dialog-content[data-state='open'] {
-webkit-animation: slide-top 0.3s cubic-bezier(0.215, 0.610, 0.355, 1.000) both;
animation: slide-top 0.3s cubic-bezier(0.215, 0.610, 0.355, 1.000) both;
-webkit-animation: slide-top 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) both;
animation: slide-top 0.3s cubic-bezier(0.215, 0.61, 0.355, 1) both;
}
.dialog-content[data-state='closed'] {
animation: bounceDown 100ms ease-in forwards;