This commit is contained in:
Jamie Pine
2022-04-24 09:50:22 -07:00
parent 7cf38af201
commit 79522d9a50
14 changed files with 218 additions and 117 deletions

View File

@@ -52,7 +52,43 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Socket {
Ok(ws::Message::Text(text)) => {
let msg: SocketMessage = serde_json::from_str(&text).unwrap();
ctx.notify(msg);
let core = self.core.clone();
let recipient = ctx.address().recipient();
let fut = async move {
match msg.payload {
SocketMessagePayload::Query(query) => {
match core.query(query).await {
Ok(response) => recipient.do_send(SocketResponse {
id: msg.id.clone(),
payload: SocketResponsePayload::Query(response),
}),
Err(err) => {
// println!("query error: {:?}", err);
// Err(err.to_string())
},
};
},
SocketMessagePayload::Command(command) => {
match core.command(command).await {
Ok(response) => recipient.do_send(SocketResponse {
id: msg.id.clone(),
payload: SocketResponsePayload::Query(response),
}),
Err(err) => {
// println!("command error: {:?}", err);
// Err(err.to_string())
},
};
},
_ => {},
}
};
fut.into_actor(self).spawn(ctx);
()
},
_ => (),
}
@@ -82,50 +118,6 @@ impl Handler<SocketResponse> for Socket {
}
}
impl Handler<SocketMessage> for Socket {
type Result = ();
fn handle(&mut self, msg: SocketMessage, ctx: &mut Self::Context) -> Self::Result {
let core = self.core.clone();
let recipient = ctx.address().recipient();
let fut = async move {
match msg.payload {
SocketMessagePayload::Query(query) => {
match core.query(query).await {
Ok(response) => recipient.do_send(SocketResponse {
id: msg.id.clone(),
payload: SocketResponsePayload::Query(response),
}),
Err(err) => {
// println!("query error: {:?}", err);
// Err(err.to_string())
},
};
},
SocketMessagePayload::Command(command) => {
match core.command(command).await {
Ok(response) => recipient.do_send(SocketResponse {
id: msg.id.clone(),
payload: SocketResponsePayload::Query(response),
}),
Err(err) => {
// println!("command error: {:?}", err);
// Err(err.to_string())
},
};
},
_ => {},
}
};
fut.into_actor(self).spawn(ctx);
()
}
}
#[get("/")]
async fn index() -> impl Responder {
format!("Spacedrive Server!")

View File

@@ -0,0 +1,37 @@
/*
Warnings:
- You are about to drop the column `total_byte_capacity` on the `library_statistics` table. All the data in the column will be lost.
*/
-- CreateTable
CREATE TABLE "FileConflict" (
"original_file_id" INTEGER NOT NULL,
"detactched_file_id" INTEGER NOT NULL
);
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_library_statistics" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"date_captured" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"library_id" INTEGER NOT NULL,
"total_file_count" INTEGER NOT NULL DEFAULT 0,
"total_bytes_used" TEXT NOT NULL DEFAULT '0',
"total_bytes_capacity" TEXT NOT NULL DEFAULT '0',
"total_unique_bytes" TEXT NOT NULL DEFAULT '0',
"total_bytes_free" TEXT NOT NULL DEFAULT '0',
"preview_media_bytes" TEXT NOT NULL DEFAULT '0'
);
INSERT INTO "new_library_statistics" ("date_captured", "id", "library_id", "total_bytes_used", "total_file_count", "total_unique_bytes") SELECT "date_captured", "id", "library_id", "total_bytes_used", "total_file_count", "total_unique_bytes" FROM "library_statistics";
DROP TABLE "library_statistics";
ALTER TABLE "new_library_statistics" RENAME TO "library_statistics";
CREATE UNIQUE INDEX "library_statistics_library_id_key" ON "library_statistics"("library_id");
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;
-- CreateIndex
CREATE UNIQUE INDEX "FileConflict_original_file_id_key" ON "FileConflict"("original_file_id");
-- CreateIndex
CREATE UNIQUE INDEX "FileConflict_detactched_file_id_key" ON "FileConflict"("detactched_file_id");

