Skip to content

Commit

Permalink
Open Trash from the application (#2338)
Browse files Browse the repository at this point in the history
* Open Trash from the application

* Working Trash Sidebar Button

* Small UI fixes

* Update common.json

* Move openTrash to Tauri Command instead of RSPC

* format and remove type assertion

---------

Co-authored-by: Utku Bakir <[email protected]>
  • Loading branch information
Rocky43007 and utkubakir committed Apr 22, 2024
1 parent 745399e commit b4037d6
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 29 deletions.
43 changes: 43 additions & 0 deletions apps/desktop/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{
collections::HashMap,
fs,
path::PathBuf,
process::Command,
sync::{Arc, Mutex, PoisonError},
time::Duration,
};
Expand Down Expand Up @@ -149,6 +150,47 @@ async fn open_logs_dir(node: tauri::State<'_, Arc<Node>>) -> Result<(), ()> {
})
}

#[tauri::command(async)]
#[specta::specta]
async fn open_trash_in_os_explorer() -> Result<(), ()> {
#[cfg(target_os = "macos")]
{
let full_path = format!("{}/.Trash/", std::env::var("HOME").unwrap());

Command::new("open")
.arg(full_path)
.spawn()
.map_err(|err| error!("Error opening trash: {err:#?}"))?
.wait()
.map_err(|err| error!("Error opening trash: {err:#?}"))?;

return Ok(());
}

#[cfg(target_os = "windows")]
{
Command::new("explorer")
.arg("shell:RecycleBinFolder")
.spawn()
.map_err(|err| error!("Error opening trash: {err:#?}"))?
.wait()
.map_err(|err| error!("Error opening trash: {err:#?}"))?;
return Ok(());
}

#[cfg(target_os = "linux")]
{
Command::new("xdg-open")
.arg("~/.local/share/Trash/")
.spawn()
.map_err(|err| error!("Error opening trash: {err:#?}"))?
.wait()
.map_err(|err| error!("Error opening trash: {err:#?}"))?;

return Ok(());
}
}