View File

@@ -43,13 +43,15 @@ model Library {
}
model LibraryStatistics {
id Int @id @default(autoincrement())
date_captured DateTime @default(now())
library_id Int @unique
total_file_count Int @default(0)
total_bytes_used String @default("0")
total_byte_capacity String @default("0")
total_unique_bytes String @default("0")
id Int @id @default(autoincrement())
date_captured DateTime @default(now())
library_id Int @unique
total_file_count Int @default(0)
total_bytes_used String @default("0")
total_bytes_capacity String @default("0")
total_unique_bytes String @default("0")
total_bytes_free String @default("0")
preview_media_bytes String @default("0")
@@map("library_statistics")
}

View File

@@ -1,20 +1,15 @@
use anyhow::Result;
use thiserror::Error;
use uuid::Uuid;
use crate::state::client::LibraryState;
use crate::{db::migrate, prisma::library, state};
use crate::{prisma, Core};
use super::LibraryError;
pub static LIBRARY_DB_NAME: &str = "library.db";
pub static DEFAULT_NAME: &str = "My Library";
#[derive(Error, Debug)]
pub enum LibraryError {
#[error("Database error")]
DatabaseError(#[from] prisma::QueryError),
}
pub async fn get(core: &Core) -> Result<library::Data, LibraryError> {
let config = state::client::get();
let db = &core.database;

View File

@@ -1 +1,14 @@
pub mod loader;
pub mod statistics;
use thiserror::Error;
use crate::{prisma, sys::SysError};
#[derive(Error, Debug)]
pub enum LibraryError {
#[error("Database error")]
DatabaseError(#[from] prisma::QueryError),
#[error("System error")]
SysError(#[from] SysError),
}

View File

@@ -0,0 +1,67 @@
use crate::{prisma::library_statistics, state::client, CoreContext};
use serde::{Deserialize, Serialize};
use ts_rs::TS;
use super::LibraryError;
#[derive(Debug, Serialize, Deserialize, TS, Clone)]
#[ts(export)]
pub struct Statistics {
total_file_count: i32,
total_bytes_used: String,
total_bytes_capacity: String,
total_bytes_free: String,
total_unique_bytes: String,
preview_media_bytes: String,
library_db_size: String,
}
impl Into<Statistics> for library_statistics::Data {
fn into(self) -> Statistics {
Statistics {
total_file_count: self.total_file_count,
total_bytes_used: self.total_bytes_used,
total_bytes_capacity: self.total_bytes_capacity,
total_bytes_free: self.total_bytes_free,
total_unique_bytes: self.total_unique_bytes,
preview_media_bytes: self.preview_media_bytes,
library_db_size: String::new(),
}
}
}
impl Default for Statistics {
fn default() -> Self {
Self {
total_file_count: 0,
total_bytes_used: String::new(),
total_bytes_capacity: String::new(),
total_bytes_free: String::new(),
total_unique_bytes: String::new(),
preview_media_bytes: String::new(),
library_db_size: String::new(),
}
}
}
impl Statistics {
pub async fn recalculate(ctx: &CoreContext) -> Result<(), LibraryError> {
let config = client::get();
let db = &ctx.database;
let library_data = config.get_current_library();
let library_statistics_db = match db
.library_statistics()
.find_unique(library_statistics::id::equals(library_data.library_id))
.exec()
.await?
{
Some(library_statistics_db) => library_statistics_db.into(),
// create the default values if database has no entry
None => Statistics::default(),
};
Ok(())
}
}

View File

@@ -31,6 +31,7 @@ pub static CLIENT_STATE_CONFIG_NAME: &str = "client_state.json";
#[ts(export)]
pub struct LibraryState {
pub library_uuid: String,
pub library_id: i32,
pub library_path: String,
pub offline: bool,
}

View File

@@ -3,6 +3,7 @@
# Todo
- Landing sections
- Client pool
- Custom scrollbars
- Tag files
- Right click menu

View File

@@ -14,7 +14,7 @@ import { ExplorerScreen } from './screens/Explorer';
import { useCoreEvents } from './hooks/useCoreEvents';
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';
import { OverviewScreen } from './screens/Overview';
import { SpacesScreen } from './screens/Spaces';
import { DebugScreen } from './screens/Debug';
import { Modal } from './components/layout/Modal';
import GeneralSettings from './screens/settings/GeneralSettings';
import SlideUp from './components/transitions/SlideUp';
@@ -27,6 +27,7 @@ import { Button } from '@sd/ui';
import { CoreEvent } from '@sd/core';
import clsx from 'clsx';
import './style.scss';
import { ContentScreen } from './screens/Content';
const queryClient = new QueryClient();
@@ -114,7 +115,8 @@ function Router() {
<Route path="/" element={<AppLayout />}>
<Route index element={<RedirectPage to="/overview" />} />
<Route path="overview" element={<OverviewScreen />} />
<Route path="spaces" element={<SpacesScreen />} />
<Route path="content" element={<ContentScreen />} />
<Route path="debug" element={<DebugScreen />} />
<Route path="settings/*" element={<SettingsRoutes />} />
<Route path="explorer/:id" element={<ExplorerScreen />} />
<Route path="*" element={<NotFound />} />

View File

@@ -1,7 +1,7 @@
import { LockClosedIcon } from '@heroicons/react/outline';
import { CogIcon, EyeOffIcon, PlusIcon, ServerIcon } from '@heroicons/react/solid';
import clsx from 'clsx';
import { CirclesFour, EjectSimple, MonitorPlay, Planet } from 'phosphor-react';
import { CirclesFour, Code, EjectSimple, MonitorPlay, Planet } from 'phosphor-react';
import React, { useContext, useEffect, useState } from 'react';
import { NavLink, NavLinkProps } from 'react-router-dom';
import { TrafficLights } from '../os/TrafficLights';
@@ -111,10 +111,14 @@ export const Sidebar: React.FC<SidebarProps> = (props) => {
<Icon component={Planet} />
Overview
</SidebarLink>
<SidebarLink to="spaces">
<SidebarLink to="content">
<Icon component={CirclesFour} />
Content
</SidebarLink>
<SidebarLink to="debug">
<Icon component={Code} />
Debug
</SidebarLink>
{/* <SidebarLink to="explorer">
<Icon component={MonitorPlay} />
Explorer
@@ -141,7 +145,8 @@ export const Sidebar: React.FC<SidebarProps> = (props) => {
)}
>
<div className="w-[18px] mr-2 -mt-0.5">
{isActive ? <FolderWhite /> : <Folder />}
<FolderWhite className={clsx(!isActive && 'hidden')} />
<Folder className={clsx(isActive && 'hidden')} />
</div>
{location.name}
<div className="flex-grow" />

View File

@@ -0,0 +1,13 @@
// import { useBridgeCommand, useBridgeQuery } from '@sd/client';
import React from 'react';
export const ContentScreen: React.FC<{}> = (props) => {
return (
<div className="flex flex-col w-full h-screen p-5 overflow-x-scroll">
<div className="flex flex-col space-y-5 pb-7">
<h1 className="text-lg font-bold ">Content</h1>
</div>
</div>
);
};

View File

@@ -1,18 +1,41 @@
import { useBridgeQuery } from '@sd/client';
import { useBridgeCommand, useBridgeQuery } from '@sd/client';
import { Button } from '@sd/ui';
import React from 'react';
import ReactJson from 'react-json-view';
import FileItem from '../components/file/FileItem';
import CodeBlock from '../components/primitive/Codeblock';
import { Tag } from '../components/primitive/Tag';
export const SpacesScreen: React.FC<{}> = (props) => {
export const DebugScreen: React.FC<{}> = (props) => {
const { data: client } = useBridgeQuery('ClientGetState');
const { data: jobs } = useBridgeQuery('JobGetRunning');
const { data: jobHistory } = useBridgeQuery('JobGetHistory');
const { mutate: purgeDB } = useBridgeCommand('PurgeDatabase', {
onMutate: () => {
alert('Database purged');
}
});
const { mutate: identifyFiles } = useBridgeCommand('IdentifyUniqueFiles');
return (
<div className="flex flex-col w-full h-screen p-5 overflow-x-scroll">
<div className="flex flex-col space-y-5 pb-7">
<h1 className="text-lg font-bold ">Developer Debugger</h1>
<div className="flex flex-row pb-4 space-x-2">
<Button className="w-40" variant="gray" size="sm" onClick={() => {}}>
Open data folder
</Button>
<Button className="w-40" variant="gray" size="sm" onClick={() => purgeDB(undefined)}>
Purge database
</Button>
<Button
className="w-40"
variant="gray"
size="sm"
onClick={() => identifyFiles(undefined)}
>
Identify unique files
</Button>
</div>
<h1 className="text-sm font-bold ">Running Jobs</h1>
<CodeBlock src={{ ...jobs }} />
<h1 className="text-sm font-bold ">Job History</h1>

View File

@@ -11,15 +11,6 @@ import { useBridgeCommand, useBridgeQuery } from '@sd/client';
export default function GeneralSettings() {
const { data: volumes } = useBridgeQuery('SysGetVolumes');
const [fakeSliderVal, setFakeSliderVal] = useState([30, 0]);
const { mutate: purgeDB } = useBridgeCommand('PurgeDatabase', {
onMutate: () => {
alert('Database purged');
}
});
const { mutate: identifyFiles } = useBridgeCommand('IdentifyUniqueFiles');
return (
<div className="flex flex-col flex-grow max-w-4xl space-y-4">
<div className="mt-3 mb-3">
@@ -31,17 +22,7 @@ export default function GeneralSettings() {
<b>Note: </b>This is a pre-alpha build of Spacedrive, many features are yet to be
functional.
</p>
<div className="flex flex-row pb-4 space-x-2">
<Button className="w-40" variant="gray" size="sm" onClick={() => {}}>
Open data folder
</Button>
<Button className="w-40" variant="gray" size="sm" onClick={() => purgeDB(undefined)}>
Purge database
</Button>
<Button className="w-40" variant="gray" size="sm" onClick={() => identifyFiles(undefined)}>
Identify unique files
</Button>
</div>
{/* <InputContainer
title="Test scan directory"
description="This will create a job to scan the directory you specify to the database."
@@ -83,37 +64,6 @@ export default function GeneralSettings() {
}
/>
</div>
<Button className="mb-3" variant="primary">
Add Location
</Button>
</div>
</InputContainer>
<InputContainer
title="Volumes"
description="A list of mounted volumes on this machine, for no reason."
>
<Slider
step={5}
value={fakeSliderVal}
onValueChange={setFakeSliderVal}
defaultValue={[25, 75]}
/>
</InputContainer>
<InputContainer
title="A long input"
description="Local cache storage for media previews and thumbnails."
>
<div className="flex flex-row">
<Input
className="flex-grow"
placeholder="/users/jamie/Library/Application Support/spacedrive/cache"
/>
</div>
</InputContainer>
<InputContainer title="Vault" description="Enable vault storage with VeraCrypt.">
<div className="flex flex-row">
<Button variant="primary">Enable Vault</Button>
{/*<Input className="flex-grow" value="jeff" placeholder="/users/jamie/Desktop" />*/}
</div>
</InputContainer>

BIN
pnpm-lock.yaml generated
View File

Binary file not shown.