#[derive(Debug, Clone, Serialize, Deserialize, specta::Type, tauri_specta::Event)]
#[serde(tag = "type")]
pub enum DragAndDropEvent {
Expand Down Expand Up @@ -218,6 +260,7 @@ async fn main() -> tauri::Result<()> {
reload_webview,
set_menu_bar_item_state,
request_fda_macos,
open_trash_in_os_explorer,
file::open_file_paths,
file::open_ephemeral_files,
file::get_file_path_open_with_apps,
Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ export const commands = {
async requestFdaMacos(): Promise<null> {
return await TAURI_INVOKE('plugin:tauri-specta|request_fda_macos');
},
async openTrashInOsExplorer(): Promise<__Result__<null, null>> {
try {
return {
status: 'ok',
data: await TAURI_INVOKE('plugin:tauri-specta|open_trash_in_os_explorer')
};
} catch (e) {
if (e instanceof Error) throw e;
else return { status: 'error', error: e as any };
}
},
async openFilePaths(
library: string,
ids: number[]
Expand Down
4 changes: 2 additions & 2 deletions core/src/api/search/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, path::PathBuf};
use std::{collections::HashMap, path::PathBuf, process::Command};

use crate::{
api::{locations::ExplorerItem, utils::library},
Expand Down Expand Up @@ -28,7 +28,7 @@ use futures::StreamExt;
use rspc::{alpha::AlphaRouter, ErrorCode};
use serde::{Deserialize, Serialize};
use specta::Type;
use tracing::{error, warn};
use tracing::{error, info, warn};

pub mod file_path;
pub mod media_data;
Expand Down
8 changes: 3 additions & 5 deletions docs/developers/technology/normalised-cache.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,16 @@ This means the queries will always render the newest version of the model.

## Terminology

- `CacheNode`: A node in the cache - this contains the data and can be identified by the model's name and unique ID within the data (eg. database primary key).
- `Reference<T>`: A reference to a node in the cache - This contains the model's name and unique ID.
- `CacheNode`: A node in the cache - this contains the data and can be identified by the model's name and unique ID within the data (eg. database primary key).
- `Reference<T>`: A reference to a node in the cache - This contains the model's name and unique ID.

## High level overview

We turn the data on the backend into a list of `CacheNode`'s and a list of `Reference<T>`'s and then return it to the frontend.

We insert the `CacheNode`'s into a global cache on the frontend and then use the `Reference<T>`'s to reconstruct the data by looking up the `CacheNode`'s.

When the cache changes (from another query, invalidation, etc), we can reconstruct *all* queries using their `Reference<T>`'s to reflect the updated data.

When the cache changes (from another query, invalidation, etc), we can reconstruct _all_ queries using their `Reference<T>`'s to reflect the updated data.

## Rust usage

Expand Down Expand Up @@ -129,7 +128,6 @@ const filePaths = useCache(query.data?.file_paths);

This is only possible because `useNodes` and `useCache` take in a specific key, instead of the whole `data` object, so you can tell it where to look.


## Known issues

### Specta support
Expand Down
20 changes: 10 additions & 10 deletions docs/developers/technology/rspc.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@ We use a fork based on [rspc 0.1.4](https://docs.rs/rspc) which contains heavy m

## What's different?

- A super pre-release version of rspc v1's procedure syntax.
- Upgrade to Specta v2 prelease
- Add `Router::sd_patch_types_dangerously`
- Expose internal type maps for the invalidation system.
- All procedures must return a result
- `Procedure::with2` which is a hack to properly support the middleware mapper API
- Legacy executor system - Will require major changes to the React Native link.
- A super pre-release version of rspc v1's procedure syntax.
- Upgrade to Specta v2 prelease
- Add `Router::sd_patch_types_dangerously`
- Expose internal type maps for the invalidation system.
- All procedures must return a result
- `Procedure::with2` which is a hack to properly support the middleware mapper API
- Legacy executor system - Will require major changes to the React Native link.

Removed features relied on by Spacedrive:
- Argument middleware mapper API has been removed upstream

- Argument middleware mapper API has been removed upstream

## Basic usage

Expand Down Expand Up @@ -83,9 +84,8 @@ Minus batching HTTP requests are run in parallel.

### Websocket reconnect

If the websocket connection is dropped (due to network disruption) all subscriptions *will not* restart upon reconnecting.
If the websocket connection is dropped (due to network disruption) all subscriptions _will not_ restart upon reconnecting.

This will cause the invalidation system to break and potentially other parts of the app that rely on subscriptions.

Queries and mutations done during the network disruption will hang indefinitely.

7 changes: 4 additions & 3 deletions docs/product/getting-started/setup.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ docker run -d --name spacedrive -p 8080:8080 -e SD_AUTH=admin:spacedrive -v /var
When using the Spacedrive server you can use the `SD_AUTH` environment variable to configure authentication.

Valid values:
- `SD_AUTH=disabled` - Disables authentication.
- `SD_AUTH=username:password` - Enables authentication for a single user.
- `SD_AUTH=username:password,username1:password1` - Enables authentication with multiple users (you can add as many users as you want).

- `SD_AUTH=disabled` - Disables authentication.
- `SD_AUTH=username:password` - Enables authentication for a single user.
- `SD_AUTH=username:password,username1:password1` - Enables authentication with multiple users (you can add as many users as you want).

### Mobile (Preview)

Expand Down
24 changes: 22 additions & 2 deletions interface/app/$libraryId/Layout/Sidebar/sections/Local/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { EjectSimple } from '@phosphor-icons/react';
import { ArrowRight, EjectSimple } from '@phosphor-icons/react';
import clsx from 'clsx';
import { PropsWithChildren, useMemo } from 'react';
import { useBridgeQuery, useCache, useLibraryQuery, useNodes } from '@sd/client';
import { Button, toast, tw } from '@sd/ui';
import { Icon, IconName } from '~/components';
import { useLocale } from '~/hooks';
import { useLocale, useOperatingSystem } from '~/hooks';
import { useHomeDir } from '~/hooks/useHomeDir';
import { usePlatform } from '~/util/Platform';

import { useExplorerDroppable } from '../../../../Explorer/useExplorerDroppable';
import { useExplorerSearchParams } from '../../../../Explorer/util';
Expand All @@ -26,11 +27,18 @@ const EjectButton = ({ className }: { className?: string }) => (
</Button>
);

const OpenToButton = ({ className }: { className?: string; what_is_opening?: string }) => (
<Button className={clsx('absolute right-[2px] !p-[5px]', className)} variant="subtle">
<ArrowRight size={18} className="size-3 opacity-70" />
</Button>
);

const SidebarIcon = ({ name }: { name: IconName }) => {
return <Icon name={name} size={20} className="mr-1" />;
};

export default function LocalSection() {
const platform = usePlatform();
const locationsQuery = useLibraryQuery(['locations.list']);
useNodes(locationsQuery.data?.nodes);
const locations = useCache(locationsQuery.data?.items);
Expand Down Expand Up @@ -76,6 +84,7 @@ export default function LocalSection() {
)
);

const os = useOperatingSystem();
return (
<Section name={t('local')}>
<SeeMore>
Expand Down Expand Up @@ -137,6 +146,17 @@ export default function LocalSection() {
</EphemeralLocation>
);
})}
{platform.openTrashInOsExplorer && (
// eslint-disable-next-line tailwindcss/migration-from-tailwind-2
<div
className={`max-w relative flex grow flex-row items-center gap-0.5 truncate rounded border border-transparent ${os === 'macOS' ? 'bg-opacity-90' : ''} px-2 py-1 text-sm font-medium text-sidebar-inkDull outline-none ring-0 ring-inset ring-transparent ring-offset-0 focus:ring-1 focus:ring-accent focus:ring-offset-0`}

Check warning on line 152 in interface/app/$libraryId/Layout/Sidebar/sections/Local/index.tsx

View workflow job for this annotation

GitHub Actions / ESLint

Classname 'bg-opacity-90' should be replaced by an opacity suffix (eg. '/90')
onClick={() => platform.openTrashInOsExplorer?.()}
>
<SidebarIcon name="Trash" />
<Name>{t('trash')}</Name>
<OpenToButton />
</div>
)}
</SeeMore>
</Section>
);
Expand Down
14 changes: 7 additions & 7 deletions interface/hooks/useMouseItemResize.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useCallback, useEffect } from 'react';
import { useExplorerContext } from '~/app/$libraryId/Explorer/Context';
import { getSizes } from '~/app/$libraryId/Explorer/OptionsPanel/ListView/util';
import { LIST_VIEW_ICON_SIZES } from '~/app/$libraryId/Explorer/View/ListView/useTable';

import { useOperatingSystem } from './useOperatingSystem';
import { getSizes } from '~/app/$libraryId/Explorer/OptionsPanel/ListView/util';

/**
* Hook that allows resizing of items in the Explorer views for GRID and LIST only - using the mouse wheel.
Expand All @@ -19,19 +19,19 @@ export const useMouseItemResize = () => {
const isList = layoutMode === 'list';
const deltaYModifier = isList ? Math.sign(e.deltaY) : e.deltaY / 10; // Sensitivity adjustment
const newSize =
Number(
isList
? explorer.settingsStore.listViewIconSize
: explorer.settingsStore.gridItemSize
) + deltaYModifier;
Number(
isList
? explorer.settingsStore.listViewIconSize
: explorer.settingsStore.gridItemSize
) + deltaYModifier;

const minSize = isList ? 0 : 60;
const maxSize = isList ? 2 : 200;
const clampedSize = Math.max(minSize, Math.min(maxSize, newSize));

if (isList) {
const listSizes = getSizes(LIST_VIEW_ICON_SIZES);
explorer.settingsStore.listViewIconSize = listSizes.sizeMap.get(clampedSize) ?? "0"
explorer.settingsStore.listViewIconSize = listSizes.sizeMap.get(clampedSize) ?? '0';
} else if (layoutMode === 'grid') {
explorer.settingsStore.gridItemSize = Number(clampedSize.toFixed(0));
}
Expand Down
1 change: 1 addition & 0 deletions interface/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@
"toggle_metadata": "Toggle metadata",
"toggle_path_bar": "Toggle path bar",
"toggle_quick_preview": "Toggle quick preview",
"trash": "Trash",
"type": "Type",
"ui_animations": "UI Animations",
"ui_animations_description": "Dialogs and other UI elements will animate when opening and closing.",
Expand Down
1 change: 1 addition & 0 deletions interface/util/Platform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type Platform = {
showDevtools?(): void;
openPath?(path: string): void;
openLogsDir?(): void;
openTrashInOsExplorer?(): void;
userHomeDir?(): Promise<string>;
// Opens a file path with a given ID
openFilePaths?(library: string, ids: number[]): any;
Expand Down

0 comments on commit b4037d6

Please sign in to comment.